Handle invalid plugin skills manifest field (#25717)

## Summary
- Treat invalid `plugin.json` `skills` shapes as a field-level warning
instead of rejecting the whole manifest
- Keep valid string path behavior unchanged and continue falling back to
the default `skills/` root
- Add regression coverage for array-shaped `skills`

## Tests
- `just fmt`
- `cargo test -p codex-core-plugins`
This commit is contained in:
xli-oai authored and GitHub committed 2026-06-01 17:19:34 -07:00
1 parent 0b3a6f7185
commit 1ad0d7aa4b
2 files changed
+63 -2

No files matched your search

@@ -959,6 +959,43 @@ async fn load_plugins_ignores_manifest_component_paths_without_dot_slash() {
);
}
#[tokio::test]
async fn load_plugins_ignores_invalid_manifest_skills_shape() {
let codex_home = TempDir::new().unwrap();
let plugin_root = codex_home
.path()
.join("plugins/cache")
.join("test/sample/local");
write_file(
&plugin_root.join(".codex-plugin/plugin.json"),
r#"{
"name": "sample",
"skills": ["./custom-skills/"]
}"#,
);
write_file(
&plugin_root.join("skills/default-skill/SKILL.md"),
"---\nname: default-skill\ndescription: default skill\n---\n",
);
write_file(
&plugin_root.join("custom-skills/custom-skill/SKILL.md"),
"---\nname: custom-skill\ndescription: custom skill\n---\n",
);
let outcome = load_plugins_from_config(
&plugin_config_toml(/*enabled*/ true, /*plugins_feature_enabled*/ true),
codex_home.path(),
)
.await;
assert_eq!(outcome.plugins()[0].error, None);
assert_eq!(
outcome.plugins()[0].skill_roots,
vec![plugin_root.join("skills").abs()]
);
}
#[tokio::test]
async fn load_plugins_preserves_disabled_plugins_without_effective_contributions() {
let codex_home = TempDir::new().unwrap();