feat(sdk): contributes.skills — skills IdeA-native déclarables par plugin — #282 (types IdeAPluginSkillContribution/IdeAPluginSkillKind: id/name/description/kind workflow|reference/path .md package-relative, validation manifeste, export public; docs manifest + codex-skills-and-idea-plugins recentrés skills IdeA-native vs .codex-plugin Codex, README; QA verte: npm run build)

This commit is contained in:
2026-09-08 15:48:47 +02:00
parent 1239104b0f
commit 6eb8db3791
5 changed files with 101 additions and 26 deletions

View File

@ -6,6 +6,8 @@ export type {
IdeAPluginLayoutContribution,
IdeAPluginMcpServerContribution,
IdeAPluginMenuItemContribution,
IdeAPluginSkillContribution,
IdeAPluginSkillKind,
IdeAPluginTopLevelMenuContribution
} from "./manifest.js";
export {

View File

@ -14,6 +14,7 @@ export interface IdeAPluginManifest {
*/
activationScope?: IdeAPluginActivationScope;
contributes?: {
skills?: IdeAPluginSkillContribution[];
menus?: IdeAPluginTopLevelMenuContribution[];
menuItems?: IdeAPluginMenuItemContribution[];
slashCommands?: IdeAPluginSlashCommandContribution[];
@ -26,10 +27,24 @@ export type IdeAPluginCapability = "ui" | "mcp" | "tooling";
export type IdeAPluginActivationScope = "app" | "project";
export type IdeAPluginSkillKind = "workflow" | "reference";
export interface IdeAPluginEngineConstraints {
idea?: string;
}
export interface IdeAPluginSkillContribution {
id: string;
/** Agent-facing name shown in the injected skill catalogue and accepted by idea_skill_read. */
name: string;
/** Short affordance shown to agents before they load the skill body. */
description: string;
/** Defaults to "workflow". */
kind?: IdeAPluginSkillKind;
/** Package-relative Markdown file, usually skills/<name>/SKILL.md. */
path: string;
}
export interface IdeAPluginTopLevelMenuContribution {
id: string;
label: string;
@ -192,6 +207,20 @@ function validateContributes(value: unknown, errors: string[]): void {
return;
}
validateArray(value, "skills", errors, (skill, index) => {
requireString(skill, "id", errors, `contributes.skills[${index}].id`);
requireString(skill, "name", errors, `contributes.skills[${index}].name`);
requireString(skill, "description", errors, `contributes.skills[${index}].description`);
requireString(skill, "path", errors, `contributes.skills[${index}].path`);
if (typeof skill.kind === "string" && skill.kind !== "workflow" && skill.kind !== "reference") {
errors.push(`contributes.skills[${index}].kind must be "workflow" or "reference" when provided`);
} else if (skill.kind !== undefined && typeof skill.kind !== "string") {
errors.push(`contributes.skills[${index}].kind must be a string when provided`);
}
if (typeof skill.path === "string" && !skill.path.endsWith(".md")) {
errors.push(`contributes.skills[${index}].path must point to a .md file`);
}
});
validateArray(value, "menus", errors, (menu, index) => {
requireString(menu, "id", errors, `contributes.menus[${index}].id`);
requireString(menu, "label", errors, `contributes.menus[${index}].label`);