@kolisachint/hoocode-agent 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +10 -7
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +10 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/capabilities/deferral.d.ts +78 -0
- package/dist/core/capabilities/deferral.d.ts.map +1 -0
- package/dist/core/capabilities/deferral.js +99 -0
- package/dist/core/capabilities/deferral.js.map +1 -0
- package/dist/core/capabilities/dense.d.ts +51 -0
- package/dist/core/capabilities/dense.d.ts.map +1 -0
- package/dist/core/capabilities/dense.js +121 -0
- package/dist/core/capabilities/dense.js.map +1 -0
- package/dist/core/capabilities/lexical.d.ts +43 -0
- package/dist/core/capabilities/lexical.d.ts.map +1 -0
- package/dist/core/capabilities/lexical.js +104 -0
- package/dist/core/capabilities/lexical.js.map +1 -0
- package/dist/core/capabilities/registry.d.ts +56 -0
- package/dist/core/capabilities/registry.d.ts.map +1 -0
- package/dist/core/capabilities/registry.js +0 -0
- package/dist/core/capabilities/registry.js.map +1 -0
- package/dist/core/capabilities/search.d.ts +47 -0
- package/dist/core/capabilities/search.d.ts.map +1 -0
- package/dist/core/capabilities/search.js +82 -0
- package/dist/core/capabilities/search.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +27 -3
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +61 -7
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/plugins/authoring.d.ts +56 -9
- package/dist/core/extensions/plugins/authoring.d.ts.map +1 -1
- package/dist/core/extensions/plugins/authoring.js +0 -0
- package/dist/core/extensions/plugins/authoring.js.map +1 -1
- package/dist/core/extensions/plugins/drift.d.ts +75 -0
- package/dist/core/extensions/plugins/drift.d.ts.map +1 -0
- package/dist/core/extensions/plugins/drift.js +194 -0
- package/dist/core/extensions/plugins/drift.js.map +1 -0
- package/dist/core/extensions/plugins/formats/claude.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/claude.js +5 -0
- package/dist/core/extensions/plugins/formats/claude.js.map +1 -1
- package/dist/core/extensions/plugins/formats/copilot.d.ts +6 -0
- package/dist/core/extensions/plugins/formats/copilot.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/copilot.js +57 -16
- package/dist/core/extensions/plugins/formats/copilot.js.map +1 -1
- package/dist/core/extensions/plugins/formats/index.d.ts +39 -1
- package/dist/core/extensions/plugins/formats/index.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/index.js +90 -13
- package/dist/core/extensions/plugins/formats/index.js.map +1 -1
- package/dist/core/extensions/plugins/formats/jsonManifest.d.ts +14 -0
- package/dist/core/extensions/plugins/formats/jsonManifest.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/jsonManifest.js +37 -4
- package/dist/core/extensions/plugins/formats/jsonManifest.js.map +1 -1
- package/dist/core/extensions/plugins/formats/platform-targets.d.ts +48 -24
- package/dist/core/extensions/plugins/formats/platform-targets.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/platform-targets.js +62 -30
- package/dist/core/extensions/plugins/formats/platform-targets.js.map +1 -1
- package/dist/core/extensions/plugins/formats/shared.d.ts +22 -0
- package/dist/core/extensions/plugins/formats/shared.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/shared.js +81 -4
- package/dist/core/extensions/plugins/formats/shared.js.map +1 -1
- package/dist/core/extensions/plugins/formats/types.d.ts +10 -1
- package/dist/core/extensions/plugins/formats/types.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/types.js.map +1 -1
- package/dist/core/extensions/plugins/gates.d.ts +64 -0
- package/dist/core/extensions/plugins/gates.d.ts.map +1 -0
- package/dist/core/extensions/plugins/gates.js +297 -0
- package/dist/core/extensions/plugins/gates.js.map +1 -0
- package/dist/core/extensions/plugins/hooks-bridge.d.ts +1 -1
- package/dist/core/extensions/plugins/hooks-bridge.d.ts.map +1 -1
- package/dist/core/extensions/plugins/hooks-bridge.js +12 -8
- package/dist/core/extensions/plugins/hooks-bridge.js.map +1 -1
- package/dist/core/extensions/plugins/index.d.ts +36 -5
- package/dist/core/extensions/plugins/index.d.ts.map +1 -1
- package/dist/core/extensions/plugins/index.js +66 -15
- package/dist/core/extensions/plugins/index.js.map +1 -1
- package/dist/core/extensions/plugins/install.d.ts +43 -24
- package/dist/core/extensions/plugins/install.d.ts.map +1 -1
- package/dist/core/extensions/plugins/install.js +167 -54
- package/dist/core/extensions/plugins/install.js.map +1 -1
- package/dist/core/extensions/plugins/locations.d.ts +84 -0
- package/dist/core/extensions/plugins/locations.d.ts.map +1 -0
- package/dist/core/extensions/plugins/locations.js +137 -0
- package/dist/core/extensions/plugins/locations.js.map +1 -0
- package/dist/core/extensions/plugins/manifest.d.ts +21 -1
- package/dist/core/extensions/plugins/manifest.d.ts.map +1 -1
- package/dist/core/extensions/plugins/manifest.js +2 -2
- package/dist/core/extensions/plugins/manifest.js.map +1 -1
- package/dist/core/extensions/plugins/packaging.d.ts +115 -0
- package/dist/core/extensions/plugins/packaging.d.ts.map +1 -0
- package/dist/core/extensions/plugins/packaging.js +362 -0
- package/dist/core/extensions/plugins/packaging.js.map +1 -0
- package/dist/core/extensions/plugins/smoke.d.ts +33 -0
- package/dist/core/extensions/plugins/smoke.d.ts.map +1 -0
- package/dist/core/extensions/plugins/smoke.js +231 -0
- package/dist/core/extensions/plugins/smoke.js.map +1 -0
- package/dist/core/extensions/plugins/trigger-eval.d.ts +136 -0
- package/dist/core/extensions/plugins/trigger-eval.d.ts.map +1 -0
- package/dist/core/extensions/plugins/trigger-eval.js +0 -0
- package/dist/core/extensions/plugins/trigger-eval.js.map +1 -0
- package/dist/core/package-manager.d.ts +6 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts +2 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +15 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +2 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +3 -3
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-types.d.ts +1 -1
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/skills.d.ts +9 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +23 -3
- package/dist/core/skills.js.map +1 -1
- package/dist/core/tools/package-plugin.d.ts +19 -0
- package/dist/core/tools/package-plugin.d.ts.map +1 -0
- package/dist/core/tools/package-plugin.js +81 -0
- package/dist/core/tools/package-plugin.js.map +1 -0
- package/dist/core/tools/plugin-tool-names.d.ts +1 -0
- package/dist/core/tools/plugin-tool-names.d.ts.map +1 -1
- package/dist/core/tools/plugin-tool-names.js +6 -0
- package/dist/core/tools/plugin-tool-names.js.map +1 -1
- package/dist/core/tools/plugins.d.ts.map +1 -1
- package/dist/core/tools/plugins.js +48 -7
- package/dist/core/tools/plugins.js.map +1 -1
- package/dist/core/tools/propose-plugin.d.ts.map +1 -1
- package/dist/core/tools/propose-plugin.js +49 -21
- package/dist/core/tools/propose-plugin.js.map +1 -1
- package/dist/core/tools/webfetch.d.ts +3 -1
- package/dist/core/tools/webfetch.d.ts.map +1 -1
- package/dist/core/tools/webfetch.js +8 -2
- package/dist/core/tools/webfetch.js.map +1 -1
- package/dist/core/tools/websearch.d.ts +2 -0
- package/dist/core/tools/websearch.d.ts.map +1 -1
- package/dist/core/tools/websearch.js +2 -1
- package/dist/core/tools/websearch.js.map +1 -1
- package/dist/core/tools/webtools-shared.d.ts +23 -2
- package/dist/core/tools/webtools-shared.d.ts.map +1 -1
- package/dist/core/tools/webtools-shared.js +59 -9
- package/dist/core/tools/webtools-shared.js.map +1 -1
- package/dist/extensions/core/marketplace.d.ts +14 -3
- package/dist/extensions/core/marketplace.d.ts.map +1 -1
- package/dist/extensions/core/marketplace.js +77 -18
- package/dist/extensions/core/marketplace.js.map +1 -1
- package/dist/extensions/core/mcp-deferred.d.ts +39 -2
- package/dist/extensions/core/mcp-deferred.d.ts.map +1 -1
- package/dist/extensions/core/mcp-deferred.js +74 -10
- package/dist/extensions/core/mcp-deferred.js.map +1 -1
- package/dist/extensions/core/mcp-loader.d.ts.map +1 -1
- package/dist/extensions/core/mcp-loader.js +52 -9
- package/dist/extensions/core/mcp-loader.js.map +1 -1
- package/dist/extensions/core/scaffold.d.ts +3 -3
- package/dist/extensions/core/scaffold.d.ts.map +1 -1
- package/dist/extensions/core/scaffold.js +9 -9
- package/dist/extensions/core/scaffold.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +25 -7
- package/dist/main.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +8 -0
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +12 -3
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/providers.md +11 -0
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +5 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copilot.js","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/copilot.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GitHub Copilot format.\n *\n * hoocode's preferred Copilot home is the `.github/plugin/` marker directory —\n * the convention used by the real-world plugins indexed by\n * github/copilot-plugins (e.g. microsoft/work-iq) and the documented location\n * for GitHub-hosted marketplaces. The official Copilot CLI plugin reference\n * (docs.github.com copilot/reference/copilot-cli-reference/cli-plugin-reference,\n * \"File locations\"; verified 2026-07) accepts several locations for both files\n * (`.plugin/`, plugin root, `.github/plugin/`, `.claude-plugin/`), so this\n * adapter reads them all — `.github/plugin/` first, then root, then `.plugin/`,\n * then the legacy hoocode layout — and writes `.github/plugin/`.\n * (`.claude-plugin/` belongs to the Claude adapter, which wins precedence, so a\n * `.claude-plugin`-only directory correctly parses as a Claude plugin; Copilot\n * reads those natively anyway.) The capability tree matches the Claude layout:\n *\n * skills skills/<name>/SKILL.md (or the manifest's `skills` path override)\n * commands .github/prompts/<name>.prompt.md (Copilot's prompt-file convention — the\n * analog of a slash command; a manifest\n * `commands` path or `commands/` dir is read too)\n * subagents agents/<name>.agent.md (Copilot's custom-agent convention — the\n * `.agent.md` suffix and a YAML-list `tools`\n * frontmatter are what Copilot recognizes; the\n * reader still accepts bare `.md` names)\n * hooks hooks.json or hooks/hooks.json ({ description?, hooks: { Event: [...] } })\n * MCP servers .mcp.json ({ mcpServers } | { servers })\n *\n * Workspace-level (non-plugin) conventions, per the current GitHub Copilot\n * customization docs (docs.github.com — agent skills, custom agents, prompt\n * files; verified 2026-07):\n *\n * skills .github/skills/<name>/SKILL.md (agentskills.io open standard)\n * custom agents .github/agents/<name>.agent.md (frontmatter: name, description,\n * tools as a YAML list, model, ...)\n * prompt files .github/prompts/<name>.prompt.md (VS Code / Copilot prompt files)\n *\n * Earlier hoocode releases authored a different Copilot mapping\n * (`.github/copilot-plugin.json` + `.github/prompts/*.prompt.md` +\n * `.github/chatmodes/*.chatmode.md`); the reader still accepts that layout as a\n * legacy fallback so previously authored plugins keep loading. Copilot\n * conventions move quickly; this file is the single place that encodes them,\n * so tracking an upstream change never reaches beyond this adapter.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { NormalizedPlugin } from \"../manifest.js\";\nimport {\n\tauthoredHooksToConfig,\n\tdirIfExists,\n\temitJson,\n\temitMarkdown,\n\tnormalizeHooks,\n\tnormalizeMcp,\n\tparseAuthor,\n\ttype RawManifest,\n\treadJson,\n\tresolveCapabilityDir,\n\tslug,\n\ttoolsYamlList,\n} from \"./shared.js\";\nimport type { EmittedFile, PluginDraft, PluginFormatAdapter } from \"./types.js\";\n\nconst MARKER_DIR = \".github\";\n/**\n * Manifest probe order: `.github/plugin/plugin.json` first — hoocode's\n * preferred Copilot home, matching the real-world plugins indexed by\n * github/copilot-plugins (e.g. microsoft/work-iq) — then the Copilot CLI\n * reference's other locations (root `plugin.json`, `.plugin/plugin.json`) and\n * hoocode's legacy `.github/copilot-plugin.json`. (`.claude-plugin/plugin.json`,\n * also probed by the CLI, belongs to the Claude adapter.)\n */\nconst MANIFEST_REL_PATHS = [\n\tpath.join(MARKER_DIR, \"plugin\", \"plugin.json\"),\n\t\"plugin.json\",\n\tpath.join(\".plugin\", \"plugin.json\"),\n\tpath.join(MARKER_DIR, \"copilot-plugin.json\"),\n] as const;\n/** Authored manifest location: the preferred `.github/plugin/` home. */\nconst emitManifestRelPath = path.join(MARKER_DIR, \"plugin\", \"plugin.json\");\n\n/**\n * Copilot prompt-file home. `.github/prompts/<name>.prompt.md` is the current\n * Copilot/VS Code prompt-file convention, and hoocode maps a plugin's commands\n * to it (both the writer and this reader), so it is the authored location for\n * commands — not merely a legacy fallback.\n */\nconst PROMPTS_DIR = path.join(MARKER_DIR, \"prompts\");\n// Legacy authored layout (read-only fallbacks).\nconst LEGACY_CHATMODES_DIR = path.join(MARKER_DIR, \"chatmodes\");\nconst LEGACY_MCP_FILE = path.join(MARKER_DIR, \"mcp.json\");\nconst LEGACY_HOOKS_FILE = path.join(MARKER_DIR, \"hooks\", \"hooks.json\");\n\n/** Read a hooks JSON file (either `{ hooks: {...} }` or a bare event map). */\nfunction readHooksFile(root: string, rel: string): NormalizedPlugin[\"hooks\"] {\n\tconst file = path.join(root, rel);\n\tif (!fs.existsSync(file)) return undefined;\n\tconst raw = readJson<{ hooks?: Record<string, unknown> } | Record<string, unknown>>(file);\n\tif (!raw || typeof raw !== \"object\") return undefined;\n\tconst config = (\"hooks\" in raw && raw.hooks ? raw.hooks : raw) as NormalizedPlugin[\"hooks\"];\n\treturn config && Object.keys(config).length > 0 ? config : undefined;\n}\n\nfunction manifestPathFor(root: string): string | undefined {\n\tfor (const rel of MANIFEST_REL_PATHS) {\n\t\tif (readJson(path.join(root, rel)) != null) return path.join(root, rel);\n\t}\n\treturn undefined;\n}\n\nexport const copilotFormat: PluginFormatAdapter = {\n\tid: \"copilot\",\n\tplatform: \"github\",\n\tprecedence: 2,\n\tlabel: \"GitHub Copilot (.github)\",\n\t// .github/plugin/ first (hoocode's preferred Copilot home and the documented\n\t// location for GitHub-hosted marketplaces), then the legacy .github/ spot,\n\t// then the Copilot CLI's other probe locations (root, .plugin/).\n\tmarketplaceFiles: [\n\t\tpath.join(MARKER_DIR, \"plugin\", \"marketplace.json\"),\n\t\tpath.join(MARKER_DIR, \"marketplace.json\"),\n\t\t\"marketplace.json\",\n\t\tpath.join(\".plugin\", \"marketplace.json\"),\n\t],\n\n\tworkspace: {\n\t\troot: MARKER_DIR,\n\t\t// Copilot reads repo skills from .github/skills (also .claude/skills and\n\t\t// .agents/skills, which the sibling adapters cover).\n\t\temitSkill: (s) => ({\n\t\t\tpath: path.join(MARKER_DIR, \"skills\", slug(s.name), \"SKILL.md\"),\n\t\t\tcontent: emitMarkdown({ name: s.name, description: s.description }, s.body),\n\t\t}),\n\t\t// Custom agents take `tools` as a YAML list (not the Claude comma string).\n\t\temitAgent: (a) => ({\n\t\t\tpath: path.join(MARKER_DIR, \"agents\", `${slug(a.name)}.agent.md`),\n\t\t\tcontent: emitMarkdown(\n\t\t\t\t{ name: a.name, description: a.description, tools: toolsYamlList(a.tools), model: a.model },\n\t\t\t\ta.body,\n\t\t\t),\n\t\t}),\n\t\t// The closest Copilot equivalent of a slash command is a prompt file.\n\t\temitCommand: (c) => ({\n\t\t\tpath: path.join(MARKER_DIR, \"prompts\", `${slug(c.name)}.prompt.md`),\n\t\t\tcontent: emitMarkdown({ description: c.description }, c.body),\n\t\t}),\n\t},\n\n\tdetectPlugin(root: string): boolean {\n\t\treturn manifestPathFor(root) !== undefined;\n\t},\n\n\tparsePlugin(root: string): NormalizedPlugin | null {\n\t\tconst manifestPath = manifestPathFor(root);\n\t\tif (!manifestPath) return null;\n\t\tconst raw = readJson<RawManifest>(manifestPath);\n\t\tif (!raw) return null;\n\n\t\tconst id = (raw.name ?? path.basename(root)).trim();\n\t\tif (!id) return null;\n\n\t\treturn {\n\t\t\tid,\n\t\t\tversion: raw.version,\n\t\t\tdescription: raw.description,\n\t\t\tauthor: parseAuthor(raw.author),\n\t\t\troot,\n\t\t\tmanifestPath,\n\t\t\tformat: \"copilot\",\n\t\t\t// Single-format view; the registry widens this to every format present.\n\t\t\tsupportPlatform: [\"github\"],\n\t\t\t// Claude-mirror layout (manifest overrides honored), with the legacy\n\t\t\t// prompts/chatmodes locations as read-only fallbacks.\n\t\t\tskillsDir: resolveCapabilityDir(root, raw.skills, \"skills\"),\n\t\t\t// Commands map to Copilot prompt files at `.github/prompts/`; a manifest\n\t\t\t// `commands` override or a conventional `commands/` dir still wins if present.\n\t\t\tcommandsDir: resolveCapabilityDir(root, raw.commands, \"commands\") ?? dirIfExists(root, PROMPTS_DIR),\n\t\t\tagentsDir: resolveCapabilityDir(root, raw.agents, \"agents\") ?? dirIfExists(root, LEGACY_CHATMODES_DIR),\n\t\t\tthemesDir: resolveCapabilityDir(root, raw.themes, \"themes\"),\n\t\t\t// Copilot CLI plugins put hooks config at root `hooks.json`; normalizeHooks\n\t\t\t// covers the Claude-mirror `hooks/hooks.json`, then the legacy location.\n\t\t\thooks:\n\t\t\t\tnormalizeHooks(raw.hooks, root) ??\n\t\t\t\treadHooksFile(root, \"hooks.json\") ??\n\t\t\t\treadHooksFile(root, LEGACY_HOOKS_FILE),\n\t\t\tmcpServers: normalizeMcp(raw.mcpServers, root) ?? normalizeMcp(undefined, root, LEGACY_MCP_FILE),\n\t\t\t// Providers are a native-only concept.\n\t\t\tproviders: undefined,\n\t\t};\n\t},\n\n\temit(draft: PluginDraft): EmittedFile[] {\n\t\t// Only the manifest is Copilot-specific — the canonical location is root\n\t\t// `plugin.json` (Copilot CLI spec) — and the capability tree mirrors the\n\t\t// Claude layout, so a plugin authored for both platforms is one tree with a\n\t\t// root manifest for Copilot and a .claude-plugin/ manifest for Claude.\n\t\tconst files: EmittedFile[] = [];\n\n\t\tfiles.push({\n\t\t\tpath: emitManifestRelPath,\n\t\t\tcontent: emitJson({\n\t\t\t\tname: draft.id,\n\t\t\t\t...(draft.version ? { version: draft.version } : {}),\n\t\t\t\t...(draft.description ? { description: draft.description } : {}),\n\t\t\t\t// Spec: `author` is an object with a required `name`.\n\t\t\t\t...(draft.author ? { author: { name: draft.author } } : {}),\n\t\t\t}),\n\t\t});\n\n\t\tfor (const s of draft.skills ?? []) {\n\t\t\tfiles.push({\n\t\t\t\tpath: path.join(\"skills\", slug(s.name), \"SKILL.md\"),\n\t\t\t\tcontent: emitMarkdown({ name: s.name, description: s.description }, s.body),\n\t\t\t});\n\t\t}\n\t\tfor (const c of draft.commands ?? []) {\n\t\t\t// Copilot's analog of a slash command is a prompt file:\n\t\t\t// `.github/prompts/<name>.prompt.md` (docs.github.com prompt files;\n\t\t\t// verified 2026-07) — same target as this adapter's workspace.emitCommand.\n\t\t\tfiles.push({\n\t\t\t\tpath: path.join(PROMPTS_DIR, `${slug(c.name)}.prompt.md`),\n\t\t\t\tcontent: emitMarkdown({ description: c.description }, c.body),\n\t\t\t});\n\t\t}\n\t\tfor (const a of draft.agents ?? []) {\n\t\t\t// Copilot recognizes custom agents by the `.agent.md` suffix, and takes\n\t\t\t// `tools` as a YAML list (not the Claude comma string) — matching this\n\t\t\t// adapter's workspace.emitAgent and the current GitHub Copilot docs\n\t\t\t// (docs.github.com custom agents / plugins-creating; verified 2026-07).\n\t\t\tfiles.push({\n\t\t\t\tpath: path.join(\"agents\", `${slug(a.name)}.agent.md`),\n\t\t\t\tcontent: emitMarkdown(\n\t\t\t\t\t{ name: a.name, description: a.description, tools: toolsYamlList(a.tools), model: a.model },\n\t\t\t\t\ta.body,\n\t\t\t\t),\n\t\t\t});\n\t\t}\n\t\tif (draft.mcpServers?.length) {\n\t\t\tfiles.push({\n\t\t\t\tpath: \".mcp.json\",\n\t\t\t\tcontent: emitJson({\n\t\t\t\t\tmcpServers: Object.fromEntries(\n\t\t\t\t\t\tdraft.mcpServers.map((s) => [\n\t\t\t\t\t\t\ts.name,\n\t\t\t\t\t\t\t{ command: s.command, ...(s.args ? { args: s.args } : {}), ...(s.env ? { env: s.env } : {}) },\n\t\t\t\t\t\t]),\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t});\n\t\t}\n\t\tif (draft.hooks?.length) {\n\t\t\tfiles.push({\n\t\t\t\tpath: path.join(\"hooks\", \"hooks.json\"),\n\t\t\t\tcontent: emitJson({ hooks: authoredHooksToConfig(draft.hooks) }),\n\t\t\t});\n\t\t}\n\t\treturn files;\n\t},\n};\n"]}
|
|
1
|
+
{"version":3,"file":"copilot.js","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/copilot.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GitHub Copilot format.\n *\n * hoocode's preferred Copilot home is the `.github/plugin/` marker directory —\n * the convention used by the real-world plugins indexed by\n * github/copilot-plugins (e.g. microsoft/work-iq) and the documented location\n * for GitHub-hosted marketplaces. The official Copilot CLI plugin reference\n * (docs.github.com copilot/reference/copilot-cli-reference/cli-plugin-reference,\n * \"File locations\"; verified 2026-07) accepts several locations for both files\n * (`.plugin/`, plugin root, `.github/plugin/`, `.claude-plugin/`), so this\n * adapter reads them all — `.github/plugin/` first, then root, then `.plugin/`,\n * then the legacy hoocode layout — and writes `.github/plugin/`.\n * (`.claude-plugin/` belongs to the Claude adapter, which wins precedence, so a\n * `.claude-plugin`-only directory correctly parses as a Claude plugin; Copilot\n * reads those natively anyway.) The capability tree matches the Claude layout:\n *\n * skills skills/<name>/SKILL.md (or the manifest's `skills` path override)\n * commands .github/prompts/<name>.prompt.md (Copilot's prompt-file convention — the\n * analog of a slash command; a manifest\n * `commands` path or `commands/` dir is read too)\n * subagents agents/<name>.agent.md (Copilot's custom-agent convention — the\n * `.agent.md` suffix and a YAML-list `tools`\n * frontmatter are what Copilot recognizes; the\n * reader still accepts bare `.md` names)\n * hooks hooks.json or hooks/hooks.json ({ description?, hooks: { Event: [...] } })\n * MCP servers .mcp.json ({ mcpServers } | { servers })\n *\n * Workspace-level (non-plugin) conventions, per the current GitHub Copilot\n * customization docs (docs.github.com — agent skills, custom agents, prompt\n * files; verified 2026-07):\n *\n * skills .github/skills/<name>/SKILL.md (agentskills.io open standard)\n * custom agents .github/agents/<name>.agent.md (frontmatter: name, description,\n * tools as a YAML list, model, ...)\n * prompt files .github/prompts/<name>.prompt.md (VS Code / Copilot prompt files)\n *\n * Earlier hoocode releases authored a different Copilot mapping\n * (`.github/copilot-plugin.json` + `.github/prompts/*.prompt.md` +\n * `.github/chatmodes/*.chatmode.md`); the reader still accepts that layout as a\n * legacy fallback so previously authored plugins keep loading. Copilot\n * conventions move quickly; this file is the single place that encodes them,\n * so tracking an upstream change never reaches beyond this adapter.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { NormalizedPlugin } from \"../manifest.js\";\nimport {\n\tauthoredHooksToConfig,\n\tdetectUnsupportedSurfaces,\n\tdirIfExists,\n\temitJson,\n\temitMarkdown,\n\tnormalizeHooks,\n\tnormalizeMcp,\n\tparseAuthor,\n\ttype RawManifest,\n\treadJson,\n\tresolveCapabilityDir,\n\tslug,\n\ttoolsYamlList,\n\tunknownManifestFields,\n} from \"./shared.js\";\nimport type { EmittedFile, PluginDraft, PluginFormatAdapter } from \"./types.js\";\n\nconst MARKER_DIR = \".github\";\n/**\n * Manifest probe order, matching the Copilot CLI reference exactly:\n * `.plugin/` → root → `.github/plugin/` → (`.claude-plugin/`, which belongs to\n * the Claude adapter), with hoocode's legacy `.github/copilot-plugin.json` last.\n *\n * The order is the vendor's, not ours: a plugin carrying more than one manifest\n * must resolve to the same one under hoocode as under Copilot CLI, or the two\n * read different metadata from the same directory.\n */\nconst MANIFEST_REL_PATHS = [\n\tpath.join(\".plugin\", \"plugin.json\"),\n\t\"plugin.json\",\n\tpath.join(MARKER_DIR, \"plugin\", \"plugin.json\"),\n\tpath.join(MARKER_DIR, \"copilot-plugin.json\"),\n] as const;\n/**\n * Authored manifest location: root `plugin.json`, which is what the Copilot CLI\n * plugin-creating guide teaches and probe position #2. An earlier version emitted\n * `.github/plugin/plugin.json` while the comment here claimed root was canonical;\n * the comment was right. (`.github/plugin/` is still *read*, third in the probe\n * order above, since real marketplace-indexed plugins use it.)\n */\nconst emitManifestRelPath = \"plugin.json\";\n\n/**\n * Copilot prompt-file home. `.github/prompts/<name>.prompt.md` is the current\n * Copilot/VS Code prompt-file convention, and hoocode maps a plugin's commands\n * to it (both the writer and this reader), so it is the authored location for\n * commands — not merely a legacy fallback.\n */\nconst PROMPTS_DIR = path.join(MARKER_DIR, \"prompts\");\n// Legacy authored layout (read-only fallback).\nconst LEGACY_CHATMODES_DIR = path.join(MARKER_DIR, \"chatmodes\");\n// Documented alternates, not legacy: the reference lists both locations for each.\nconst ALT_MCP_FILE = path.join(MARKER_DIR, \"mcp.json\");\nconst ALT_HOOKS_FILE = path.join(\"hooks\", \"hooks.json\");\n// hoocode's own older authored layout, still read so those plugins keep loading.\nconst LEGACY_HOOKS_FILE = path.join(MARKER_DIR, \"hooks\", \"hooks.json\");\n\n/** Read a hooks JSON file (either `{ hooks: {...} }` or a bare event map). */\nfunction readHooksFile(root: string, rel: string): NormalizedPlugin[\"hooks\"] {\n\tconst file = path.join(root, rel);\n\tif (!fs.existsSync(file)) return undefined;\n\tconst raw = readJson<{ hooks?: Record<string, unknown> } | Record<string, unknown>>(file);\n\tif (!raw || typeof raw !== \"object\") return undefined;\n\tconst config = (\"hooks\" in raw && raw.hooks ? raw.hooks : raw) as NormalizedPlugin[\"hooks\"];\n\treturn config && Object.keys(config).length > 0 ? config : undefined;\n}\n\nfunction manifestPathFor(root: string): string | undefined {\n\tfor (const rel of MANIFEST_REL_PATHS) {\n\t\tif (readJson(path.join(root, rel)) != null) return path.join(root, rel);\n\t}\n\treturn undefined;\n}\n\n/**\n * Every plugin-relative path this adapter reads, for the Tier 2 drift check\n * (§2.2). Assembled from the constants above rather than restated, so a path\n * added to the reader cannot be missing from the declaration.\n */\nexport function copilotReadPaths(): string[] {\n\treturn [\n\t\t...MANIFEST_REL_PATHS,\n\t\tPROMPTS_DIR,\n\t\tLEGACY_CHATMODES_DIR,\n\t\tALT_MCP_FILE,\n\t\tALT_HOOKS_FILE,\n\t\tLEGACY_HOOKS_FILE,\n\t\t\"skills\",\n\t\t\"agents\",\n\t\t// The `<name>.agent.md` subagent convention, which the reference writes as\n\t\t// a suffix rather than a path.\n\t\t\".agent.md\",\n\t\t\"hooks.json\",\n\t\t\".mcp.json\",\n\t].map((p) => p.replace(/\\\\/g, \"/\"));\n}\n\nexport const copilotFormat: PluginFormatAdapter = {\n\tid: \"copilot\",\n\tplatform: \"github\",\n\tprecedence: 2,\n\tlabel: \"GitHub Copilot (.github)\",\n\t// .github/plugin/ first (hoocode's preferred Copilot home and the documented\n\t// location for GitHub-hosted marketplaces), then the legacy .github/ spot,\n\t// then the Copilot CLI's other probe locations (root, .plugin/).\n\tmarketplaceFiles: [\n\t\tpath.join(MARKER_DIR, \"plugin\", \"marketplace.json\"),\n\t\tpath.join(MARKER_DIR, \"marketplace.json\"),\n\t\t\"marketplace.json\",\n\t\tpath.join(\".plugin\", \"marketplace.json\"),\n\t],\n\n\tworkspace: {\n\t\troot: MARKER_DIR,\n\t\t// Copilot reads repo skills from .github/skills (also .claude/skills and\n\t\t// .agents/skills, which the sibling adapters cover).\n\t\temitSkill: (s) => ({\n\t\t\tpath: path.join(MARKER_DIR, \"skills\", slug(s.name), \"SKILL.md\"),\n\t\t\tcontent: emitMarkdown({ name: s.name, description: s.description }, s.body),\n\t\t}),\n\t\t// Custom agents take `tools` as a YAML list (not the Claude comma string).\n\t\temitAgent: (a) => ({\n\t\t\tpath: path.join(MARKER_DIR, \"agents\", `${slug(a.name)}.agent.md`),\n\t\t\tcontent: emitMarkdown(\n\t\t\t\t{ name: a.name, description: a.description, tools: toolsYamlList(a.tools), model: a.model },\n\t\t\t\ta.body,\n\t\t\t),\n\t\t}),\n\t\t// The closest Copilot equivalent of a slash command is a prompt file.\n\t\temitCommand: (c) => ({\n\t\t\tpath: path.join(MARKER_DIR, \"prompts\", `${slug(c.name)}.prompt.md`),\n\t\t\tcontent: emitMarkdown({ description: c.description }, c.body),\n\t\t}),\n\t},\n\n\thasManifest(root: string): boolean {\n\t\treturn manifestPathFor(root) !== undefined;\n\t},\n\n\tdetectPlugin(root: string): boolean {\n\t\treturn manifestPathFor(root) !== undefined;\n\t},\n\n\tparsePlugin(root: string): NormalizedPlugin | null {\n\t\tconst manifestPath = manifestPathFor(root);\n\t\tif (!manifestPath) return null;\n\t\tconst raw = readJson<RawManifest>(manifestPath);\n\t\tif (!raw) return null;\n\n\t\tconst id = (raw.name ?? path.basename(root)).trim();\n\t\tif (!id) return null;\n\n\t\treturn {\n\t\t\tid,\n\t\t\tversion: raw.version,\n\t\t\tdescription: raw.description,\n\t\t\tauthor: parseAuthor(raw.author),\n\t\t\troot,\n\t\t\tmanifestPath,\n\t\t\tformat: \"copilot\",\n\t\t\t// Single-format view; the registry widens this to every format present.\n\t\t\tsupportPlatform: [\"github\"],\n\t\t\t// Claude-mirror layout (manifest overrides honored), with the legacy\n\t\t\t// prompts/chatmodes locations as read-only fallbacks.\n\t\t\tskillsDir: resolveCapabilityDir(root, raw.skills, \"skills\"),\n\t\t\t// Commands map to Copilot prompt files at `.github/prompts/`; a manifest\n\t\t\t// `commands` override or a conventional `commands/` dir still wins if present.\n\t\t\tcommandsDir: resolveCapabilityDir(root, raw.commands, \"commands\") ?? dirIfExists(root, PROMPTS_DIR),\n\t\t\tagentsDir: resolveCapabilityDir(root, raw.agents, \"agents\") ?? dirIfExists(root, LEGACY_CHATMODES_DIR),\n\t\t\tthemesDir: resolveCapabilityDir(root, raw.themes, \"themes\"),\n\t\t\t// Manifest first, then the reference's two locations (root `hooks.json`\n\t\t\t// and `hooks/hooks.json`), then hoocode's legacy `.github/hooks/`.\n\t\t\thooks:\n\t\t\t\tnormalizeHooks(raw.hooks, root) ??\n\t\t\t\treadHooksFile(root, \"hooks.json\") ??\n\t\t\t\treadHooksFile(root, ALT_HOOKS_FILE) ??\n\t\t\t\treadHooksFile(root, LEGACY_HOOKS_FILE),\n\t\t\tmcpServers: normalizeMcp(raw.mcpServers, root) ?? normalizeMcp(undefined, root, ALT_MCP_FILE),\n\t\t\t// Providers are a native-only concept.\n\t\t\tproviders: undefined,\n\t\t\t// `extensions` and `lspServers` are real Copilot manifest keys we do not\n\t\t\t// model; carried here so an edit cannot drop them.\n\t\t\tunknownFields: unknownManifestFields(raw),\n\t\t\tunsupportedSurfaces: detectUnsupportedSurfaces(root),\n\t\t};\n\t},\n\n\temit(draft: PluginDraft): EmittedFile[] {\n\t\t// Only the manifest is Copilot-specific — the canonical location is root\n\t\t// `plugin.json` (Copilot CLI spec) — and the capability tree mirrors the\n\t\t// Claude layout, so a plugin authored for both platforms is one tree with a\n\t\t// root manifest for Copilot and a .claude-plugin/ manifest for Claude.\n\t\tconst files: EmittedFile[] = [];\n\n\t\tfiles.push({\n\t\t\tpath: emitManifestRelPath,\n\t\t\tcontent: emitJson({\n\t\t\t\t...(draft.unknownFields ?? {}),\n\t\t\t\tname: draft.id,\n\t\t\t\t...(draft.version ? { version: draft.version } : {}),\n\t\t\t\t...(draft.description ? { description: draft.description } : {}),\n\t\t\t\t// Spec: `author` is an object with a required `name`.\n\t\t\t\t...(draft.author ? { author: { name: draft.author } } : {}),\n\t\t\t}),\n\t\t});\n\n\t\tfor (const s of draft.skills ?? []) {\n\t\t\tfiles.push({\n\t\t\t\tpath: path.join(\"skills\", slug(s.name), \"SKILL.md\"),\n\t\t\t\tcontent: emitMarkdown({ name: s.name, description: s.description }, s.body),\n\t\t\t});\n\t\t}\n\t\tfor (const c of draft.commands ?? []) {\n\t\t\t// Copilot's analog of a slash command is a prompt file:\n\t\t\t// `.github/prompts/<name>.prompt.md` (docs.github.com prompt files;\n\t\t\t// verified 2026-07) — same target as this adapter's workspace.emitCommand.\n\t\t\tfiles.push({\n\t\t\t\tpath: path.join(PROMPTS_DIR, `${slug(c.name)}.prompt.md`),\n\t\t\t\tcontent: emitMarkdown({ description: c.description }, c.body),\n\t\t\t});\n\t\t}\n\t\tfor (const a of draft.agents ?? []) {\n\t\t\t// Copilot recognizes custom agents by the `.agent.md` suffix, and takes\n\t\t\t// `tools` as a YAML list (not the Claude comma string) — matching this\n\t\t\t// adapter's workspace.emitAgent and the current GitHub Copilot docs\n\t\t\t// (docs.github.com custom agents / plugins-creating; verified 2026-07).\n\t\t\tfiles.push({\n\t\t\t\tpath: path.join(\"agents\", `${slug(a.name)}.agent.md`),\n\t\t\t\tcontent: emitMarkdown(\n\t\t\t\t\t{ name: a.name, description: a.description, tools: toolsYamlList(a.tools), model: a.model },\n\t\t\t\t\ta.body,\n\t\t\t\t),\n\t\t\t});\n\t\t}\n\t\tif (draft.mcpServers?.length) {\n\t\t\tfiles.push({\n\t\t\t\tpath: \".mcp.json\",\n\t\t\t\tcontent: emitJson({\n\t\t\t\t\tmcpServers: Object.fromEntries(\n\t\t\t\t\t\tdraft.mcpServers.map((s) => [\n\t\t\t\t\t\t\ts.name,\n\t\t\t\t\t\t\t{ command: s.command, ...(s.args ? { args: s.args } : {}), ...(s.env ? { env: s.env } : {}) },\n\t\t\t\t\t\t]),\n\t\t\t\t\t),\n\t\t\t\t}),\n\t\t\t});\n\t\t}\n\t\tif (draft.hooks?.length) {\n\t\t\tfiles.push({\n\t\t\t\tpath: path.join(\"hooks\", \"hooks.json\"),\n\t\t\t\tcontent: emitJson({ hooks: authoredHooksToConfig(draft.hooks) }),\n\t\t\t});\n\t\t}\n\t\treturn files;\n\t},\n};\n"]}
|
|
@@ -19,6 +19,21 @@ export declare const PLUGIN_FORMATS: readonly PluginFormatAdapter[];
|
|
|
19
19
|
export declare function getFormat(id: PluginFormatId): PluginFormatAdapter | undefined;
|
|
20
20
|
/** Look up an adapter by its public platform token (`"github"` → Copilot). */
|
|
21
21
|
export declare function getFormatByPlatform(platform: MarketplacePlatform): PluginFormatAdapter | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* Whether `root` carries an actual manifest file, in any supported format.
|
|
24
|
+
* Cheap: existence only, no parse.
|
|
25
|
+
*/
|
|
26
|
+
export declare function hasAnyManifest(root: string): boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the skill scanner should treat `root` as a plugin and stop descending.
|
|
29
|
+
*
|
|
30
|
+
* Keyed on the **manifest**, deliberately not on `detectPlugin`. Claude's
|
|
31
|
+
* manifest-optional rule counts a bare `SKILL.md` as enough to make a directory a
|
|
32
|
+
* plugin — true inside a plugins directory, catastrophic inside a skills
|
|
33
|
+
* directory, where it describes every plain skill folder there is. Using
|
|
34
|
+
* `detectPlugin` here would make the scanner skip all of them.
|
|
35
|
+
*/
|
|
36
|
+
export declare function isPluginRoot(root: string): boolean;
|
|
22
37
|
/**
|
|
23
38
|
* Parse a plugin directory using the highest-precedence format present.
|
|
24
39
|
* Returns null when no registered format recognizes the directory.
|
|
@@ -26,7 +41,9 @@ export declare function getFormatByPlatform(platform: MarketplacePlatform): Plug
|
|
|
26
41
|
* `supportPlatform` records *every* format present (not just the winner), so a
|
|
27
42
|
* directory carrying more than one vendor layout reports all of them.
|
|
28
43
|
*/
|
|
29
|
-
export declare function parsePluginWithFormats(root: string
|
|
44
|
+
export declare function parsePluginWithFormats(root: string, options?: {
|
|
45
|
+
requireManifest?: boolean;
|
|
46
|
+
}): NormalizedPlugin | null;
|
|
30
47
|
/**
|
|
31
48
|
* Render a draft into the on-disk files for the given platforms (defaulting to
|
|
32
49
|
* the draft's own `supportPlatform`, then to every format). Files from different
|
|
@@ -35,4 +52,25 @@ export declare function parsePluginWithFormats(root: string): NormalizedPlugin |
|
|
|
35
52
|
export declare function emitForPlatforms(draft: PluginDraft, platforms?: MarketplacePlatform[]): EmittedFile[];
|
|
36
53
|
export { claudeFormat, copilotFormat };
|
|
37
54
|
export type { EmittedFile, MarketplacePlatform, PluginDraft, PluginFormatAdapter, PluginFormatId, } from "./types.js";
|
|
55
|
+
/**
|
|
56
|
+
* Everything the adapters claim to understand: manifest keys, plugin-relative
|
|
57
|
+
* paths they read, marketplace index locations, and the surfaces they knowingly
|
|
58
|
+
* skip.
|
|
59
|
+
*
|
|
60
|
+
* This is the input to the Tier 2 drift check (§2.2), and it is a *declaration*
|
|
61
|
+
* on purpose. A checker that inferred coverage by reading the parsers would be
|
|
62
|
+
* validating its own inference; a declared set is a claim the codebase makes,
|
|
63
|
+
* which a vendor reference can falsify.
|
|
64
|
+
*
|
|
65
|
+
* `unsupportedSurfaces` is not a gap list. Those paths are known and
|
|
66
|
+
* deliberately unhandled, so re-flagging them every run would bury the one
|
|
67
|
+
* finding that matters: a vendor path in neither set.
|
|
68
|
+
*/
|
|
69
|
+
export declare function declaredVocabulary(): {
|
|
70
|
+
manifestKeys: string[];
|
|
71
|
+
marketplaceKeys: string[];
|
|
72
|
+
readPaths: string[];
|
|
73
|
+
marketplaceFiles: string[];
|
|
74
|
+
unsupportedSurfaces: string[];
|
|
75
|
+
};
|
|
38
76
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAoB,MAAM,cAAc,CAAC;AAG/D,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,WAAW,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAErH,8EAA8E;AAC9E,eAAO,MAAM,cAAc,EAAE,SAAS,mBAAmB,EAEZ,CAAC;AAE9C,oDAAoD;AACpD,wBAAgB,SAAS,CAAC,EAAE,EAAE,cAAc,GAAG,mBAAmB,GAAG,SAAS,CAE7E;AAED,gFAA8E;AAC9E,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,mBAAmB,GAAG,mBAAmB,GAAG,SAAS,CAElG;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAElD;AAkCD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,gBAAgB,GAAG,IAAI,CAcrH;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,mBAAmB,EAAE,GAAG,WAAW,EAAE,CAWrG;AAED,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC;AACvC,YAAY,EACX,WAAW,EACX,mBAAmB,EACnB,WAAW,EACX,mBAAmB,EACnB,cAAc,GACd,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,IAAI;IACrC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,EAAE,MAAM,EAAE,CAAC;CAC9B,CAkBA","sourcesContent":["/**\n * Plugin format registry.\n *\n * The single ordered list of every supported plugin format. Readers, the\n * marketplace parser, and `ProposePlugin` all go through here instead of\n * branching on a format, so adding or evolving a vendor layout is a one-file\n * change (write/adjust an adapter, add it to {@link PLUGIN_FORMATS}).\n *\n * Order is precedence order — native `.agents-plugin` first, then Claude, then\n * Copilot — so \"first match wins\" when a directory carries more than one format.\n */\n\nimport type { NormalizedPlugin } from \"../manifest.js\";\nimport { agentsFormat } from \"./agents.js\";\nimport { claudeFormat } from \"./claude.js\";\nimport { copilotFormat, copilotReadPaths } from \"./copilot.js\";\nimport { JSON_MANIFEST_READ_PATHS } from \"./jsonManifest.js\";\nimport { knownUnsupportedSurfaces, modelledManifestKeys } from \"./shared.js\";\nimport type { EmittedFile, MarketplacePlatform, PluginDraft, PluginFormatAdapter, PluginFormatId } from \"./types.js\";\n\n/** All registered formats, in precedence order (lower `precedence` first). */\nexport const PLUGIN_FORMATS: readonly PluginFormatAdapter[] = [agentsFormat, claudeFormat, copilotFormat]\n\t.slice()\n\t.sort((a, b) => a.precedence - b.precedence);\n\n/** Look up an adapter by its internal format id. */\nexport function getFormat(id: PluginFormatId): PluginFormatAdapter | undefined {\n\treturn PLUGIN_FORMATS.find((f) => f.id === id);\n}\n\n/** Look up an adapter by its public platform token (`\"github\"` → Copilot). */\nexport function getFormatByPlatform(platform: MarketplacePlatform): PluginFormatAdapter | undefined {\n\treturn PLUGIN_FORMATS.find((f) => f.platform === platform);\n}\n\n/**\n * Whether `root` carries an actual manifest file, in any supported format.\n * Cheap: existence only, no parse.\n */\nexport function hasAnyManifest(root: string): boolean {\n\treturn PLUGIN_FORMATS.some((format) => format.hasManifest(root));\n}\n\n/**\n * Whether the skill scanner should treat `root` as a plugin and stop descending.\n *\n * Keyed on the **manifest**, deliberately not on `detectPlugin`. Claude's\n * manifest-optional rule counts a bare `SKILL.md` as enough to make a directory a\n * plugin — true inside a plugins directory, catastrophic inside a skills\n * directory, where it describes every plain skill folder there is. Using\n * `detectPlugin` here would make the scanner skip all of them.\n */\nexport function isPluginRoot(root: string): boolean {\n\treturn hasAnyManifest(root);\n}\n\n/**\n * Formats that recognize `root`, manifest-bearing ones first.\n *\n * The two-pass order matters. Claude's manifest-optional rule means its adapter\n * recognizes any directory with components in default locations — including a\n * Copilot plugin, which has its own manifest and a lower precedence number. A\n * single precedence-ordered pass would therefore hand every Copilot plugin to\n * the Claude adapter. An explicit manifest always beats an inferred match.\n */\nfunction matchingFormats(root: string): PluginFormatAdapter[] {\n\tconst withManifest = PLUGIN_FORMATS.filter((f) => f.hasManifest(root));\n\tconst inferred = PLUGIN_FORMATS.filter((f) => !f.hasManifest(root) && f.detectPlugin(root));\n\treturn [...withManifest, ...inferred];\n}\n\n/**\n * Every platform a plugin directory *offers*, precedence winner first.\n *\n * Manifest-bearing formats only: an inferred match means \"Claude would also load\n * this\", not \"this directory ships a Claude layout\", and reporting it would make\n * a Copilot-only plugin claim `[\"github\", \"claude\"]`. When nothing has a manifest\n * the inferred winner is all there is, so it stands alone.\n */\nfunction detectPlatforms(root: string): MarketplacePlatform[] {\n\tconst declared = PLUGIN_FORMATS.filter((f) => f.hasManifest(root));\n\tconst platforms: MarketplacePlatform[] = [];\n\tfor (const format of declared.length > 0 ? declared : matchingFormats(root).slice(0, 1)) {\n\t\tif (!platforms.includes(format.platform)) platforms.push(format.platform);\n\t}\n\treturn platforms;\n}\n\n/**\n * Parse a plugin directory using the highest-precedence format present.\n * Returns null when no registered format recognizes the directory.\n *\n * `supportPlatform` records *every* format present (not just the winner), so a\n * directory carrying more than one vendor layout reports all of them.\n */\nexport function parsePluginWithFormats(root: string, options?: { requireManifest?: boolean }): NormalizedPlugin | null {\n\t// Inside a skills directory the manifest is what promotes a folder from plain\n\t// skill to plugin, so manifest-less detection must be switched off there or\n\t// every skill folder becomes a plugin. See §1.6.\n\tif (options?.requireManifest && !hasAnyManifest(root)) return null;\n\tfor (const format of matchingFormats(root)) {\n\t\tconst parsed = format.parsePlugin(root);\n\t\tif (parsed) {\n\t\t\t// Winner's platform is already first; fold in the rest.\n\t\t\tconst supportPlatform = detectPlatforms(root);\n\t\t\treturn { ...parsed, supportPlatform };\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Render a draft into the on-disk files for the given platforms (defaulting to\n * the draft's own `supportPlatform`, then to every format). Files from different\n * formats live under distinct marker directories, so the merge never collides.\n */\nexport function emitForPlatforms(draft: PluginDraft, platforms?: MarketplacePlatform[]): EmittedFile[] {\n\tconst targets = platforms ?? draft.supportPlatform ?? PLUGIN_FORMATS.map((f) => f.platform);\n\tconst files: EmittedFile[] = [];\n\tconst seen = new Set<MarketplacePlatform>();\n\tfor (const platform of targets) {\n\t\tif (seen.has(platform)) continue;\n\t\tseen.add(platform);\n\t\tconst adapter = getFormatByPlatform(platform);\n\t\tif (adapter) files.push(...adapter.emit(draft));\n\t}\n\treturn files;\n}\n\nexport { claudeFormat, copilotFormat };\nexport type {\n\tEmittedFile,\n\tMarketplacePlatform,\n\tPluginDraft,\n\tPluginFormatAdapter,\n\tPluginFormatId,\n} from \"./types.js\";\n\n/**\n * Everything the adapters claim to understand: manifest keys, plugin-relative\n * paths they read, marketplace index locations, and the surfaces they knowingly\n * skip.\n *\n * This is the input to the Tier 2 drift check (§2.2), and it is a *declaration*\n * on purpose. A checker that inferred coverage by reading the parsers would be\n * validating its own inference; a declared set is a claim the codebase makes,\n * which a vendor reference can falsify.\n *\n * `unsupportedSurfaces` is not a gap list. Those paths are known and\n * deliberately unhandled, so re-flagging them every run would bury the one\n * finding that matters: a vendor path in neither set.\n */\nexport function declaredVocabulary(): {\n\tmanifestKeys: string[];\n\tmarketplaceKeys: string[];\n\treadPaths: string[];\n\tmarketplaceFiles: string[];\n\tunsupportedSurfaces: string[];\n} {\n\tconst readPaths = new Set<string>([...JSON_MANIFEST_READ_PATHS, ...copilotReadPaths()]);\n\tfor (const format of PLUGIN_FORMATS) {\n\t\treadPaths.add(\n\t\t\t`${format.id === \"copilot\" ? \".github\" : format.id === \"claude\" ? \".claude-plugin\" : \".agents-plugin\"}/plugin.json`,\n\t\t);\n\t}\n\treturn {\n\t\tmanifestKeys: modelledManifestKeys(),\n\t\t// Marketplace *index* keys, modelled by `parseMarketplaceDir`. Declared\n\t\t// separately from plugin-manifest keys but checked together: a reference\n\t\t// page documents both, and a drift check that knew only one of the two\n\t\t// vocabularies would report the other's fields as unknown every run.\n\t\tmarketplaceKeys: [\"name\", \"owner\", \"metadata\", \"pluginRoot\", \"plugins\", \"source\", \"supportPlatform\", \"strict\"],\n\t\treadPaths: [...readPaths].sort(),\n\t\tmarketplaceFiles: [...new Set(PLUGIN_FORMATS.flatMap((f) => f.marketplaceFiles))].sort(),\n\t\tunsupportedSurfaces: knownUnsupportedSurfaces(),\n\t};\n}\n"]}
|
|
@@ -11,7 +11,9 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { agentsFormat } from "./agents.js";
|
|
13
13
|
import { claudeFormat } from "./claude.js";
|
|
14
|
-
import { copilotFormat } from "./copilot.js";
|
|
14
|
+
import { copilotFormat, copilotReadPaths } from "./copilot.js";
|
|
15
|
+
import { JSON_MANIFEST_READ_PATHS } from "./jsonManifest.js";
|
|
16
|
+
import { knownUnsupportedSurfaces, modelledManifestKeys } from "./shared.js";
|
|
15
17
|
/** All registered formats, in precedence order (lower `precedence` first). */
|
|
16
18
|
export const PLUGIN_FORMATS = [agentsFormat, claudeFormat, copilotFormat]
|
|
17
19
|
.slice()
|
|
@@ -24,11 +26,52 @@ export function getFormat(id) {
|
|
|
24
26
|
export function getFormatByPlatform(platform) {
|
|
25
27
|
return PLUGIN_FORMATS.find((f) => f.platform === platform);
|
|
26
28
|
}
|
|
27
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Whether `root` carries an actual manifest file, in any supported format.
|
|
31
|
+
* Cheap: existence only, no parse.
|
|
32
|
+
*/
|
|
33
|
+
export function hasAnyManifest(root) {
|
|
34
|
+
return PLUGIN_FORMATS.some((format) => format.hasManifest(root));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Whether the skill scanner should treat `root` as a plugin and stop descending.
|
|
38
|
+
*
|
|
39
|
+
* Keyed on the **manifest**, deliberately not on `detectPlugin`. Claude's
|
|
40
|
+
* manifest-optional rule counts a bare `SKILL.md` as enough to make a directory a
|
|
41
|
+
* plugin — true inside a plugins directory, catastrophic inside a skills
|
|
42
|
+
* directory, where it describes every plain skill folder there is. Using
|
|
43
|
+
* `detectPlugin` here would make the scanner skip all of them.
|
|
44
|
+
*/
|
|
45
|
+
export function isPluginRoot(root) {
|
|
46
|
+
return hasAnyManifest(root);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Formats that recognize `root`, manifest-bearing ones first.
|
|
50
|
+
*
|
|
51
|
+
* The two-pass order matters. Claude's manifest-optional rule means its adapter
|
|
52
|
+
* recognizes any directory with components in default locations — including a
|
|
53
|
+
* Copilot plugin, which has its own manifest and a lower precedence number. A
|
|
54
|
+
* single precedence-ordered pass would therefore hand every Copilot plugin to
|
|
55
|
+
* the Claude adapter. An explicit manifest always beats an inferred match.
|
|
56
|
+
*/
|
|
57
|
+
function matchingFormats(root) {
|
|
58
|
+
const withManifest = PLUGIN_FORMATS.filter((f) => f.hasManifest(root));
|
|
59
|
+
const inferred = PLUGIN_FORMATS.filter((f) => !f.hasManifest(root) && f.detectPlugin(root));
|
|
60
|
+
return [...withManifest, ...inferred];
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Every platform a plugin directory *offers*, precedence winner first.
|
|
64
|
+
*
|
|
65
|
+
* Manifest-bearing formats only: an inferred match means "Claude would also load
|
|
66
|
+
* this", not "this directory ships a Claude layout", and reporting it would make
|
|
67
|
+
* a Copilot-only plugin claim `["github", "claude"]`. When nothing has a manifest
|
|
68
|
+
* the inferred winner is all there is, so it stands alone.
|
|
69
|
+
*/
|
|
28
70
|
function detectPlatforms(root) {
|
|
71
|
+
const declared = PLUGIN_FORMATS.filter((f) => f.hasManifest(root));
|
|
29
72
|
const platforms = [];
|
|
30
|
-
for (const format of
|
|
31
|
-
if (
|
|
73
|
+
for (const format of declared.length > 0 ? declared : matchingFormats(root).slice(0, 1)) {
|
|
74
|
+
if (!platforms.includes(format.platform))
|
|
32
75
|
platforms.push(format.platform);
|
|
33
76
|
}
|
|
34
77
|
return platforms;
|
|
@@ -40,15 +83,18 @@ function detectPlatforms(root) {
|
|
|
40
83
|
* `supportPlatform` records *every* format present (not just the winner), so a
|
|
41
84
|
* directory carrying more than one vendor layout reports all of them.
|
|
42
85
|
*/
|
|
43
|
-
export function parsePluginWithFormats(root) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
86
|
+
export function parsePluginWithFormats(root, options) {
|
|
87
|
+
// Inside a skills directory the manifest is what promotes a folder from plain
|
|
88
|
+
// skill to plugin, so manifest-less detection must be switched off there or
|
|
89
|
+
// every skill folder becomes a plugin. See §1.6.
|
|
90
|
+
if (options?.requireManifest && !hasAnyManifest(root))
|
|
91
|
+
return null;
|
|
92
|
+
for (const format of matchingFormats(root)) {
|
|
93
|
+
const parsed = format.parsePlugin(root);
|
|
94
|
+
if (parsed) {
|
|
95
|
+
// Winner's platform is already first; fold in the rest.
|
|
96
|
+
const supportPlatform = detectPlatforms(root);
|
|
97
|
+
return { ...parsed, supportPlatform };
|
|
52
98
|
}
|
|
53
99
|
}
|
|
54
100
|
return null;
|
|
@@ -73,4 +119,35 @@ export function emitForPlatforms(draft, platforms) {
|
|
|
73
119
|
return files;
|
|
74
120
|
}
|
|
75
121
|
export { claudeFormat, copilotFormat };
|
|
122
|
+
/**
|
|
123
|
+
* Everything the adapters claim to understand: manifest keys, plugin-relative
|
|
124
|
+
* paths they read, marketplace index locations, and the surfaces they knowingly
|
|
125
|
+
* skip.
|
|
126
|
+
*
|
|
127
|
+
* This is the input to the Tier 2 drift check (§2.2), and it is a *declaration*
|
|
128
|
+
* on purpose. A checker that inferred coverage by reading the parsers would be
|
|
129
|
+
* validating its own inference; a declared set is a claim the codebase makes,
|
|
130
|
+
* which a vendor reference can falsify.
|
|
131
|
+
*
|
|
132
|
+
* `unsupportedSurfaces` is not a gap list. Those paths are known and
|
|
133
|
+
* deliberately unhandled, so re-flagging them every run would bury the one
|
|
134
|
+
* finding that matters: a vendor path in neither set.
|
|
135
|
+
*/
|
|
136
|
+
export function declaredVocabulary() {
|
|
137
|
+
const readPaths = new Set([...JSON_MANIFEST_READ_PATHS, ...copilotReadPaths()]);
|
|
138
|
+
for (const format of PLUGIN_FORMATS) {
|
|
139
|
+
readPaths.add(`${format.id === "copilot" ? ".github" : format.id === "claude" ? ".claude-plugin" : ".agents-plugin"}/plugin.json`);
|
|
140
|
+
}
|
|
141
|
+
return {
|
|
142
|
+
manifestKeys: modelledManifestKeys(),
|
|
143
|
+
// Marketplace *index* keys, modelled by `parseMarketplaceDir`. Declared
|
|
144
|
+
// separately from plugin-manifest keys but checked together: a reference
|
|
145
|
+
// page documents both, and a drift check that knew only one of the two
|
|
146
|
+
// vocabularies would report the other's fields as unknown every run.
|
|
147
|
+
marketplaceKeys: ["name", "owner", "metadata", "pluginRoot", "plugins", "source", "supportPlatform", "strict"],
|
|
148
|
+
readPaths: [...readPaths].sort(),
|
|
149
|
+
marketplaceFiles: [...new Set(PLUGIN_FORMATS.flatMap((f) => f.marketplaceFiles))].sort(),
|
|
150
|
+
unsupportedSurfaces: knownUnsupportedSurfaces(),
|
|
151
|
+
};
|
|
152
|
+
}
|
|
76
153
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAG7C,8EAA8E;AAC9E,MAAM,CAAC,MAAM,cAAc,GAAmC,CAAC,YAAY,EAAE,YAAY,EAAE,aAAa,CAAC;KACvG,KAAK,EAAE;KACP,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC;AAE9C,oDAAoD;AACpD,MAAM,UAAU,SAAS,CAAC,EAAkB,EAAmC;IAC9E,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;AAAA,CAC/C;AAED,gFAA8E;AAC9E,MAAM,UAAU,mBAAmB,CAAC,QAA6B,EAAmC;IACnG,OAAO,cAAc,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;AAAA,CAC3D;AAED,6EAA6E;AAC7E,SAAS,eAAe,CAAC,IAAY,EAAyB;IAC7D,MAAM,SAAS,GAA0B,EAAE,CAAC;IAC5C,KAAK,MAAM,MAAM,IAAI,cAAc,EAAE,CAAC;QACrC,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACxG,CAAC;IACD,OAAO,SAAS,CAAC;AAAA,CACjB;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,IAAY,EAA2B;IAC7E,KAAK,MAAM,MAAM,IAAI,cAAc,EAAE,CAAC;QACrC,IAAI,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,MAAM,EAAE,CAAC;gBACZ,6EAA6E;gBAC7E,MAAM,eAAe,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;gBAC9C,OAAO,EAAE,GAAG,MAAM,EAAE,eAAe,EAAE,CAAC;YACvC,CAAC;QACF,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAkB,EAAE,SAAiC,EAAiB;IACtG,MAAM,OAAO,GAAG,SAAS,IAAI,KAAK,CAAC,eAAe,IAAI,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IAC5F,MAAM,KAAK,GAAkB,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC5C,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,SAAS;QACjC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACnB,MAAM,OAAO,GAAG,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC9C,IAAI,OAAO;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,KAAK,CAAC;AAAA,CACb;AAED,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,CAAC","sourcesContent":["/**\n * Plugin format registry.\n *\n * The single ordered list of every supported plugin format. Readers, the\n * marketplace parser, and `ProposePlugin` all go through here instead of\n * branching on a format, so adding or evolving a vendor layout is a one-file\n * change (write/adjust an adapter, add it to {@link PLUGIN_FORMATS}).\n *\n * Order is precedence order — native `.agents-plugin` first, then Claude, then\n * Copilot — so \"first match wins\" when a directory carries more than one format.\n */\n\nimport type { NormalizedPlugin } from \"../manifest.js\";\nimport { agentsFormat } from \"./agents.js\";\nimport { claudeFormat } from \"./claude.js\";\nimport { copilotFormat } from \"./copilot.js\";\nimport type { EmittedFile, MarketplacePlatform, PluginDraft, PluginFormatAdapter, PluginFormatId } from \"./types.js\";\n\n/** All registered formats, in precedence order (lower `precedence` first). */\nexport const PLUGIN_FORMATS: readonly PluginFormatAdapter[] = [agentsFormat, claudeFormat, copilotFormat]\n\t.slice()\n\t.sort((a, b) => a.precedence - b.precedence);\n\n/** Look up an adapter by its internal format id. */\nexport function getFormat(id: PluginFormatId): PluginFormatAdapter | undefined {\n\treturn PLUGIN_FORMATS.find((f) => f.id === id);\n}\n\n/** Look up an adapter by its public platform token (`\"github\"` → Copilot). */\nexport function getFormatByPlatform(platform: MarketplacePlatform): PluginFormatAdapter | undefined {\n\treturn PLUGIN_FORMATS.find((f) => f.platform === platform);\n}\n\n/** Every platform present in a plugin directory, precedence winner first. */\nfunction detectPlatforms(root: string): MarketplacePlatform[] {\n\tconst platforms: MarketplacePlatform[] = [];\n\tfor (const format of PLUGIN_FORMATS) {\n\t\tif (format.detectPlugin(root) && !platforms.includes(format.platform)) platforms.push(format.platform);\n\t}\n\treturn platforms;\n}\n\n/**\n * Parse a plugin directory using the highest-precedence format present.\n * Returns null when no registered format recognizes the directory.\n *\n * `supportPlatform` records *every* format present (not just the winner), so a\n * directory carrying more than one vendor layout reports all of them.\n */\nexport function parsePluginWithFormats(root: string): NormalizedPlugin | null {\n\tfor (const format of PLUGIN_FORMATS) {\n\t\tif (format.detectPlugin(root)) {\n\t\t\tconst parsed = format.parsePlugin(root);\n\t\t\tif (parsed) {\n\t\t\t\t// Winner's platform is already first via precedence order; fold in the rest.\n\t\t\t\tconst supportPlatform = detectPlatforms(root);\n\t\t\t\treturn { ...parsed, supportPlatform };\n\t\t\t}\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Render a draft into the on-disk files for the given platforms (defaulting to\n * the draft's own `supportPlatform`, then to every format). Files from different\n * formats live under distinct marker directories, so the merge never collides.\n */\nexport function emitForPlatforms(draft: PluginDraft, platforms?: MarketplacePlatform[]): EmittedFile[] {\n\tconst targets = platforms ?? draft.supportPlatform ?? PLUGIN_FORMATS.map((f) => f.platform);\n\tconst files: EmittedFile[] = [];\n\tconst seen = new Set<MarketplacePlatform>();\n\tfor (const platform of targets) {\n\t\tif (seen.has(platform)) continue;\n\t\tseen.add(platform);\n\t\tconst adapter = getFormatByPlatform(platform);\n\t\tif (adapter) files.push(...adapter.emit(draft));\n\t}\n\treturn files;\n}\n\nexport { claudeFormat, copilotFormat };\nexport type {\n\tEmittedFile,\n\tMarketplacePlatform,\n\tPluginDraft,\n\tPluginFormatAdapter,\n\tPluginFormatId,\n} from \"./types.js\";\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plugin format registry.\n *\n * The single ordered list of every supported plugin format. Readers, the\n * marketplace parser, and `ProposePlugin` all go through here instead of\n * branching on a format, so adding or evolving a vendor layout is a one-file\n * change (write/adjust an adapter, add it to {@link PLUGIN_FORMATS}).\n *\n * Order is precedence order — native `.agents-plugin` first, then Claude, then\n * Copilot — so \"first match wins\" when a directory carries more than one format.\n */\n\nimport type { NormalizedPlugin } from \"../manifest.js\";\nimport { agentsFormat } from \"./agents.js\";\nimport { claudeFormat } from \"./claude.js\";\nimport { copilotFormat, copilotReadPaths } from \"./copilot.js\";\nimport { JSON_MANIFEST_READ_PATHS } from \"./jsonManifest.js\";\nimport { knownUnsupportedSurfaces, modelledManifestKeys } from \"./shared.js\";\nimport type { EmittedFile, MarketplacePlatform, PluginDraft, PluginFormatAdapter, PluginFormatId } from \"./types.js\";\n\n/** All registered formats, in precedence order (lower `precedence` first). */\nexport const PLUGIN_FORMATS: readonly PluginFormatAdapter[] = [agentsFormat, claudeFormat, copilotFormat]\n\t.slice()\n\t.sort((a, b) => a.precedence - b.precedence);\n\n/** Look up an adapter by its internal format id. */\nexport function getFormat(id: PluginFormatId): PluginFormatAdapter | undefined {\n\treturn PLUGIN_FORMATS.find((f) => f.id === id);\n}\n\n/** Look up an adapter by its public platform token (`\"github\"` → Copilot). */\nexport function getFormatByPlatform(platform: MarketplacePlatform): PluginFormatAdapter | undefined {\n\treturn PLUGIN_FORMATS.find((f) => f.platform === platform);\n}\n\n/**\n * Whether `root` carries an actual manifest file, in any supported format.\n * Cheap: existence only, no parse.\n */\nexport function hasAnyManifest(root: string): boolean {\n\treturn PLUGIN_FORMATS.some((format) => format.hasManifest(root));\n}\n\n/**\n * Whether the skill scanner should treat `root` as a plugin and stop descending.\n *\n * Keyed on the **manifest**, deliberately not on `detectPlugin`. Claude's\n * manifest-optional rule counts a bare `SKILL.md` as enough to make a directory a\n * plugin — true inside a plugins directory, catastrophic inside a skills\n * directory, where it describes every plain skill folder there is. Using\n * `detectPlugin` here would make the scanner skip all of them.\n */\nexport function isPluginRoot(root: string): boolean {\n\treturn hasAnyManifest(root);\n}\n\n/**\n * Formats that recognize `root`, manifest-bearing ones first.\n *\n * The two-pass order matters. Claude's manifest-optional rule means its adapter\n * recognizes any directory with components in default locations — including a\n * Copilot plugin, which has its own manifest and a lower precedence number. A\n * single precedence-ordered pass would therefore hand every Copilot plugin to\n * the Claude adapter. An explicit manifest always beats an inferred match.\n */\nfunction matchingFormats(root: string): PluginFormatAdapter[] {\n\tconst withManifest = PLUGIN_FORMATS.filter((f) => f.hasManifest(root));\n\tconst inferred = PLUGIN_FORMATS.filter((f) => !f.hasManifest(root) && f.detectPlugin(root));\n\treturn [...withManifest, ...inferred];\n}\n\n/**\n * Every platform a plugin directory *offers*, precedence winner first.\n *\n * Manifest-bearing formats only: an inferred match means \"Claude would also load\n * this\", not \"this directory ships a Claude layout\", and reporting it would make\n * a Copilot-only plugin claim `[\"github\", \"claude\"]`. When nothing has a manifest\n * the inferred winner is all there is, so it stands alone.\n */\nfunction detectPlatforms(root: string): MarketplacePlatform[] {\n\tconst declared = PLUGIN_FORMATS.filter((f) => f.hasManifest(root));\n\tconst platforms: MarketplacePlatform[] = [];\n\tfor (const format of declared.length > 0 ? declared : matchingFormats(root).slice(0, 1)) {\n\t\tif (!platforms.includes(format.platform)) platforms.push(format.platform);\n\t}\n\treturn platforms;\n}\n\n/**\n * Parse a plugin directory using the highest-precedence format present.\n * Returns null when no registered format recognizes the directory.\n *\n * `supportPlatform` records *every* format present (not just the winner), so a\n * directory carrying more than one vendor layout reports all of them.\n */\nexport function parsePluginWithFormats(root: string, options?: { requireManifest?: boolean }): NormalizedPlugin | null {\n\t// Inside a skills directory the manifest is what promotes a folder from plain\n\t// skill to plugin, so manifest-less detection must be switched off there or\n\t// every skill folder becomes a plugin. See §1.6.\n\tif (options?.requireManifest && !hasAnyManifest(root)) return null;\n\tfor (const format of matchingFormats(root)) {\n\t\tconst parsed = format.parsePlugin(root);\n\t\tif (parsed) {\n\t\t\t// Winner's platform is already first; fold in the rest.\n\t\t\tconst supportPlatform = detectPlatforms(root);\n\t\t\treturn { ...parsed, supportPlatform };\n\t\t}\n\t}\n\treturn null;\n}\n\n/**\n * Render a draft into the on-disk files for the given platforms (defaulting to\n * the draft's own `supportPlatform`, then to every format). Files from different\n * formats live under distinct marker directories, so the merge never collides.\n */\nexport function emitForPlatforms(draft: PluginDraft, platforms?: MarketplacePlatform[]): EmittedFile[] {\n\tconst targets = platforms ?? draft.supportPlatform ?? PLUGIN_FORMATS.map((f) => f.platform);\n\tconst files: EmittedFile[] = [];\n\tconst seen = new Set<MarketplacePlatform>();\n\tfor (const platform of targets) {\n\t\tif (seen.has(platform)) continue;\n\t\tseen.add(platform);\n\t\tconst adapter = getFormatByPlatform(platform);\n\t\tif (adapter) files.push(...adapter.emit(draft));\n\t}\n\treturn files;\n}\n\nexport { claudeFormat, copilotFormat };\nexport type {\n\tEmittedFile,\n\tMarketplacePlatform,\n\tPluginDraft,\n\tPluginFormatAdapter,\n\tPluginFormatId,\n} from \"./types.js\";\n\n/**\n * Everything the adapters claim to understand: manifest keys, plugin-relative\n * paths they read, marketplace index locations, and the surfaces they knowingly\n * skip.\n *\n * This is the input to the Tier 2 drift check (§2.2), and it is a *declaration*\n * on purpose. A checker that inferred coverage by reading the parsers would be\n * validating its own inference; a declared set is a claim the codebase makes,\n * which a vendor reference can falsify.\n *\n * `unsupportedSurfaces` is not a gap list. Those paths are known and\n * deliberately unhandled, so re-flagging them every run would bury the one\n * finding that matters: a vendor path in neither set.\n */\nexport function declaredVocabulary(): {\n\tmanifestKeys: string[];\n\tmarketplaceKeys: string[];\n\treadPaths: string[];\n\tmarketplaceFiles: string[];\n\tunsupportedSurfaces: string[];\n} {\n\tconst readPaths = new Set<string>([...JSON_MANIFEST_READ_PATHS, ...copilotReadPaths()]);\n\tfor (const format of PLUGIN_FORMATS) {\n\t\treadPaths.add(\n\t\t\t`${format.id === \"copilot\" ? \".github\" : format.id === \"claude\" ? \".claude-plugin\" : \".agents-plugin\"}/plugin.json`,\n\t\t);\n\t}\n\treturn {\n\t\tmanifestKeys: modelledManifestKeys(),\n\t\t// Marketplace *index* keys, modelled by `parseMarketplaceDir`. Declared\n\t\t// separately from plugin-manifest keys but checked together: a reference\n\t\t// page documents both, and a drift check that knew only one of the two\n\t\t// vocabularies would report the other's fields as unknown every run.\n\t\tmarketplaceKeys: [\"name\", \"owner\", \"metadata\", \"pluginRoot\", \"plugins\", \"source\", \"supportPlatform\", \"strict\"],\n\t\treadPaths: [...readPaths].sort(),\n\t\tmarketplaceFiles: [...new Set(PLUGIN_FORMATS.flatMap((f) => f.marketplaceFiles))].sort(),\n\t\tunsupportedSurfaces: knownUnsupportedSurfaces(),\n\t};\n}\n"]}
|
|
@@ -7,8 +7,22 @@
|
|
|
7
7
|
* from this factory so the shared reader/writer lives in one place.
|
|
8
8
|
*/
|
|
9
9
|
import type { PluginFormatAdapter, PluginFormatId } from "./types.js";
|
|
10
|
+
/** Component locations that make a directory a plugin even with no manifest. */
|
|
11
|
+
export declare const CONVENTIONAL_COMPONENTS: string[];
|
|
12
|
+
/**
|
|
13
|
+
* Everything this adapter resolves, including surfaces that are read from the
|
|
14
|
+
* manifest rather than auto-discovered. Distinct from
|
|
15
|
+
* {@link CONVENTIONAL_COMPONENTS}, which drives *detection* — `themes` is parsed
|
|
16
|
+
* but has never made a directory a plugin on its own.
|
|
17
|
+
*/
|
|
18
|
+
export declare const JSON_MANIFEST_READ_PATHS: string[];
|
|
10
19
|
interface JsonManifestOptions {
|
|
11
20
|
id: Extract<PluginFormatId, "agents" | "claude">;
|
|
21
|
+
/**
|
|
22
|
+
* Honor the vendor's manifest-optional rule. True for Claude, whose reference
|
|
23
|
+
* states the manifest is optional for marketplace and `--plugin-dir` plugins.
|
|
24
|
+
*/
|
|
25
|
+
allowManifestless?: boolean;
|
|
12
26
|
/** Marker subdirectory, e.g. ".agents-plugin". */
|
|
13
27
|
manifestDir: string;
|
|
14
28
|
/** Workspace-level artifact root, e.g. ".agents" / ".claude" (skills/, agents/, commands/ live under it). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonManifest.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/jsonManifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"jsonManifest.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/jsonManifest.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAoBH,OAAO,KAAK,EAA4B,mBAAmB,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAIhG,gFAAgF;AAChF,eAAO,MAAM,uBAAuB,UAAqE,CAAC;AAE1G;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,UAA6D,CAAC;AAOnG,UAAU,mBAAmB;IAC5B,EAAE,EAAE,OAAO,CAAC,cAAc,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC;IACjD;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,kDAAkD;IAClD,WAAW,EAAE,MAAM,CAAC;IACpB,6GAA6G;IAC7G,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,iBAAiB,EAAE,OAAO,CAAC;CAC3B;AAED,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,mBAAmB,GAAG,mBAAmB,CAuHxF","sourcesContent":["/**\n * Factory for the `plugin.json`-style formats (native `.agents-plugin` and\n * Claude Code `.claude-plugin`). They share one on-disk layout — a JSON manifest\n * under a marker directory plus `skills/`, `commands/`, `agents/`, `themes/`,\n * `hooks/hooks.json` — and differ only in the marker directory, the format id,\n * and whether `providers` are honored (native-only). Both adapters are produced\n * from this factory so the shared reader/writer lives in one place.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { NormalizedPlugin, PluginProvider } from \"../manifest.js\";\nimport {\n\tauthoredHooksToConfig,\n\tclaudeStyleWorkspace,\n\tdetectUnsupportedSurfaces,\n\temitJson,\n\temitMarkdown,\n\tnormalizeHooks,\n\tnormalizeMcp,\n\tparseAuthor,\n\ttype RawManifest,\n\treadJson,\n\tresolveCapabilityDir,\n\tslug,\n\tunknownManifestFields,\n} from \"./shared.js\";\nimport type { EmittedFile, PluginDraft, PluginFormatAdapter, PluginFormatId } from \"./types.js\";\n\nconst MANIFEST_FILE = \"plugin.json\";\n\n/** Component locations that make a directory a plugin even with no manifest. */\nexport const CONVENTIONAL_COMPONENTS = [\"skills\", \"commands\", \"agents\", \"hooks\", \".mcp.json\", \"SKILL.md\"];\n\n/**\n * Everything this adapter resolves, including surfaces that are read from the\n * manifest rather than auto-discovered. Distinct from\n * {@link CONVENTIONAL_COMPONENTS}, which drives *detection* — `themes` is parsed\n * but has never made a directory a plugin on its own.\n */\nexport const JSON_MANIFEST_READ_PATHS = [...CONVENTIONAL_COMPONENTS, \"themes\", \"hooks/hooks.json\"];\n\n/** True when `root` carries any component in its default location. */\nfunction hasConventionalComponents(root: string): boolean {\n\treturn CONVENTIONAL_COMPONENTS.some((rel) => fs.existsSync(path.join(root, rel)));\n}\n\ninterface JsonManifestOptions {\n\tid: Extract<PluginFormatId, \"agents\" | \"claude\">;\n\t/**\n\t * Honor the vendor's manifest-optional rule. True for Claude, whose reference\n\t * states the manifest is optional for marketplace and `--plugin-dir` plugins.\n\t */\n\tallowManifestless?: boolean;\n\t/** Marker subdirectory, e.g. \".agents-plugin\". */\n\tmanifestDir: string;\n\t/** Workspace-level artifact root, e.g. \".agents\" / \".claude\" (skills/, agents/, commands/ live under it). */\n\tworkspaceRoot: string;\n\tprecedence: number;\n\tlabel: string;\n\t/** Native honors `providers`; the Claude-compat path ignores them. */\n\tsupportsProviders: boolean;\n}\n\nexport function createJsonManifestAdapter(opts: JsonManifestOptions): PluginFormatAdapter {\n\tconst manifestRelPath = path.join(opts.manifestDir, MANIFEST_FILE);\n\n\treturn {\n\t\tid: opts.id,\n\t\tplatform: opts.id, // \"agents\" | \"claude\" map 1:1 to their platform token\n\t\tprecedence: opts.precedence,\n\t\tlabel: opts.label,\n\t\tmarketplaceFiles: [path.join(opts.manifestDir, \"marketplace.json\")],\n\t\tworkspace: claudeStyleWorkspace(opts.workspaceRoot),\n\n\t\thasManifest(root: string): boolean {\n\t\t\treturn readJson(path.join(root, manifestRelPath)) != null;\n\t\t},\n\n\t\tdetectPlugin(root: string): boolean {\n\t\t\tif (this.hasManifest(root)) return true;\n\t\t\t// Manifest-optional: a directory whose components sit in the default\n\t\t\t// locations is a plugin, with the name derived from the directory.\n\t\t\t//\n\t\t\t// Deliberately NOT applied inside a skills directory: there the manifest\n\t\t\t// is precisely what promotes a folder from plain skill to plugin, so\n\t\t\t// `discoverPlugins` passes `requireManifest` for those roots. Two vendor\n\t\t\t// rules that look contradictory until you notice they describe different\n\t\t\t// containers. See docs/plugin-system-architecture.md §1.6 and §2.1.\n\t\t\treturn opts.allowManifestless === true && hasConventionalComponents(root);\n\t\t},\n\n\t\tparsePlugin(root: string): NormalizedPlugin | null {\n\t\t\tconst manifestPath = path.join(root, manifestRelPath);\n\t\t\tconst raw = readJson<RawManifest>(manifestPath) ?? (this.detectPlugin(root) ? {} : null);\n\t\t\tif (!raw) return null;\n\n\t\t\tconst id = (raw.name ?? path.basename(root)).trim();\n\t\t\tif (!id) return null;\n\n\t\t\tconst providers: PluginProvider[] | undefined =\n\t\t\t\topts.supportsProviders && Array.isArray(raw.providers) ? (raw.providers as PluginProvider[]) : undefined;\n\n\t\t\treturn {\n\t\t\t\tid,\n\t\t\t\tversion: raw.version,\n\t\t\t\tdescription: raw.description,\n\t\t\t\tauthor: parseAuthor(raw.author),\n\t\t\t\troot,\n\t\t\t\tmanifestPath,\n\t\t\t\tformat: opts.id,\n\t\t\t\t// Single-format view; the registry widens this to every format present.\n\t\t\t\tsupportPlatform: [opts.id],\n\t\t\t\t// A plugin shipping exactly one skill may put SKILL.md at its root\n\t\t\t\t// instead of creating skills/ (Claude reference, \"Skills\").\n\t\t\t\tskillsDir:\n\t\t\t\t\tresolveCapabilityDir(root, raw.skills, \"skills\") ??\n\t\t\t\t\t(fs.existsSync(path.join(root, \"SKILL.md\")) ? root : undefined),\n\t\t\t\tcommandsDir: resolveCapabilityDir(root, raw.commands, \"commands\"),\n\t\t\t\tagentsDir: resolveCapabilityDir(root, raw.agents, \"agents\"),\n\t\t\t\tthemesDir: resolveCapabilityDir(root, raw.themes, \"themes\"),\n\t\t\t\thooks: normalizeHooks(raw.hooks, root),\n\t\t\t\tmcpServers: normalizeMcp(raw.mcpServers, root),\n\t\t\t\tproviders,\n\t\t\t\tunknownFields: unknownManifestFields(raw),\n\t\t\t\tunsupportedSurfaces: detectUnsupportedSurfaces(root),\n\t\t\t};\n\t\t},\n\n\t\temit(draft: PluginDraft): EmittedFile[] {\n\t\t\tconst files: EmittedFile[] = [];\n\t\t\tconst mcpServers = draft.mcpServers?.length\n\t\t\t\t? Object.fromEntries(\n\t\t\t\t\t\tdraft.mcpServers.map((s) => [\n\t\t\t\t\t\t\ts.name,\n\t\t\t\t\t\t\t{ command: s.command, ...(s.args ? { args: s.args } : {}), ...(s.env ? { env: s.env } : {}) },\n\t\t\t\t\t\t]),\n\t\t\t\t\t)\n\t\t\t\t: undefined;\n\n\t\t\tfiles.push({\n\t\t\t\tpath: manifestRelPath,\n\t\t\t\tcontent: emitJson({\n\t\t\t\t\t...(draft.unknownFields ?? {}),\n\t\t\t\t\tname: draft.id,\n\t\t\t\t\t...(draft.version ? { version: draft.version } : {}),\n\t\t\t\t\t...(draft.description ? { description: draft.description } : {}),\n\t\t\t\t\t// Claude Code's schema documents `author` as an object with `name`.\n\t\t\t\t\t...(draft.author ? { author: { name: draft.author } } : {}),\n\t\t\t\t\t...(mcpServers ? { mcpServers } : {}),\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tfor (const s of draft.skills ?? []) {\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: path.join(\"skills\", slug(s.name), \"SKILL.md\"),\n\t\t\t\t\tcontent: emitMarkdown({ name: s.name, description: s.description }, s.body),\n\t\t\t\t});\n\t\t\t}\n\t\t\tfor (const c of draft.commands ?? []) {\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: path.join(\"commands\", `${slug(c.name)}.md`),\n\t\t\t\t\tcontent: emitMarkdown({ description: c.description }, c.body),\n\t\t\t\t});\n\t\t\t}\n\t\t\tfor (const a of draft.agents ?? []) {\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: path.join(\"agents\", `${slug(a.name)}.md`),\n\t\t\t\t\tcontent: emitMarkdown(\n\t\t\t\t\t\t{ name: a.name, description: a.description, tools: a.tools, model: a.model },\n\t\t\t\t\t\ta.body,\n\t\t\t\t\t),\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (draft.hooks?.length) {\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: path.join(\"hooks\", \"hooks.json\"),\n\t\t\t\t\tcontent: emitJson({ hooks: authoredHooksToConfig(draft.hooks) }),\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn files;\n\t\t},\n\t};\n}\n"]}
|
|
@@ -6,9 +6,23 @@
|
|
|
6
6
|
* and whether `providers` are honored (native-only). Both adapters are produced
|
|
7
7
|
* from this factory so the shared reader/writer lives in one place.
|
|
8
8
|
*/
|
|
9
|
+
import * as fs from "node:fs";
|
|
9
10
|
import * as path from "node:path";
|
|
10
|
-
import { authoredHooksToConfig, claudeStyleWorkspace, emitJson, emitMarkdown, normalizeHooks, normalizeMcp, parseAuthor, readJson, resolveCapabilityDir, slug, } from "./shared.js";
|
|
11
|
+
import { authoredHooksToConfig, claudeStyleWorkspace, detectUnsupportedSurfaces, emitJson, emitMarkdown, normalizeHooks, normalizeMcp, parseAuthor, readJson, resolveCapabilityDir, slug, unknownManifestFields, } from "./shared.js";
|
|
11
12
|
const MANIFEST_FILE = "plugin.json";
|
|
13
|
+
/** Component locations that make a directory a plugin even with no manifest. */
|
|
14
|
+
export const CONVENTIONAL_COMPONENTS = ["skills", "commands", "agents", "hooks", ".mcp.json", "SKILL.md"];
|
|
15
|
+
/**
|
|
16
|
+
* Everything this adapter resolves, including surfaces that are read from the
|
|
17
|
+
* manifest rather than auto-discovered. Distinct from
|
|
18
|
+
* {@link CONVENTIONAL_COMPONENTS}, which drives *detection* — `themes` is parsed
|
|
19
|
+
* but has never made a directory a plugin on its own.
|
|
20
|
+
*/
|
|
21
|
+
export const JSON_MANIFEST_READ_PATHS = [...CONVENTIONAL_COMPONENTS, "themes", "hooks/hooks.json"];
|
|
22
|
+
/** True when `root` carries any component in its default location. */
|
|
23
|
+
function hasConventionalComponents(root) {
|
|
24
|
+
return CONVENTIONAL_COMPONENTS.some((rel) => fs.existsSync(path.join(root, rel)));
|
|
25
|
+
}
|
|
12
26
|
export function createJsonManifestAdapter(opts) {
|
|
13
27
|
const manifestRelPath = path.join(opts.manifestDir, MANIFEST_FILE);
|
|
14
28
|
return {
|
|
@@ -18,12 +32,25 @@ export function createJsonManifestAdapter(opts) {
|
|
|
18
32
|
label: opts.label,
|
|
19
33
|
marketplaceFiles: [path.join(opts.manifestDir, "marketplace.json")],
|
|
20
34
|
workspace: claudeStyleWorkspace(opts.workspaceRoot),
|
|
21
|
-
|
|
35
|
+
hasManifest(root) {
|
|
22
36
|
return readJson(path.join(root, manifestRelPath)) != null;
|
|
23
37
|
},
|
|
38
|
+
detectPlugin(root) {
|
|
39
|
+
if (this.hasManifest(root))
|
|
40
|
+
return true;
|
|
41
|
+
// Manifest-optional: a directory whose components sit in the default
|
|
42
|
+
// locations is a plugin, with the name derived from the directory.
|
|
43
|
+
//
|
|
44
|
+
// Deliberately NOT applied inside a skills directory: there the manifest
|
|
45
|
+
// is precisely what promotes a folder from plain skill to plugin, so
|
|
46
|
+
// `discoverPlugins` passes `requireManifest` for those roots. Two vendor
|
|
47
|
+
// rules that look contradictory until you notice they describe different
|
|
48
|
+
// containers. See docs/plugin-system-architecture.md §1.6 and §2.1.
|
|
49
|
+
return opts.allowManifestless === true && hasConventionalComponents(root);
|
|
50
|
+
},
|
|
24
51
|
parsePlugin(root) {
|
|
25
52
|
const manifestPath = path.join(root, manifestRelPath);
|
|
26
|
-
const raw = readJson(manifestPath);
|
|
53
|
+
const raw = readJson(manifestPath) ?? (this.detectPlugin(root) ? {} : null);
|
|
27
54
|
if (!raw)
|
|
28
55
|
return null;
|
|
29
56
|
const id = (raw.name ?? path.basename(root)).trim();
|
|
@@ -40,13 +67,18 @@ export function createJsonManifestAdapter(opts) {
|
|
|
40
67
|
format: opts.id,
|
|
41
68
|
// Single-format view; the registry widens this to every format present.
|
|
42
69
|
supportPlatform: [opts.id],
|
|
43
|
-
|
|
70
|
+
// A plugin shipping exactly one skill may put SKILL.md at its root
|
|
71
|
+
// instead of creating skills/ (Claude reference, "Skills").
|
|
72
|
+
skillsDir: resolveCapabilityDir(root, raw.skills, "skills") ??
|
|
73
|
+
(fs.existsSync(path.join(root, "SKILL.md")) ? root : undefined),
|
|
44
74
|
commandsDir: resolveCapabilityDir(root, raw.commands, "commands"),
|
|
45
75
|
agentsDir: resolveCapabilityDir(root, raw.agents, "agents"),
|
|
46
76
|
themesDir: resolveCapabilityDir(root, raw.themes, "themes"),
|
|
47
77
|
hooks: normalizeHooks(raw.hooks, root),
|
|
48
78
|
mcpServers: normalizeMcp(raw.mcpServers, root),
|
|
49
79
|
providers,
|
|
80
|
+
unknownFields: unknownManifestFields(raw),
|
|
81
|
+
unsupportedSurfaces: detectUnsupportedSurfaces(root),
|
|
50
82
|
};
|
|
51
83
|
},
|
|
52
84
|
emit(draft) {
|
|
@@ -60,6 +92,7 @@ export function createJsonManifestAdapter(opts) {
|
|
|
60
92
|
files.push({
|
|
61
93
|
path: manifestRelPath,
|
|
62
94
|
content: emitJson({
|
|
95
|
+
...(draft.unknownFields ?? {}),
|
|
63
96
|
name: draft.id,
|
|
64
97
|
...(draft.version ? { version: draft.version } : {}),
|
|
65
98
|
...(draft.description ? { description: draft.description } : {}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jsonManifest.js","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/jsonManifest.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Factory for the `plugin.json`-style formats (native `.agents-plugin` and\n * Claude Code `.claude-plugin`). They share one on-disk layout — a JSON manifest\n * under a marker directory plus `skills/`, `commands/`, `agents/`, `themes/`,\n * `hooks/hooks.json` — and differ only in the marker directory, the format id,\n * and whether `providers` are honored (native-only). Both adapters are produced\n * from this factory so the shared reader/writer lives in one place.\n */\n\nimport * as path from \"node:path\";\nimport type { NormalizedPlugin, PluginProvider } from \"../manifest.js\";\nimport {\n\tauthoredHooksToConfig,\n\tclaudeStyleWorkspace,\n\temitJson,\n\temitMarkdown,\n\tnormalizeHooks,\n\tnormalizeMcp,\n\tparseAuthor,\n\ttype RawManifest,\n\treadJson,\n\tresolveCapabilityDir,\n\tslug,\n} from \"./shared.js\";\nimport type { EmittedFile, PluginDraft, PluginFormatAdapter, PluginFormatId } from \"./types.js\";\n\nconst MANIFEST_FILE = \"plugin.json\";\n\ninterface JsonManifestOptions {\n\tid: Extract<PluginFormatId, \"agents\" | \"claude\">;\n\t/** Marker subdirectory, e.g. \".agents-plugin\". */\n\tmanifestDir: string;\n\t/** Workspace-level artifact root, e.g. \".agents\" / \".claude\" (skills/, agents/, commands/ live under it). */\n\tworkspaceRoot: string;\n\tprecedence: number;\n\tlabel: string;\n\t/** Native honors `providers`; the Claude-compat path ignores them. */\n\tsupportsProviders: boolean;\n}\n\nexport function createJsonManifestAdapter(opts: JsonManifestOptions): PluginFormatAdapter {\n\tconst manifestRelPath = path.join(opts.manifestDir, MANIFEST_FILE);\n\n\treturn {\n\t\tid: opts.id,\n\t\tplatform: opts.id, // \"agents\" | \"claude\" map 1:1 to their platform token\n\t\tprecedence: opts.precedence,\n\t\tlabel: opts.label,\n\t\tmarketplaceFiles: [path.join(opts.manifestDir, \"marketplace.json\")],\n\t\tworkspace: claudeStyleWorkspace(opts.workspaceRoot),\n\n\t\tdetectPlugin(root: string): boolean {\n\t\t\treturn readJson(path.join(root, manifestRelPath)) != null;\n\t\t},\n\n\t\tparsePlugin(root: string): NormalizedPlugin | null {\n\t\t\tconst manifestPath = path.join(root, manifestRelPath);\n\t\t\tconst raw = readJson<RawManifest>(manifestPath);\n\t\t\tif (!raw) return null;\n\n\t\t\tconst id = (raw.name ?? path.basename(root)).trim();\n\t\t\tif (!id) return null;\n\n\t\t\tconst providers: PluginProvider[] | undefined =\n\t\t\t\topts.supportsProviders && Array.isArray(raw.providers) ? (raw.providers as PluginProvider[]) : undefined;\n\n\t\t\treturn {\n\t\t\t\tid,\n\t\t\t\tversion: raw.version,\n\t\t\t\tdescription: raw.description,\n\t\t\t\tauthor: parseAuthor(raw.author),\n\t\t\t\troot,\n\t\t\t\tmanifestPath,\n\t\t\t\tformat: opts.id,\n\t\t\t\t// Single-format view; the registry widens this to every format present.\n\t\t\t\tsupportPlatform: [opts.id],\n\t\t\t\tskillsDir: resolveCapabilityDir(root, raw.skills, \"skills\"),\n\t\t\t\tcommandsDir: resolveCapabilityDir(root, raw.commands, \"commands\"),\n\t\t\t\tagentsDir: resolveCapabilityDir(root, raw.agents, \"agents\"),\n\t\t\t\tthemesDir: resolveCapabilityDir(root, raw.themes, \"themes\"),\n\t\t\t\thooks: normalizeHooks(raw.hooks, root),\n\t\t\t\tmcpServers: normalizeMcp(raw.mcpServers, root),\n\t\t\t\tproviders,\n\t\t\t};\n\t\t},\n\n\t\temit(draft: PluginDraft): EmittedFile[] {\n\t\t\tconst files: EmittedFile[] = [];\n\t\t\tconst mcpServers = draft.mcpServers?.length\n\t\t\t\t? Object.fromEntries(\n\t\t\t\t\t\tdraft.mcpServers.map((s) => [\n\t\t\t\t\t\t\ts.name,\n\t\t\t\t\t\t\t{ command: s.command, ...(s.args ? { args: s.args } : {}), ...(s.env ? { env: s.env } : {}) },\n\t\t\t\t\t\t]),\n\t\t\t\t\t)\n\t\t\t\t: undefined;\n\n\t\t\tfiles.push({\n\t\t\t\tpath: manifestRelPath,\n\t\t\t\tcontent: emitJson({\n\t\t\t\t\tname: draft.id,\n\t\t\t\t\t...(draft.version ? { version: draft.version } : {}),\n\t\t\t\t\t...(draft.description ? { description: draft.description } : {}),\n\t\t\t\t\t// Claude Code's schema documents `author` as an object with `name`.\n\t\t\t\t\t...(draft.author ? { author: { name: draft.author } } : {}),\n\t\t\t\t\t...(mcpServers ? { mcpServers } : {}),\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tfor (const s of draft.skills ?? []) {\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: path.join(\"skills\", slug(s.name), \"SKILL.md\"),\n\t\t\t\t\tcontent: emitMarkdown({ name: s.name, description: s.description }, s.body),\n\t\t\t\t});\n\t\t\t}\n\t\t\tfor (const c of draft.commands ?? []) {\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: path.join(\"commands\", `${slug(c.name)}.md`),\n\t\t\t\t\tcontent: emitMarkdown({ description: c.description }, c.body),\n\t\t\t\t});\n\t\t\t}\n\t\t\tfor (const a of draft.agents ?? []) {\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: path.join(\"agents\", `${slug(a.name)}.md`),\n\t\t\t\t\tcontent: emitMarkdown(\n\t\t\t\t\t\t{ name: a.name, description: a.description, tools: a.tools, model: a.model },\n\t\t\t\t\t\ta.body,\n\t\t\t\t\t),\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (draft.hooks?.length) {\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: path.join(\"hooks\", \"hooks.json\"),\n\t\t\t\t\tcontent: emitJson({ hooks: authoredHooksToConfig(draft.hooks) }),\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn files;\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"file":"jsonManifest.js","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/jsonManifest.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Factory for the `plugin.json`-style formats (native `.agents-plugin` and\n * Claude Code `.claude-plugin`). They share one on-disk layout — a JSON manifest\n * under a marker directory plus `skills/`, `commands/`, `agents/`, `themes/`,\n * `hooks/hooks.json` — and differ only in the marker directory, the format id,\n * and whether `providers` are honored (native-only). Both adapters are produced\n * from this factory so the shared reader/writer lives in one place.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { NormalizedPlugin, PluginProvider } from \"../manifest.js\";\nimport {\n\tauthoredHooksToConfig,\n\tclaudeStyleWorkspace,\n\tdetectUnsupportedSurfaces,\n\temitJson,\n\temitMarkdown,\n\tnormalizeHooks,\n\tnormalizeMcp,\n\tparseAuthor,\n\ttype RawManifest,\n\treadJson,\n\tresolveCapabilityDir,\n\tslug,\n\tunknownManifestFields,\n} from \"./shared.js\";\nimport type { EmittedFile, PluginDraft, PluginFormatAdapter, PluginFormatId } from \"./types.js\";\n\nconst MANIFEST_FILE = \"plugin.json\";\n\n/** Component locations that make a directory a plugin even with no manifest. */\nexport const CONVENTIONAL_COMPONENTS = [\"skills\", \"commands\", \"agents\", \"hooks\", \".mcp.json\", \"SKILL.md\"];\n\n/**\n * Everything this adapter resolves, including surfaces that are read from the\n * manifest rather than auto-discovered. Distinct from\n * {@link CONVENTIONAL_COMPONENTS}, which drives *detection* — `themes` is parsed\n * but has never made a directory a plugin on its own.\n */\nexport const JSON_MANIFEST_READ_PATHS = [...CONVENTIONAL_COMPONENTS, \"themes\", \"hooks/hooks.json\"];\n\n/** True when `root` carries any component in its default location. */\nfunction hasConventionalComponents(root: string): boolean {\n\treturn CONVENTIONAL_COMPONENTS.some((rel) => fs.existsSync(path.join(root, rel)));\n}\n\ninterface JsonManifestOptions {\n\tid: Extract<PluginFormatId, \"agents\" | \"claude\">;\n\t/**\n\t * Honor the vendor's manifest-optional rule. True for Claude, whose reference\n\t * states the manifest is optional for marketplace and `--plugin-dir` plugins.\n\t */\n\tallowManifestless?: boolean;\n\t/** Marker subdirectory, e.g. \".agents-plugin\". */\n\tmanifestDir: string;\n\t/** Workspace-level artifact root, e.g. \".agents\" / \".claude\" (skills/, agents/, commands/ live under it). */\n\tworkspaceRoot: string;\n\tprecedence: number;\n\tlabel: string;\n\t/** Native honors `providers`; the Claude-compat path ignores them. */\n\tsupportsProviders: boolean;\n}\n\nexport function createJsonManifestAdapter(opts: JsonManifestOptions): PluginFormatAdapter {\n\tconst manifestRelPath = path.join(opts.manifestDir, MANIFEST_FILE);\n\n\treturn {\n\t\tid: opts.id,\n\t\tplatform: opts.id, // \"agents\" | \"claude\" map 1:1 to their platform token\n\t\tprecedence: opts.precedence,\n\t\tlabel: opts.label,\n\t\tmarketplaceFiles: [path.join(opts.manifestDir, \"marketplace.json\")],\n\t\tworkspace: claudeStyleWorkspace(opts.workspaceRoot),\n\n\t\thasManifest(root: string): boolean {\n\t\t\treturn readJson(path.join(root, manifestRelPath)) != null;\n\t\t},\n\n\t\tdetectPlugin(root: string): boolean {\n\t\t\tif (this.hasManifest(root)) return true;\n\t\t\t// Manifest-optional: a directory whose components sit in the default\n\t\t\t// locations is a plugin, with the name derived from the directory.\n\t\t\t//\n\t\t\t// Deliberately NOT applied inside a skills directory: there the manifest\n\t\t\t// is precisely what promotes a folder from plain skill to plugin, so\n\t\t\t// `discoverPlugins` passes `requireManifest` for those roots. Two vendor\n\t\t\t// rules that look contradictory until you notice they describe different\n\t\t\t// containers. See docs/plugin-system-architecture.md §1.6 and §2.1.\n\t\t\treturn opts.allowManifestless === true && hasConventionalComponents(root);\n\t\t},\n\n\t\tparsePlugin(root: string): NormalizedPlugin | null {\n\t\t\tconst manifestPath = path.join(root, manifestRelPath);\n\t\t\tconst raw = readJson<RawManifest>(manifestPath) ?? (this.detectPlugin(root) ? {} : null);\n\t\t\tif (!raw) return null;\n\n\t\t\tconst id = (raw.name ?? path.basename(root)).trim();\n\t\t\tif (!id) return null;\n\n\t\t\tconst providers: PluginProvider[] | undefined =\n\t\t\t\topts.supportsProviders && Array.isArray(raw.providers) ? (raw.providers as PluginProvider[]) : undefined;\n\n\t\t\treturn {\n\t\t\t\tid,\n\t\t\t\tversion: raw.version,\n\t\t\t\tdescription: raw.description,\n\t\t\t\tauthor: parseAuthor(raw.author),\n\t\t\t\troot,\n\t\t\t\tmanifestPath,\n\t\t\t\tformat: opts.id,\n\t\t\t\t// Single-format view; the registry widens this to every format present.\n\t\t\t\tsupportPlatform: [opts.id],\n\t\t\t\t// A plugin shipping exactly one skill may put SKILL.md at its root\n\t\t\t\t// instead of creating skills/ (Claude reference, \"Skills\").\n\t\t\t\tskillsDir:\n\t\t\t\t\tresolveCapabilityDir(root, raw.skills, \"skills\") ??\n\t\t\t\t\t(fs.existsSync(path.join(root, \"SKILL.md\")) ? root : undefined),\n\t\t\t\tcommandsDir: resolveCapabilityDir(root, raw.commands, \"commands\"),\n\t\t\t\tagentsDir: resolveCapabilityDir(root, raw.agents, \"agents\"),\n\t\t\t\tthemesDir: resolveCapabilityDir(root, raw.themes, \"themes\"),\n\t\t\t\thooks: normalizeHooks(raw.hooks, root),\n\t\t\t\tmcpServers: normalizeMcp(raw.mcpServers, root),\n\t\t\t\tproviders,\n\t\t\t\tunknownFields: unknownManifestFields(raw),\n\t\t\t\tunsupportedSurfaces: detectUnsupportedSurfaces(root),\n\t\t\t};\n\t\t},\n\n\t\temit(draft: PluginDraft): EmittedFile[] {\n\t\t\tconst files: EmittedFile[] = [];\n\t\t\tconst mcpServers = draft.mcpServers?.length\n\t\t\t\t? Object.fromEntries(\n\t\t\t\t\t\tdraft.mcpServers.map((s) => [\n\t\t\t\t\t\t\ts.name,\n\t\t\t\t\t\t\t{ command: s.command, ...(s.args ? { args: s.args } : {}), ...(s.env ? { env: s.env } : {}) },\n\t\t\t\t\t\t]),\n\t\t\t\t\t)\n\t\t\t\t: undefined;\n\n\t\t\tfiles.push({\n\t\t\t\tpath: manifestRelPath,\n\t\t\t\tcontent: emitJson({\n\t\t\t\t\t...(draft.unknownFields ?? {}),\n\t\t\t\t\tname: draft.id,\n\t\t\t\t\t...(draft.version ? { version: draft.version } : {}),\n\t\t\t\t\t...(draft.description ? { description: draft.description } : {}),\n\t\t\t\t\t// Claude Code's schema documents `author` as an object with `name`.\n\t\t\t\t\t...(draft.author ? { author: { name: draft.author } } : {}),\n\t\t\t\t\t...(mcpServers ? { mcpServers } : {}),\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tfor (const s of draft.skills ?? []) {\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: path.join(\"skills\", slug(s.name), \"SKILL.md\"),\n\t\t\t\t\tcontent: emitMarkdown({ name: s.name, description: s.description }, s.body),\n\t\t\t\t});\n\t\t\t}\n\t\t\tfor (const c of draft.commands ?? []) {\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: path.join(\"commands\", `${slug(c.name)}.md`),\n\t\t\t\t\tcontent: emitMarkdown({ description: c.description }, c.body),\n\t\t\t\t});\n\t\t\t}\n\t\t\tfor (const a of draft.agents ?? []) {\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: path.join(\"agents\", `${slug(a.name)}.md`),\n\t\t\t\t\tcontent: emitMarkdown(\n\t\t\t\t\t\t{ name: a.name, description: a.description, tools: a.tools, model: a.model },\n\t\t\t\t\t\ta.body,\n\t\t\t\t\t),\n\t\t\t\t});\n\t\t\t}\n\t\t\tif (draft.hooks?.length) {\n\t\t\t\tfiles.push({\n\t\t\t\t\tpath: path.join(\"hooks\", \"hooks.json\"),\n\t\t\t\t\tcontent: emitJson({ hooks: authoredHooksToConfig(draft.hooks) }),\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn files;\n\t\t},\n\t};\n}\n"]}
|