mirror of
https://github.com/openai/codex.git
synced 2026-11-07 08:34:29 +00:00
## What changed - Convert supported plugin command Markdown into generated skills when a plugin is installed. - Read command sources from the manifest's `commands` field, falling back to the plugin's `commands/` directory. - Load generated command skills alongside native plugin skills while preferring native skills with the same name. - Skip commands with unsupported templates, missing descriptions, name collisions, or generated skills larger than 4 KB, and keep migration failures from blocking plugin installation. ## Testing - Cover default and manifest-configured command paths, stale generated skill cleanup, size limits, native-skill precedence, invalid manifest fields, and non-fatal migration errors. GitOrigin-RevId: 67d910048544b160b191066569bca69b2b951ebc
62 lines
2.1 KiB
Rust
62 lines
2.1 KiB
Rust
use super::CommandDescriptionMode;
|
|
use super::CommandMigrationProfile;
|
|
use super::CommandSkillSizeLimit;
|
|
use super::CommandSource;
|
|
use super::RewriteProfile;
|
|
use super::import_command_sources;
|
|
use super::supported_command_sources;
|
|
use super::unique_command_sources;
|
|
use crate::manifest::load_plugin_command_paths;
|
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
|
use std::fs;
|
|
use std::io;
|
|
use std::path::Path;
|
|
|
|
const PLUGIN_COMMANDS_DIR: &str = "commands";
|
|
const PLUGIN_METADATA_DIR: &str = ".codex-plugin";
|
|
const MIGRATED_COMMAND_SKILLS_DIR: &str = "migrated-command-skills";
|
|
const MAX_MIGRATED_COMMAND_SKILL_BYTES: usize = 4_000;
|
|
|
|
const PLUGIN_REWRITE_PROFILE: RewriteProfile = RewriteProfile::new("AGENTS.md", &[]);
|
|
const PLUGIN_MIGRATION_PROFILE: CommandMigrationProfile = CommandMigrationProfile::new(
|
|
PLUGIN_REWRITE_PROFILE,
|
|
CommandDescriptionMode::RequireFrontmatter,
|
|
);
|
|
|
|
pub(crate) fn migrate_plugin_commands(plugin_root: &Path) -> io::Result<()> {
|
|
let target_skills = plugin_root
|
|
.join(PLUGIN_METADATA_DIR)
|
|
.join(MIGRATED_COMMAND_SKILLS_DIR);
|
|
if target_skills.is_dir() {
|
|
fs::remove_dir_all(&target_skills)?;
|
|
} else if target_skills.exists() {
|
|
fs::remove_file(&target_skills)?;
|
|
}
|
|
import_command_sources(
|
|
plugin_command_sources(plugin_root)?,
|
|
&target_skills,
|
|
PLUGIN_MIGRATION_PROFILE,
|
|
CommandSkillSizeLimit::MaxBytes(MAX_MIGRATED_COMMAND_SKILL_BYTES),
|
|
)?;
|
|
Ok(())
|
|
}
|
|
|
|
pub(crate) fn migrated_command_skills_root(plugin_root: &AbsolutePathBuf) -> AbsolutePathBuf {
|
|
plugin_root
|
|
.join(PLUGIN_METADATA_DIR)
|
|
.join(MIGRATED_COMMAND_SKILLS_DIR)
|
|
}
|
|
|
|
fn plugin_command_sources(plugin_root: &Path) -> io::Result<Vec<CommandSource>> {
|
|
let command_paths = load_plugin_command_paths(plugin_root)?
|
|
.unwrap_or_else(|| vec![plugin_root.join(PLUGIN_COMMANDS_DIR)]);
|
|
let mut sources = Vec::new();
|
|
for command_path in command_paths {
|
|
sources.extend(supported_command_sources(
|
|
&command_path,
|
|
CommandDescriptionMode::RequireFrontmatter,
|
|
)?);
|
|
}
|
|
Ok(unique_command_sources(sources))
|
|
}
|