Migrate plugin commands into skills on install (#33411)

## 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
This commit is contained in:
charlesgong-openai
2026-07-15 19:51:37 +00:00
committed by copyberry
parent 38b064c31b
commit 2cd6ed7509
14 changed files with 984 additions and 427 deletions
@@ -1,14 +1,15 @@
use codex_core_plugins::CommandDescriptionMode;
use codex_core_plugins::CommandMigrationProfile;
use codex_core_plugins::CommandRewriteProfile;
use codex_core_plugins::count_missing_commands_with_profile;
use codex_core_plugins::import_commands_with_profile;
use codex_core_plugins::marketplace_add::is_local_marketplace_source;
use codex_external_agent_migration::CommandDescriptionMode;
use codex_external_agent_migration::CommandMigrationProfile;
use codex_core_plugins::missing_command_names_with_profile;
use codex_external_agent_migration::RewriteProfile;
use codex_external_agent_migration::build_mcp_config_from_external;
use codex_external_agent_migration::count_missing_commands_with_profile;
use codex_external_agent_migration::hook_migration_event_names_cla;
use codex_external_agent_migration::import_commands_with_profile;
use codex_external_agent_migration::import_hooks_cla;
use codex_external_agent_migration::import_subagents_with_rewrite_profile;
use codex_external_agent_migration::missing_command_names_with_profile;
use codex_plugin::PluginId;
use serde_json::Value as JsonValue;
use std::collections::BTreeMap;
@@ -42,8 +43,14 @@ pub(super) const REWRITE_PROFILE: RewriteProfile = RewriteProfile::new(
"claude",
],
);
const COMMAND_MIGRATION_PROFILE: CommandMigrationProfile =
CommandMigrationProfile::new(REWRITE_PROFILE, CommandDescriptionMode::RequireFrontmatter);
const COMMAND_MIGRATION_PROFILE: CommandMigrationProfile = CommandMigrationProfile::new(
CommandRewriteProfile::new(
REWRITE_PROFILE.doc_file_name(),
REWRITE_PROFILE.term_variants(),
)
.with_case_sensitive_term_variants(REWRITE_PROFILE.case_sensitive_term_variants()),
CommandDescriptionMode::RequireFrontmatter,
);
pub(super) fn effective_settings(project_settings: &Path) -> io::Result<Option<JsonValue>> {
let mut effective = super::read_external_settings(project_settings)?;