@kolisachint/hoocode-agent 0.5.49 → 0.5.51

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.
Files changed (154) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/cli/args.d.ts.map +1 -1
  3. package/dist/cli/args.js +4 -6
  4. package/dist/cli/args.js.map +1 -1
  5. package/dist/core/agent-frontmatter.d.ts +5 -0
  6. package/dist/core/agent-frontmatter.d.ts.map +1 -1
  7. package/dist/core/agent-frontmatter.js +10 -7
  8. package/dist/core/agent-frontmatter.js.map +1 -1
  9. package/dist/core/agent-session.d.ts.map +1 -1
  10. package/dist/core/agent-session.js +1 -1
  11. package/dist/core/agent-session.js.map +1 -1
  12. package/dist/core/export-html/index.d.ts.map +1 -1
  13. package/dist/core/export-html/index.js +1 -1
  14. package/dist/core/export-html/index.js.map +1 -1
  15. package/dist/core/export-html/template.js +2 -22
  16. package/dist/core/extensions/index.d.ts +2 -2
  17. package/dist/core/extensions/index.d.ts.map +1 -1
  18. package/dist/core/extensions/index.js +1 -1
  19. package/dist/core/extensions/index.js.map +1 -1
  20. package/dist/core/extensions/plugins/authoring.d.ts.map +1 -1
  21. package/dist/core/extensions/plugins/authoring.js +1 -1
  22. package/dist/core/extensions/plugins/authoring.js.map +1 -1
  23. package/dist/core/extensions/plugins/formats/shared.d.ts +1 -1
  24. package/dist/core/extensions/plugins/formats/shared.d.ts.map +1 -1
  25. package/dist/core/extensions/plugins/formats/shared.js +1 -1
  26. package/dist/core/extensions/plugins/formats/shared.js.map +1 -1
  27. package/dist/core/extensions/plugins/formats/types.d.ts +1 -1
  28. package/dist/core/extensions/plugins/formats/types.d.ts.map +1 -1
  29. package/dist/core/extensions/plugins/formats/types.js.map +1 -1
  30. package/dist/core/extensions/types.d.ts +3 -33
  31. package/dist/core/extensions/types.d.ts.map +1 -1
  32. package/dist/core/extensions/types.js +0 -9
  33. package/dist/core/extensions/types.js.map +1 -1
  34. package/dist/core/external-tools.d.ts +3 -3
  35. package/dist/core/external-tools.d.ts.map +1 -1
  36. package/dist/core/external-tools.js +5 -5
  37. package/dist/core/external-tools.js.map +1 -1
  38. package/dist/core/light.d.ts +2 -2
  39. package/dist/core/light.d.ts.map +1 -1
  40. package/dist/core/light.js +2 -2
  41. package/dist/core/light.js.map +1 -1
  42. package/dist/core/sdk.d.ts +2 -2
  43. package/dist/core/sdk.d.ts.map +1 -1
  44. package/dist/core/sdk.js +4 -4
  45. package/dist/core/sdk.js.map +1 -1
  46. package/dist/core/self-docs.d.ts +1 -1
  47. package/dist/core/self-docs.d.ts.map +1 -1
  48. package/dist/core/self-docs.js +1 -1
  49. package/dist/core/self-docs.js.map +1 -1
  50. package/dist/core/settings-types.d.ts +1 -1
  51. package/dist/core/settings-types.d.ts.map +1 -1
  52. package/dist/core/settings-types.js.map +1 -1
  53. package/dist/core/system-prompt.d.ts +1 -1
  54. package/dist/core/system-prompt.d.ts.map +1 -1
  55. package/dist/core/system-prompt.js +9 -26
  56. package/dist/core/system-prompt.js.map +1 -1
  57. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  58. package/dist/core/tools/edit-diff.js +326 -101
  59. package/dist/core/tools/edit-diff.js.map +1 -1
  60. package/dist/core/tools/fd-utils.d.ts +3 -17
  61. package/dist/core/tools/fd-utils.d.ts.map +1 -1
  62. package/dist/core/tools/fd-utils.js +3 -38
  63. package/dist/core/tools/fd-utils.js.map +1 -1
  64. package/dist/core/tools/index.d.ts +0 -12
  65. package/dist/core/tools/index.d.ts.map +1 -1
  66. package/dist/core/tools/index.js +2 -11
  67. package/dist/core/tools/index.js.map +1 -1
  68. package/dist/core/tools/native-search.d.ts +0 -15
  69. package/dist/core/tools/native-search.d.ts.map +1 -1
  70. package/dist/core/tools/native-search.js +0 -87
  71. package/dist/core/tools/native-search.js.map +1 -1
  72. package/dist/core/tools/propose-plugin.d.ts.map +1 -1
  73. package/dist/core/tools/propose-plugin.js +1 -1
  74. package/dist/core/tools/propose-plugin.js.map +1 -1
  75. package/dist/core/tools/read-dedup.d.ts +14 -1
  76. package/dist/core/tools/read-dedup.d.ts.map +1 -1
  77. package/dist/core/tools/read-dedup.js +53 -1
  78. package/dist/core/tools/read-dedup.js.map +1 -1
  79. package/dist/core/tools/read.d.ts.map +1 -1
  80. package/dist/core/tools/read.js +17 -5
  81. package/dist/core/tools/read.js.map +1 -1
  82. package/dist/core/tools/search.d.ts +3 -2
  83. package/dist/core/tools/search.d.ts.map +1 -1
  84. package/dist/core/tools/search.js +7 -6
  85. package/dist/core/tools/search.js.map +1 -1
  86. package/dist/core/tools/subagent.d.ts.map +1 -1
  87. package/dist/core/tools/subagent.js +1 -1
  88. package/dist/core/tools/subagent.js.map +1 -1
  89. package/dist/core/warm-subagent-pool.d.ts.map +1 -1
  90. package/dist/core/warm-subagent-pool.js +1 -1
  91. package/dist/core/warm-subagent-pool.js.map +1 -1
  92. package/dist/extensions/core/permission-gate.d.ts.map +1 -1
  93. package/dist/extensions/core/permission-gate.js +23 -5
  94. package/dist/extensions/core/permission-gate.js.map +1 -1
  95. package/dist/index.d.ts +4 -4
  96. package/dist/index.d.ts.map +1 -1
  97. package/dist/index.js +3 -3
  98. package/dist/index.js.map +1 -1
  99. package/dist/init-templates.generated.d.ts.map +1 -1
  100. package/dist/init-templates.generated.js +10 -10
  101. package/dist/init-templates.generated.js.map +1 -1
  102. package/dist/modes/interactive/components/tool-chain-summary.d.ts.map +1 -1
  103. package/dist/modes/interactive/components/tool-chain-summary.js +1 -1
  104. package/dist/modes/interactive/components/tool-chain-summary.js.map +1 -1
  105. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  106. package/dist/modes/interactive/components/tree-selector.js +4 -13
  107. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  108. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  109. package/dist/modes/interactive/interactive-mode.js +2 -2
  110. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  111. package/dist/utils/tools-manager.d.ts.map +1 -1
  112. package/dist/utils/tools-manager.js +1 -1
  113. package/dist/utils/tools-manager.js.map +1 -1
  114. package/docs/extensions.md +2 -4
  115. package/docs/modes.md +1 -1
  116. package/docs/quickstart.md +1 -1
  117. package/docs/sdk.md +8 -10
  118. package/docs/settings.md +2 -2
  119. package/docs/usage.md +3 -3
  120. package/examples/agents/fork-reviewer.md +1 -1
  121. package/examples/agents/orchestrator.md +1 -1
  122. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  123. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  124. package/examples/extensions/minimal-mode.ts +1 -188
  125. package/examples/extensions/plan-mode/README.md +1 -1
  126. package/examples/extensions/plan-mode/index.ts +2 -2
  127. package/examples/extensions/preset.ts +2 -2
  128. package/examples/extensions/sandbox/package.json +1 -1
  129. package/examples/extensions/truncated-tool.ts +1 -1
  130. package/examples/extensions/with-deps/package.json +1 -1
  131. package/examples/sdk/05-tools.ts +3 -3
  132. package/package.json +4 -4
  133. package/templates/agents/code-review.md +1 -1
  134. package/templates/agents/explore.md +2 -2
  135. package/templates/agents/general-purpose.md +1 -1
  136. package/templates/agents/plan.md +2 -2
  137. package/templates/agents/security-review.md +1 -1
  138. package/templates/modes/ask/system.md +1 -1
  139. package/templates/modes/debug/system.md +1 -1
  140. package/templates/skills/artifact-design/SKILL.md +1 -1
  141. package/templates/skills/canvas-design/SKILL.md +1 -1
  142. package/templates/skills/plugin-authoring/SKILL.md +1 -1
  143. package/dist/core/tools/find.d.ts +0 -40
  144. package/dist/core/tools/find.d.ts.map +0 -1
  145. package/dist/core/tools/find.js +0 -364
  146. package/dist/core/tools/find.js.map +0 -1
  147. package/dist/core/tools/grep.d.ts +0 -37
  148. package/dist/core/tools/grep.d.ts.map +0 -1
  149. package/dist/core/tools/grep.js +0 -414
  150. package/dist/core/tools/grep.js.map +0 -1
  151. package/dist/core/tools/ls.d.ts +0 -49
  152. package/dist/core/tools/ls.d.ts.map +0 -1
  153. package/dist/core/tools/ls.js +0 -211
  154. package/dist/core/tools/ls.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"authoring.js","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/authoring.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plugin authoring engine (spec §3) — shared by the two ProposePlugin tools.\n *\n * Completes the discover → acquire → author spectrum: when no marketplace plugin\n * fits a gap, the model can scaffold one. Authoring is gated on the *content /\n * capability-grant* trust axis (what the plugin can do), not the *source* axis\n * used for install. This module carries the risk classification, the\n * privilege-amplification guardrail, and the file writer; the tools own the two\n * escalating-risk *paths* (autonomous scaffold vs. confirm-then-activate).\n *\n * Everything is written through the format registry's {@link emitForPlatforms},\n * so an authored plugin lands in the requested vendor layouts (Claude Code and\n * GitHub Copilot by default) and round-trips back through {@link parsePluginDir}.\n */\n\nimport { cpSync, existsSync, mkdirSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\nimport { CLAUDE_TOOL_ALIASES } from \"../../agent-frontmatter.js\";\nimport { PLUGIN_SYSTEM_TOOL_NAMES } from \"../../tools/plugin-tool-names.js\";\nimport { emitForPlatforms } from \"./formats/index.js\";\nimport { isPluginPlatform, resolvePluginPlatforms } from \"./formats/platform-targets.js\";\nimport { slug } from \"./formats/shared.js\";\nimport type { AuthoredHook, AuthoredMcpServer, MarketplacePlatform, PluginDraft } from \"./formats/types.js\";\nimport { candidatePluginDirs, discardDraftDir, makeDraftDir, productionPluginDir } from \"./locations.js\";\nimport { type NormalizedPlugin, type PluginHooksConfig, parsePluginDir } from \"./manifest.js\";\n\n// Re-exported so existing importers keep one vocabulary; the resolution chain\n// (explicit → session --platform → default) lives in platform-targets.\nexport { resolvePluginPlatforms } from \"./formats/platform-targets.js\";\n\n/**\n * Layout for an *edit* of an existing plugin. Unlike creation, this never\n * re-resolves against the session's `--platform`: a merge or a removal must keep\n * the plugin in whatever layout it already has on disk, or it would move the\n * manifest out from under a plugin the user (or an older hoocode) already\n * published. Plugins authored before plugin production became platform-specific\n * carry the native `agents` layout, and those must keep working.\n */\nfunction existingLayout(existing: NormalizedPlugin, explicit?: readonly MarketplacePlatform[]): MarketplacePlatform[] {\n\tif (explicit && explicit.length > 0) return [...explicit];\n\tif (existing.supportPlatform.length > 0) return [...existing.supportPlatform];\n\treturn resolvePluginPlatforms();\n}\n\n/** hoocode tool names that only read (no mutation, no exec). Grants limited to these are low-risk. */\nconst READONLY_TOOLS = new Set([\"read\", \"grep\", \"find\", \"ls\", \"webfetch\", \"websearch\"]);\n\nexport interface AllowlistClassification {\n\t/** read-only grants are as safe as a skill; mutating/exec/network/`*` grants need confirmation. */\n\trisk: \"read-only\" | \"mutating\";\n\t/** Human-readable explanation of what drove the classification. */\n\treason: string;\n\t/** Any plugin-system (capability-acquisition) tools found — always forbidden in an authored allowlist. */\n\tpluginTools: string[];\n\t/** The raw allowlist tokens. */\n\ttokens: string[];\n}\n\n/**\n * Classify an authored subagent `tools:` allowlist as read-only vs. mutating,\n * reusing the same Claude-alias vocabulary as the agent-frontmatter normalizer\n * (spec §3 \"compute the risk, don't guess it\"). Anything unrecognized — an MCP\n * tool, a bare `*`, an unknown name — is treated as mutating (fail-safe).\n */\nexport function classifyAllowlist(tools: string | undefined): AllowlistClassification {\n\tconst tokens = (tools ?? \"\")\n\t\t.split(/[,\\s]+/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\tconst pluginTools = tokens.filter((t) => PLUGIN_SYSTEM_TOOL_NAMES.some((n) => n.toLowerCase() === t.toLowerCase()));\n\n\tif (tokens.length === 0) {\n\t\treturn { risk: \"read-only\", reason: \"no tools granted\", pluginTools, tokens };\n\t}\n\n\tconst reasons: string[] = [];\n\tlet mutating = false;\n\tfor (const t of tokens) {\n\t\tconst low = t.toLowerCase();\n\t\tif (t === \"*\" || low === \"all\") {\n\t\t\tmutating = true;\n\t\t\treasons.push(\"grants all tools (*)\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (pluginTools.some((p) => p.toLowerCase() === low)) continue; // reported separately as a guardrail violation\n\t\tconst mapped = CLAUDE_TOOL_ALIASES[low];\n\t\tif (!mapped) {\n\t\t\tmutating = true;\n\t\t\treasons.push(`grants \"${t}\" (unrecognized or MCP tool — treated as mutating)`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!READONLY_TOOLS.has(mapped)) {\n\t\t\tmutating = true;\n\t\t\treasons.push(`grants \"${mapped}\" (mutating/exec)`);\n\t\t}\n\t}\n\n\treturn {\n\t\trisk: mutating ? \"mutating\" : \"read-only\",\n\t\treason: reasons.join(\"; \") || \"read-only tools only\",\n\t\tpluginTools,\n\t\ttokens,\n\t};\n}\n\nexport interface WriteResult {\n\t/** Where the plugin ended up: a production home, or the draft dir when not promoted. */\n\tdest: string;\n\t/** False when the caller asked to stop at the draft (gates still to run). */\n\tpromoted: boolean;\n\t/** Platforms the draft was emitted for. */\n\ttargets: MarketplacePlatform[];\n\t/** Written file paths, relative to the plugin root. */\n\tfiles: string[];\n\t/** Re-parsed plugin (confirms the scaffold round-trips). */\n\tplugin: NormalizedPlugin | null;\n}\n\n/**\n * Provenance marker written at the root of every authored plugin. A production\n * home can also hold artifacts hoocode did not write — `~/.claude/skills/` is a\n * directory Claude Code and the user both write into — so this marker is what\n * separates \"ours to re-emit or delete\" from \"someone else's\". UpdatePlugin\n * (which rewrites manifests and hook/MCP files) is gated on it. Existence is the\n * signal; the content is informational.\n */\nconst AUTHORED_MARKER_FILE = \".authored.json\";\n\n/** Locate an existing plugin by id across every home, or undefined. */\nexport function findPluginDir(cwd: string, id: string): string | undefined {\n\treturn candidatePluginDirs(cwd, id).find((dir) => existsSync(dir));\n}\n\n/** Whether the plugin at `id` was authored here (carries the provenance marker), vs. installed or hand-written. */\nexport function isAuthoredPlugin(cwd: string, id: string): boolean {\n\tconst dir = findPluginDir(cwd, id);\n\treturn !!dir && existsSync(path.join(dir, AUTHORED_MARKER_FILE));\n}\n\n/**\n * Render `draft` into the requested platform layouts and write it out.\n *\n * Two modes, and the distinction matters:\n *\n * - **Creation** (default): emit into an ephemeral draft dir, then promote into\n * the target platform's production home, replacing whatever was there. A\n * production home is live — `~/.claude/skills/<id>/` is loaded by Claude Code\n * on its next session — so writing there directly would mean a plugin that\n * failed validation, or whose confirmation was declined, is already running.\n * Pass `promote: false` to stop at the draft and promote later with\n * {@link promoteDraft}.\n * - **In-place edit** (`dest` given): write the emitted files over an existing\n * plugin directory, wherever it already lives. An edit must never relocate the\n * plugin — a merge or a removal on a plugin sitting in the consumption home or\n * the legacy project home would otherwise silently move it into a production\n * home. Files not named by the emit are left alone, which is what makes the\n * directory-scanned merge semantics work.\n */\nexport function writePluginDraft(\n\tdraft: PluginDraft,\n\tplatforms?: MarketplacePlatform[],\n\toptions?: { promote?: boolean; dest?: string },\n): WriteResult {\n\t// Creation picks a platform; `agents` is refused here (see resolvePluginPlatforms).\n\tconst targets = resolvePluginPlatforms(platforms ?? draft.supportPlatform?.filter(isPluginPlatform));\n\tconst files = emitForPlatforms({ ...draft, supportPlatform: targets }, targets);\n\n\t// Formats share the capability tree (only marker manifests differ), so\n\t// dedupe by path — later formats overwrite with identical content.\n\tconst byPath = new Map(files.map((f) => [f.path, f]));\n\tconst writeInto = (root: string) => {\n\t\tfor (const f of byPath.values()) {\n\t\t\tconst abs = path.join(root, f.path);\n\t\t\tmkdirSync(path.dirname(abs), { recursive: true });\n\t\t\twriteFileSync(abs, f.content);\n\t\t}\n\t\twriteFileSync(path.join(root, AUTHORED_MARKER_FILE), `${JSON.stringify({ authored: true }, null, 2)}\\n`);\n\t};\n\tconst written = { files: [...byPath.keys(), AUTHORED_MARKER_FILE], targets };\n\n\tif (options?.dest) {\n\t\tmkdirSync(options.dest, { recursive: true });\n\t\twriteInto(options.dest);\n\t\treturn { dest: options.dest, promoted: true, ...written, plugin: parsePluginDir(options.dest) };\n\t}\n\n\tconst draftDir = makeDraftDir();\n\twriteInto(draftDir);\n\tif (options?.promote === false) {\n\t\treturn { dest: draftDir, promoted: false, ...written, plugin: parsePluginDir(draftDir) };\n\t}\n\tconst dest = promoteDraft(draftDir, draft.id, targets);\n\treturn { dest, promoted: true, ...written, plugin: parsePluginDir(dest) };\n}\n\n/**\n * Move a draft into the production home of its first target platform, replacing\n * whatever is there. The draft directory is consumed either way.\n *\n * A cross-device rename fails when temp and home sit on different filesystems,\n * so this falls back to copy-then-delete rather than assuming `rename` works.\n */\nexport function promoteDraft(draftDir: string, id: string, targets: readonly MarketplacePlatform[]): string {\n\tconst platform = targets.filter(isPluginPlatform)[0] ?? resolvePluginPlatforms()[0];\n\treturn promoteDraftTo(draftDir, productionPluginDir(platform, id));\n}\n\n/**\n * Replace `dest` with the contents of a draft. Used when the destination is\n * already known — an edit stays wherever the plugin lives, which may be the\n * consumption home or a legacy directory rather than a production home.\n */\nexport function promoteDraftTo(draftDir: string, dest: string): string {\n\trmSync(dest, { recursive: true, force: true });\n\tmkdirSync(path.dirname(dest), { recursive: true });\n\ttry {\n\t\trenameSync(draftDir, dest);\n\t} catch {\n\t\tcpSync(draftDir, dest, { recursive: true });\n\t\tdiscardDraftDir(draftDir);\n\t}\n\treturn dest;\n}\n\n/**\n * Whether authoring this id would clobber something **in the target platform's\n * production home**.\n *\n * Scoped to the target rather than every home on purpose: a `claude` `foo` and a\n * `github` `foo` are artifacts for two different ecosystems, not duplicates of\n * each other, and a marketplace-installed `foo` in the consumption home is a\n * third unrelated thing. Only a collision in the directory this write would\n * actually land in is a collision.\n */\nexport function pluginExists(id: string, platforms?: readonly MarketplacePlatform[]): boolean {\n\tconst target = resolvePluginPlatforms(platforms?.filter(isPluginPlatform))[0];\n\treturn existsSync(productionPluginDir(target, id));\n}\n\n/** Load an installed/authored plugin by id from whichever home holds it, or null. */\nexport function getPlugin(cwd: string, id: string): NormalizedPlugin | null {\n\tconst dir = findPluginDir(cwd, id);\n\treturn dir ? parsePluginDir(dir) : null;\n}\n\n/** Reverse of {@link authoredHooksToConfig}: flatten a parsed hook event-map back to authored hooks. */\nfunction hooksConfigToAuthored(config: PluginHooksConfig): AuthoredHook[] {\n\tconst out: AuthoredHook[] = [];\n\tfor (const [event, groups] of Object.entries(config)) {\n\t\tfor (const group of groups) {\n\t\t\tfor (const cmd of group.hooks) {\n\t\t\t\tif (typeof cmd.command !== \"string\" || !cmd.command) continue;\n\t\t\t\tout.push({\n\t\t\t\t\tevent,\n\t\t\t\t\t...(group.matcher ? { matcher: group.matcher } : {}),\n\t\t\t\t\tcommand: cmd.command,\n\t\t\t\t\t...(cmd.timeout ? { timeout: cmd.timeout } : {}),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\treturn out;\n}\n\n/**\n * Convert a parsed `mcpServers` record back to authored form. Throws on a\n * non-stdio (url/http-type) server rather than silently dropping it from the\n * re-emit — a merge must never quietly lose a capability (only reachable via a\n * hand-edited authored plugin; our own schema always writes `command` servers).\n */\nfunction mcpRecordToAuthored(record: Record<string, unknown>): AuthoredMcpServer[] {\n\tconst out: AuthoredMcpServer[] = [];\n\tfor (const [name, value] of Object.entries(record)) {\n\t\tif (!value || typeof value !== \"object\") continue;\n\t\tconst server = value as { command?: unknown; args?: unknown; env?: unknown };\n\t\tif (typeof server.command !== \"string\") {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot merge: MCP server \"${name}\" has no command (url/http-type servers don't round-trip through authoring). ` +\n\t\t\t\t\t\"Edit the plugin's .mcp.json directly instead.\",\n\t\t\t);\n\t\t}\n\t\tout.push({\n\t\t\tname,\n\t\t\tcommand: server.command,\n\t\t\t...(Array.isArray(server.args) ? { args: server.args.map(String) } : {}),\n\t\t\t...(server.env && typeof server.env === \"object\" ? { env: server.env as Record<string, string> } : {}),\n\t\t});\n\t}\n\treturn out;\n}\n\n/** Dedupe authored hooks by (event, matcher, command) so a re-supplied hook doesn't stack. */\nfunction dedupeHooks(hooks: AuthoredHook[]): AuthoredHook[] {\n\tconst seen = new Set<string>();\n\tconst out: AuthoredHook[] = [];\n\tfor (const h of hooks) {\n\t\tconst key = `${h.event}\u0000${h.matcher ?? \"\"}\u0000${h.command}`;\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tout.push(h);\n\t}\n\treturn out;\n}\n\n/**\n * Merge inline-authored `delta` capabilities into the existing local plugin `id`\n * and re-emit. Unlike a marketplace `UpdatePlugin`, nothing is fetched from a\n * remote source — the new content comes from the caller — so the supply-chain\n * \"benign v1 → hostile v2\" vector the spec guards against is structurally absent.\n *\n * Merge semantics:\n * - **Skills / commands / agents** are directory-scanned, so existing ones are\n * left on disk untouched; a delta entry with a matching name overwrites just\n * that file (an update), a new name is added.\n * - **Hooks** and **MCP servers** live in single files that a re-emit rewrites,\n * so they are re-emitted as the *union* of existing + delta (MCP keyed by\n * server name with delta winning; hooks deduped by event/matcher/command).\n * Hooks have no name, so there is deliberately no modify-in-place: a delta\n * hook with the same event/matcher but a different command is a NEW hook\n * added alongside the old one, never a replacement. (Keying replacement by\n * event+matcher would silently drop legitimate sibling hooks that share\n * them.) Changing a hook = {@link removeFromPlugin} the old one + merge the\n * new one.\n * - **Metadata** (version, description, author) takes the delta's value when\n * provided, else keeps the existing one.\n *\n * Platforms default to the plugin's existing `supportPlatform` so a merge never\n * silently adds or drops a vendor layout.\n */\nexport function mergePluginDraft(\n\tcwd: string,\n\tid: string,\n\tdelta: Partial<PluginDraft>,\n\tplatforms?: MarketplacePlatform[],\n): WriteResult {\n\tconst existing = getPlugin(cwd, id);\n\tif (!existing) {\n\t\tthrow new Error(`Cannot update plugin \"${id}\": it does not exist. Use ProposePlugin to create it first.`);\n\t}\n\t// Authored-only: merging re-emits manifests and hook/MCP files through our\n\t// writer, which only round-trips what PluginDraft can represent. Running that\n\t// over a marketplace install could silently drop fields it carries (capability\n\t// -dir overrides, url-type MCP servers, extra manifest keys).\n\tif (!isAuthoredPlugin(cwd, id)) {\n\t\tthrow new Error(\n\t\t\t`Cannot update plugin \"${id}\": it was not authored here (no ${AUTHORED_MARKER_FILE} marker). ` +\n\t\t\t\t\"Only locally authored plugins can be merged.\",\n\t\t);\n\t}\n\n\tconst existingHooks = existing.hooks ? hooksConfigToAuthored(existing.hooks) : [];\n\tconst mergedHooks = dedupeHooks([...existingHooks, ...(delta.hooks ?? [])]);\n\n\tconst mcpByName = new Map<string, AuthoredMcpServer>();\n\tfor (const s of existing.mcpServers ? mcpRecordToAuthored(existing.mcpServers) : []) mcpByName.set(s.name, s);\n\tfor (const s of delta.mcpServers ?? []) mcpByName.set(s.name, s);\n\n\tconst targets = existingLayout(existing, platforms);\n\tconst merged: PluginDraft = {\n\t\tid,\n\t\tversion: delta.version ?? existing.version,\n\t\tdescription: delta.description ?? existing.description,\n\t\tauthor: delta.author ?? existing.author,\n\t\tsupportPlatform: targets,\n\t\t// Keys we do not model survive the manifest rewrite.\n\t\tunknownFields: existing.unknownFields,\n\t\t// Directory-scanned capabilities: delta-only; existing files stay on disk.\n\t\tskills: delta.skills,\n\t\tcommands: delta.commands,\n\t\tagents: delta.agents,\n\t\t// Single-file capabilities: re-emit the union so a merge never drops them.\n\t\thooks: mergedHooks.length ? mergedHooks : undefined,\n\t\tmcpServers: mcpByName.size ? [...mcpByName.values()] : undefined,\n\t};\n\t// An edit stays where the plugin already lives; it never relocates it.\n\treturn writePluginDraft(merged, targets, { dest: findPluginDir(cwd, id) });\n}\n\n/** A hook to remove: `event` is required; `matcher`/`command` narrow the match when provided. */\ninterface HookRemovalSpec {\n\tevent: string;\n\tmatcher?: string;\n\tcommand?: string;\n}\n\n/** Named capabilities to remove from an authored plugin. */\nexport interface RemovalSpec {\n\tskills?: string[];\n\tcommands?: string[];\n\tsubagents?: string[];\n\tmcpServers?: string[];\n\thooks?: HookRemovalSpec[];\n}\n\nexport interface RemoveResult {\n\tdest: string;\n\t/** Human-readable descriptions of what was removed. */\n\tremoved: string[];\n\t/** Requested capabilities that were not found (nothing was removed for these). */\n\tmissing: string[];\n}\n\nfunction describeHookSpec(h: HookRemovalSpec): string {\n\treturn `hook [${h.event}${h.matcher !== undefined ? ` matcher=${h.matcher}` : \"\"}${h.command !== undefined ? ` command=${h.command}` : \"\"}]`;\n}\n\n/**\n * Remove named capabilities from the authored plugin `id`. The inverse of the\n * additive merge, and — like {@link mergePluginDraft} — authored-only.\n *\n * Removal is the low-risk direction (deleting capabilities cannot execute\n * code), which is why callers may run it without a confirmation gate.\n *\n * - **Skills / commands / subagents** are directory-scanned, so removal is a\n * surgical file delete at our emit conventions; no re-emit needed.\n * - **Hooks** (matched by event, narrowed by matcher/command when given) and\n * **MCP servers** (by name) live in single files, so the remaining set is\n * re-emitted — and when a set empties, its file is DELETED, because the\n * parser falls back to `hooks/hooks.json` / `.mcp.json` on disk and a stale\n * file would resurrect the removed capability on the next parse.\n */\nexport function removeFromPlugin(cwd: string, id: string, spec: RemovalSpec): RemoveResult {\n\tconst existing = getPlugin(cwd, id);\n\tif (!existing) {\n\t\tthrow new Error(`Cannot remove from plugin \"${id}\": it does not exist.`);\n\t}\n\tif (!isAuthoredPlugin(cwd, id)) {\n\t\tthrow new Error(\n\t\t\t`Cannot remove from plugin \"${id}\": it was not authored here (no ${AUTHORED_MARKER_FILE} marker). ` +\n\t\t\t\t\"Only locally authored plugins can be edited.\",\n\t\t);\n\t}\n\tconst dest = findPluginDir(cwd, id);\n\tif (!dest) throw new Error(`Cannot remove from plugin \"${id}\": it is not on disk.`);\n\tconst removed: string[] = [];\n\tconst missing: string[] = [];\n\n\t// Directory-scanned capabilities: surgical deletes at our emit conventions.\n\tconst fileTargets: Array<[kind: string, name: string, relPath: string]> = [\n\t\t...(spec.skills ?? []).map((n): [string, string, string] => [\"skill\", n, path.join(\"skills\", slug(n))]),\n\t\t...(spec.commands ?? []).map((n): [string, string, string] => [\n\t\t\t\"command\",\n\t\t\tn,\n\t\t\tpath.join(\"commands\", `${slug(n)}.md`),\n\t\t]),\n\t\t...(spec.subagents ?? []).map((n): [string, string, string] => [\n\t\t\t\"subagent\",\n\t\t\tn,\n\t\t\tpath.join(\"agents\", `${slug(n)}.md`),\n\t\t]),\n\t];\n\tfor (const [kind, name, rel] of fileTargets) {\n\t\tconst abs = path.join(dest, rel);\n\t\tif (existsSync(abs)) {\n\t\t\trmSync(abs, { recursive: true, force: true });\n\t\t\tremoved.push(`${kind} \"${name}\"`);\n\t\t} else {\n\t\t\tmissing.push(`${kind} \"${name}\"`);\n\t\t}\n\t}\n\n\t// Single-file capabilities: filter the reconstructed sets, then re-emit.\n\tlet singleFileChanged = false;\n\tlet remainingHooks = existing.hooks ? hooksConfigToAuthored(existing.hooks) : [];\n\tfor (const h of spec.hooks ?? []) {\n\t\tconst before = remainingHooks.length;\n\t\tremainingHooks = remainingHooks.filter(\n\t\t\t(x) =>\n\t\t\t\t!(\n\t\t\t\t\tx.event === h.event &&\n\t\t\t\t\t(h.matcher === undefined || (x.matcher ?? \"\") === h.matcher) &&\n\t\t\t\t\t(h.command === undefined || x.command === h.command)\n\t\t\t\t),\n\t\t);\n\t\tconst n = before - remainingHooks.length;\n\t\tif (n > 0) {\n\t\t\tremoved.push(`${n} ${describeHookSpec(h)}`);\n\t\t\tsingleFileChanged = true;\n\t\t} else {\n\t\t\tmissing.push(describeHookSpec(h));\n\t\t}\n\t}\n\tlet remainingMcp = existing.mcpServers ? mcpRecordToAuthored(existing.mcpServers) : [];\n\tfor (const name of spec.mcpServers ?? []) {\n\t\tconst before = remainingMcp.length;\n\t\tremainingMcp = remainingMcp.filter((s) => s.name !== name);\n\t\tif (remainingMcp.length < before) {\n\t\t\tremoved.push(`mcp server \"${name}\"`);\n\t\t\tsingleFileChanged = true;\n\t\t} else {\n\t\t\tmissing.push(`mcp server \"${name}\"`);\n\t\t}\n\t}\n\n\tif (singleFileChanged) {\n\t\tconst targets = existingLayout(existing);\n\t\twritePluginDraft(\n\t\t\t{\n\t\t\t\tid,\n\t\t\t\tversion: existing.version,\n\t\t\t\tdescription: existing.description,\n\t\t\t\tauthor: existing.author,\n\t\t\t\tsupportPlatform: targets,\n\t\t\t\tunknownFields: existing.unknownFields,\n\t\t\t\thooks: remainingHooks.length ? remainingHooks : undefined,\n\t\t\t\tmcpServers: remainingMcp.length ? remainingMcp : undefined,\n\t\t\t},\n\t\t\ttargets,\n\t\t\t{ dest },\n\t\t);\n\t\t// Emit skips empty sets, so a stale file from the previous emit survives\n\t\t// and the parser's on-disk fallback would resurrect it — delete explicitly.\n\t\tif (remainingHooks.length === 0) rmSync(path.join(dest, \"hooks\", \"hooks.json\"), { force: true });\n\t\tif (remainingMcp.length === 0) rmSync(path.join(dest, \".mcp.json\"), { force: true });\n\t}\n\n\treturn { dest, removed, missing };\n}\n"]}
1
+ {"version":3,"file":"authoring.js","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/authoring.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plugin authoring engine (spec §3) — shared by the two ProposePlugin tools.\n *\n * Completes the discover → acquire → author spectrum: when no marketplace plugin\n * fits a gap, the model can scaffold one. Authoring is gated on the *content /\n * capability-grant* trust axis (what the plugin can do), not the *source* axis\n * used for install. This module carries the risk classification, the\n * privilege-amplification guardrail, and the file writer; the tools own the two\n * escalating-risk *paths* (autonomous scaffold vs. confirm-then-activate).\n *\n * Everything is written through the format registry's {@link emitForPlatforms},\n * so an authored plugin lands in the requested vendor layouts (Claude Code and\n * GitHub Copilot by default) and round-trips back through {@link parsePluginDir}.\n */\n\nimport { cpSync, existsSync, mkdirSync, renameSync, rmSync, writeFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\nimport { CLAUDE_TOOL_ALIASES } from \"../../agent-frontmatter.js\";\nimport { PLUGIN_SYSTEM_TOOL_NAMES } from \"../../tools/plugin-tool-names.js\";\nimport { emitForPlatforms } from \"./formats/index.js\";\nimport { isPluginPlatform, resolvePluginPlatforms } from \"./formats/platform-targets.js\";\nimport { slug } from \"./formats/shared.js\";\nimport type { AuthoredHook, AuthoredMcpServer, MarketplacePlatform, PluginDraft } from \"./formats/types.js\";\nimport { candidatePluginDirs, discardDraftDir, makeDraftDir, productionPluginDir } from \"./locations.js\";\nimport { type NormalizedPlugin, type PluginHooksConfig, parsePluginDir } from \"./manifest.js\";\n\n// Re-exported so existing importers keep one vocabulary; the resolution chain\n// (explicit → session --platform → default) lives in platform-targets.\nexport { resolvePluginPlatforms } from \"./formats/platform-targets.js\";\n\n/**\n * Layout for an *edit* of an existing plugin. Unlike creation, this never\n * re-resolves against the session's `--platform`: a merge or a removal must keep\n * the plugin in whatever layout it already has on disk, or it would move the\n * manifest out from under a plugin the user (or an older hoocode) already\n * published. Plugins authored before plugin production became platform-specific\n * carry the native `agents` layout, and those must keep working.\n */\nfunction existingLayout(existing: NormalizedPlugin, explicit?: readonly MarketplacePlatform[]): MarketplacePlatform[] {\n\tif (explicit && explicit.length > 0) return [...explicit];\n\tif (existing.supportPlatform.length > 0) return [...existing.supportPlatform];\n\treturn resolvePluginPlatforms();\n}\n\n/** hoocode tool names that only read (no mutation, no exec). Grants limited to these are low-risk. */\nconst READONLY_TOOLS = new Set([\"read\", \"search\", \"webfetch\", \"websearch\"]);\n\nexport interface AllowlistClassification {\n\t/** read-only grants are as safe as a skill; mutating/exec/network/`*` grants need confirmation. */\n\trisk: \"read-only\" | \"mutating\";\n\t/** Human-readable explanation of what drove the classification. */\n\treason: string;\n\t/** Any plugin-system (capability-acquisition) tools found — always forbidden in an authored allowlist. */\n\tpluginTools: string[];\n\t/** The raw allowlist tokens. */\n\ttokens: string[];\n}\n\n/**\n * Classify an authored subagent `tools:` allowlist as read-only vs. mutating,\n * reusing the same Claude-alias vocabulary as the agent-frontmatter normalizer\n * (spec §3 \"compute the risk, don't guess it\"). Anything unrecognized — an MCP\n * tool, a bare `*`, an unknown name — is treated as mutating (fail-safe).\n */\nexport function classifyAllowlist(tools: string | undefined): AllowlistClassification {\n\tconst tokens = (tools ?? \"\")\n\t\t.split(/[,\\s]+/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\tconst pluginTools = tokens.filter((t) => PLUGIN_SYSTEM_TOOL_NAMES.some((n) => n.toLowerCase() === t.toLowerCase()));\n\n\tif (tokens.length === 0) {\n\t\treturn { risk: \"read-only\", reason: \"no tools granted\", pluginTools, tokens };\n\t}\n\n\tconst reasons: string[] = [];\n\tlet mutating = false;\n\tfor (const t of tokens) {\n\t\tconst low = t.toLowerCase();\n\t\tif (t === \"*\" || low === \"all\") {\n\t\t\tmutating = true;\n\t\t\treasons.push(\"grants all tools (*)\");\n\t\t\tcontinue;\n\t\t}\n\t\tif (pluginTools.some((p) => p.toLowerCase() === low)) continue; // reported separately as a guardrail violation\n\t\tconst mapped = CLAUDE_TOOL_ALIASES[low];\n\t\tif (!mapped) {\n\t\t\tmutating = true;\n\t\t\treasons.push(`grants \"${t}\" (unrecognized or MCP tool — treated as mutating)`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!READONLY_TOOLS.has(mapped)) {\n\t\t\tmutating = true;\n\t\t\treasons.push(`grants \"${mapped}\" (mutating/exec)`);\n\t\t}\n\t}\n\n\treturn {\n\t\trisk: mutating ? \"mutating\" : \"read-only\",\n\t\treason: reasons.join(\"; \") || \"read-only tools only\",\n\t\tpluginTools,\n\t\ttokens,\n\t};\n}\n\nexport interface WriteResult {\n\t/** Where the plugin ended up: a production home, or the draft dir when not promoted. */\n\tdest: string;\n\t/** False when the caller asked to stop at the draft (gates still to run). */\n\tpromoted: boolean;\n\t/** Platforms the draft was emitted for. */\n\ttargets: MarketplacePlatform[];\n\t/** Written file paths, relative to the plugin root. */\n\tfiles: string[];\n\t/** Re-parsed plugin (confirms the scaffold round-trips). */\n\tplugin: NormalizedPlugin | null;\n}\n\n/**\n * Provenance marker written at the root of every authored plugin. A production\n * home can also hold artifacts hoocode did not write — `~/.claude/skills/` is a\n * directory Claude Code and the user both write into — so this marker is what\n * separates \"ours to re-emit or delete\" from \"someone else's\". UpdatePlugin\n * (which rewrites manifests and hook/MCP files) is gated on it. Existence is the\n * signal; the content is informational.\n */\nconst AUTHORED_MARKER_FILE = \".authored.json\";\n\n/** Locate an existing plugin by id across every home, or undefined. */\nexport function findPluginDir(cwd: string, id: string): string | undefined {\n\treturn candidatePluginDirs(cwd, id).find((dir) => existsSync(dir));\n}\n\n/** Whether the plugin at `id` was authored here (carries the provenance marker), vs. installed or hand-written. */\nexport function isAuthoredPlugin(cwd: string, id: string): boolean {\n\tconst dir = findPluginDir(cwd, id);\n\treturn !!dir && existsSync(path.join(dir, AUTHORED_MARKER_FILE));\n}\n\n/**\n * Render `draft` into the requested platform layouts and write it out.\n *\n * Two modes, and the distinction matters:\n *\n * - **Creation** (default): emit into an ephemeral draft dir, then promote into\n * the target platform's production home, replacing whatever was there. A\n * production home is live — `~/.claude/skills/<id>/` is loaded by Claude Code\n * on its next session — so writing there directly would mean a plugin that\n * failed validation, or whose confirmation was declined, is already running.\n * Pass `promote: false` to stop at the draft and promote later with\n * {@link promoteDraft}.\n * - **In-place edit** (`dest` given): write the emitted files over an existing\n * plugin directory, wherever it already lives. An edit must never relocate the\n * plugin — a merge or a removal on a plugin sitting in the consumption home or\n * the legacy project home would otherwise silently move it into a production\n * home. Files not named by the emit are left alone, which is what makes the\n * directory-scanned merge semantics work.\n */\nexport function writePluginDraft(\n\tdraft: PluginDraft,\n\tplatforms?: MarketplacePlatform[],\n\toptions?: { promote?: boolean; dest?: string },\n): WriteResult {\n\t// Creation picks a platform; `agents` is refused here (see resolvePluginPlatforms).\n\tconst targets = resolvePluginPlatforms(platforms ?? draft.supportPlatform?.filter(isPluginPlatform));\n\tconst files = emitForPlatforms({ ...draft, supportPlatform: targets }, targets);\n\n\t// Formats share the capability tree (only marker manifests differ), so\n\t// dedupe by path — later formats overwrite with identical content.\n\tconst byPath = new Map(files.map((f) => [f.path, f]));\n\tconst writeInto = (root: string) => {\n\t\tfor (const f of byPath.values()) {\n\t\t\tconst abs = path.join(root, f.path);\n\t\t\tmkdirSync(path.dirname(abs), { recursive: true });\n\t\t\twriteFileSync(abs, f.content);\n\t\t}\n\t\twriteFileSync(path.join(root, AUTHORED_MARKER_FILE), `${JSON.stringify({ authored: true }, null, 2)}\\n`);\n\t};\n\tconst written = { files: [...byPath.keys(), AUTHORED_MARKER_FILE], targets };\n\n\tif (options?.dest) {\n\t\tmkdirSync(options.dest, { recursive: true });\n\t\twriteInto(options.dest);\n\t\treturn { dest: options.dest, promoted: true, ...written, plugin: parsePluginDir(options.dest) };\n\t}\n\n\tconst draftDir = makeDraftDir();\n\twriteInto(draftDir);\n\tif (options?.promote === false) {\n\t\treturn { dest: draftDir, promoted: false, ...written, plugin: parsePluginDir(draftDir) };\n\t}\n\tconst dest = promoteDraft(draftDir, draft.id, targets);\n\treturn { dest, promoted: true, ...written, plugin: parsePluginDir(dest) };\n}\n\n/**\n * Move a draft into the production home of its first target platform, replacing\n * whatever is there. The draft directory is consumed either way.\n *\n * A cross-device rename fails when temp and home sit on different filesystems,\n * so this falls back to copy-then-delete rather than assuming `rename` works.\n */\nexport function promoteDraft(draftDir: string, id: string, targets: readonly MarketplacePlatform[]): string {\n\tconst platform = targets.filter(isPluginPlatform)[0] ?? resolvePluginPlatforms()[0];\n\treturn promoteDraftTo(draftDir, productionPluginDir(platform, id));\n}\n\n/**\n * Replace `dest` with the contents of a draft. Used when the destination is\n * already known — an edit stays wherever the plugin lives, which may be the\n * consumption home or a legacy directory rather than a production home.\n */\nexport function promoteDraftTo(draftDir: string, dest: string): string {\n\trmSync(dest, { recursive: true, force: true });\n\tmkdirSync(path.dirname(dest), { recursive: true });\n\ttry {\n\t\trenameSync(draftDir, dest);\n\t} catch {\n\t\tcpSync(draftDir, dest, { recursive: true });\n\t\tdiscardDraftDir(draftDir);\n\t}\n\treturn dest;\n}\n\n/**\n * Whether authoring this id would clobber something **in the target platform's\n * production home**.\n *\n * Scoped to the target rather than every home on purpose: a `claude` `foo` and a\n * `github` `foo` are artifacts for two different ecosystems, not duplicates of\n * each other, and a marketplace-installed `foo` in the consumption home is a\n * third unrelated thing. Only a collision in the directory this write would\n * actually land in is a collision.\n */\nexport function pluginExists(id: string, platforms?: readonly MarketplacePlatform[]): boolean {\n\tconst target = resolvePluginPlatforms(platforms?.filter(isPluginPlatform))[0];\n\treturn existsSync(productionPluginDir(target, id));\n}\n\n/** Load an installed/authored plugin by id from whichever home holds it, or null. */\nexport function getPlugin(cwd: string, id: string): NormalizedPlugin | null {\n\tconst dir = findPluginDir(cwd, id);\n\treturn dir ? parsePluginDir(dir) : null;\n}\n\n/** Reverse of {@link authoredHooksToConfig}: flatten a parsed hook event-map back to authored hooks. */\nfunction hooksConfigToAuthored(config: PluginHooksConfig): AuthoredHook[] {\n\tconst out: AuthoredHook[] = [];\n\tfor (const [event, groups] of Object.entries(config)) {\n\t\tfor (const group of groups) {\n\t\t\tfor (const cmd of group.hooks) {\n\t\t\t\tif (typeof cmd.command !== \"string\" || !cmd.command) continue;\n\t\t\t\tout.push({\n\t\t\t\t\tevent,\n\t\t\t\t\t...(group.matcher ? { matcher: group.matcher } : {}),\n\t\t\t\t\tcommand: cmd.command,\n\t\t\t\t\t...(cmd.timeout ? { timeout: cmd.timeout } : {}),\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n\treturn out;\n}\n\n/**\n * Convert a parsed `mcpServers` record back to authored form. Throws on a\n * non-stdio (url/http-type) server rather than silently dropping it from the\n * re-emit — a merge must never quietly lose a capability (only reachable via a\n * hand-edited authored plugin; our own schema always writes `command` servers).\n */\nfunction mcpRecordToAuthored(record: Record<string, unknown>): AuthoredMcpServer[] {\n\tconst out: AuthoredMcpServer[] = [];\n\tfor (const [name, value] of Object.entries(record)) {\n\t\tif (!value || typeof value !== \"object\") continue;\n\t\tconst server = value as { command?: unknown; args?: unknown; env?: unknown };\n\t\tif (typeof server.command !== \"string\") {\n\t\t\tthrow new Error(\n\t\t\t\t`Cannot merge: MCP server \"${name}\" has no command (url/http-type servers don't round-trip through authoring). ` +\n\t\t\t\t\t\"Edit the plugin's .mcp.json directly instead.\",\n\t\t\t);\n\t\t}\n\t\tout.push({\n\t\t\tname,\n\t\t\tcommand: server.command,\n\t\t\t...(Array.isArray(server.args) ? { args: server.args.map(String) } : {}),\n\t\t\t...(server.env && typeof server.env === \"object\" ? { env: server.env as Record<string, string> } : {}),\n\t\t});\n\t}\n\treturn out;\n}\n\n/** Dedupe authored hooks by (event, matcher, command) so a re-supplied hook doesn't stack. */\nfunction dedupeHooks(hooks: AuthoredHook[]): AuthoredHook[] {\n\tconst seen = new Set<string>();\n\tconst out: AuthoredHook[] = [];\n\tfor (const h of hooks) {\n\t\tconst key = `${h.event}\u0000${h.matcher ?? \"\"}\u0000${h.command}`;\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tout.push(h);\n\t}\n\treturn out;\n}\n\n/**\n * Merge inline-authored `delta` capabilities into the existing local plugin `id`\n * and re-emit. Unlike a marketplace `UpdatePlugin`, nothing is fetched from a\n * remote source — the new content comes from the caller — so the supply-chain\n * \"benign v1 → hostile v2\" vector the spec guards against is structurally absent.\n *\n * Merge semantics:\n * - **Skills / commands / agents** are directory-scanned, so existing ones are\n * left on disk untouched; a delta entry with a matching name overwrites just\n * that file (an update), a new name is added.\n * - **Hooks** and **MCP servers** live in single files that a re-emit rewrites,\n * so they are re-emitted as the *union* of existing + delta (MCP keyed by\n * server name with delta winning; hooks deduped by event/matcher/command).\n * Hooks have no name, so there is deliberately no modify-in-place: a delta\n * hook with the same event/matcher but a different command is a NEW hook\n * added alongside the old one, never a replacement. (Keying replacement by\n * event+matcher would silently drop legitimate sibling hooks that share\n * them.) Changing a hook = {@link removeFromPlugin} the old one + merge the\n * new one.\n * - **Metadata** (version, description, author) takes the delta's value when\n * provided, else keeps the existing one.\n *\n * Platforms default to the plugin's existing `supportPlatform` so a merge never\n * silently adds or drops a vendor layout.\n */\nexport function mergePluginDraft(\n\tcwd: string,\n\tid: string,\n\tdelta: Partial<PluginDraft>,\n\tplatforms?: MarketplacePlatform[],\n): WriteResult {\n\tconst existing = getPlugin(cwd, id);\n\tif (!existing) {\n\t\tthrow new Error(`Cannot update plugin \"${id}\": it does not exist. Use ProposePlugin to create it first.`);\n\t}\n\t// Authored-only: merging re-emits manifests and hook/MCP files through our\n\t// writer, which only round-trips what PluginDraft can represent. Running that\n\t// over a marketplace install could silently drop fields it carries (capability\n\t// -dir overrides, url-type MCP servers, extra manifest keys).\n\tif (!isAuthoredPlugin(cwd, id)) {\n\t\tthrow new Error(\n\t\t\t`Cannot update plugin \"${id}\": it was not authored here (no ${AUTHORED_MARKER_FILE} marker). ` +\n\t\t\t\t\"Only locally authored plugins can be merged.\",\n\t\t);\n\t}\n\n\tconst existingHooks = existing.hooks ? hooksConfigToAuthored(existing.hooks) : [];\n\tconst mergedHooks = dedupeHooks([...existingHooks, ...(delta.hooks ?? [])]);\n\n\tconst mcpByName = new Map<string, AuthoredMcpServer>();\n\tfor (const s of existing.mcpServers ? mcpRecordToAuthored(existing.mcpServers) : []) mcpByName.set(s.name, s);\n\tfor (const s of delta.mcpServers ?? []) mcpByName.set(s.name, s);\n\n\tconst targets = existingLayout(existing, platforms);\n\tconst merged: PluginDraft = {\n\t\tid,\n\t\tversion: delta.version ?? existing.version,\n\t\tdescription: delta.description ?? existing.description,\n\t\tauthor: delta.author ?? existing.author,\n\t\tsupportPlatform: targets,\n\t\t// Keys we do not model survive the manifest rewrite.\n\t\tunknownFields: existing.unknownFields,\n\t\t// Directory-scanned capabilities: delta-only; existing files stay on disk.\n\t\tskills: delta.skills,\n\t\tcommands: delta.commands,\n\t\tagents: delta.agents,\n\t\t// Single-file capabilities: re-emit the union so a merge never drops them.\n\t\thooks: mergedHooks.length ? mergedHooks : undefined,\n\t\tmcpServers: mcpByName.size ? [...mcpByName.values()] : undefined,\n\t};\n\t// An edit stays where the plugin already lives; it never relocates it.\n\treturn writePluginDraft(merged, targets, { dest: findPluginDir(cwd, id) });\n}\n\n/** A hook to remove: `event` is required; `matcher`/`command` narrow the match when provided. */\ninterface HookRemovalSpec {\n\tevent: string;\n\tmatcher?: string;\n\tcommand?: string;\n}\n\n/** Named capabilities to remove from an authored plugin. */\nexport interface RemovalSpec {\n\tskills?: string[];\n\tcommands?: string[];\n\tsubagents?: string[];\n\tmcpServers?: string[];\n\thooks?: HookRemovalSpec[];\n}\n\nexport interface RemoveResult {\n\tdest: string;\n\t/** Human-readable descriptions of what was removed. */\n\tremoved: string[];\n\t/** Requested capabilities that were not found (nothing was removed for these). */\n\tmissing: string[];\n}\n\nfunction describeHookSpec(h: HookRemovalSpec): string {\n\treturn `hook [${h.event}${h.matcher !== undefined ? ` matcher=${h.matcher}` : \"\"}${h.command !== undefined ? ` command=${h.command}` : \"\"}]`;\n}\n\n/**\n * Remove named capabilities from the authored plugin `id`. The inverse of the\n * additive merge, and — like {@link mergePluginDraft} — authored-only.\n *\n * Removal is the low-risk direction (deleting capabilities cannot execute\n * code), which is why callers may run it without a confirmation gate.\n *\n * - **Skills / commands / subagents** are directory-scanned, so removal is a\n * surgical file delete at our emit conventions; no re-emit needed.\n * - **Hooks** (matched by event, narrowed by matcher/command when given) and\n * **MCP servers** (by name) live in single files, so the remaining set is\n * re-emitted — and when a set empties, its file is DELETED, because the\n * parser falls back to `hooks/hooks.json` / `.mcp.json` on disk and a stale\n * file would resurrect the removed capability on the next parse.\n */\nexport function removeFromPlugin(cwd: string, id: string, spec: RemovalSpec): RemoveResult {\n\tconst existing = getPlugin(cwd, id);\n\tif (!existing) {\n\t\tthrow new Error(`Cannot remove from plugin \"${id}\": it does not exist.`);\n\t}\n\tif (!isAuthoredPlugin(cwd, id)) {\n\t\tthrow new Error(\n\t\t\t`Cannot remove from plugin \"${id}\": it was not authored here (no ${AUTHORED_MARKER_FILE} marker). ` +\n\t\t\t\t\"Only locally authored plugins can be edited.\",\n\t\t);\n\t}\n\tconst dest = findPluginDir(cwd, id);\n\tif (!dest) throw new Error(`Cannot remove from plugin \"${id}\": it is not on disk.`);\n\tconst removed: string[] = [];\n\tconst missing: string[] = [];\n\n\t// Directory-scanned capabilities: surgical deletes at our emit conventions.\n\tconst fileTargets: Array<[kind: string, name: string, relPath: string]> = [\n\t\t...(spec.skills ?? []).map((n): [string, string, string] => [\"skill\", n, path.join(\"skills\", slug(n))]),\n\t\t...(spec.commands ?? []).map((n): [string, string, string] => [\n\t\t\t\"command\",\n\t\t\tn,\n\t\t\tpath.join(\"commands\", `${slug(n)}.md`),\n\t\t]),\n\t\t...(spec.subagents ?? []).map((n): [string, string, string] => [\n\t\t\t\"subagent\",\n\t\t\tn,\n\t\t\tpath.join(\"agents\", `${slug(n)}.md`),\n\t\t]),\n\t];\n\tfor (const [kind, name, rel] of fileTargets) {\n\t\tconst abs = path.join(dest, rel);\n\t\tif (existsSync(abs)) {\n\t\t\trmSync(abs, { recursive: true, force: true });\n\t\t\tremoved.push(`${kind} \"${name}\"`);\n\t\t} else {\n\t\t\tmissing.push(`${kind} \"${name}\"`);\n\t\t}\n\t}\n\n\t// Single-file capabilities: filter the reconstructed sets, then re-emit.\n\tlet singleFileChanged = false;\n\tlet remainingHooks = existing.hooks ? hooksConfigToAuthored(existing.hooks) : [];\n\tfor (const h of spec.hooks ?? []) {\n\t\tconst before = remainingHooks.length;\n\t\tremainingHooks = remainingHooks.filter(\n\t\t\t(x) =>\n\t\t\t\t!(\n\t\t\t\t\tx.event === h.event &&\n\t\t\t\t\t(h.matcher === undefined || (x.matcher ?? \"\") === h.matcher) &&\n\t\t\t\t\t(h.command === undefined || x.command === h.command)\n\t\t\t\t),\n\t\t);\n\t\tconst n = before - remainingHooks.length;\n\t\tif (n > 0) {\n\t\t\tremoved.push(`${n} ${describeHookSpec(h)}`);\n\t\t\tsingleFileChanged = true;\n\t\t} else {\n\t\t\tmissing.push(describeHookSpec(h));\n\t\t}\n\t}\n\tlet remainingMcp = existing.mcpServers ? mcpRecordToAuthored(existing.mcpServers) : [];\n\tfor (const name of spec.mcpServers ?? []) {\n\t\tconst before = remainingMcp.length;\n\t\tremainingMcp = remainingMcp.filter((s) => s.name !== name);\n\t\tif (remainingMcp.length < before) {\n\t\t\tremoved.push(`mcp server \"${name}\"`);\n\t\t\tsingleFileChanged = true;\n\t\t} else {\n\t\t\tmissing.push(`mcp server \"${name}\"`);\n\t\t}\n\t}\n\n\tif (singleFileChanged) {\n\t\tconst targets = existingLayout(existing);\n\t\twritePluginDraft(\n\t\t\t{\n\t\t\t\tid,\n\t\t\t\tversion: existing.version,\n\t\t\t\tdescription: existing.description,\n\t\t\t\tauthor: existing.author,\n\t\t\t\tsupportPlatform: targets,\n\t\t\t\tunknownFields: existing.unknownFields,\n\t\t\t\thooks: remainingHooks.length ? remainingHooks : undefined,\n\t\t\t\tmcpServers: remainingMcp.length ? remainingMcp : undefined,\n\t\t\t},\n\t\t\ttargets,\n\t\t\t{ dest },\n\t\t);\n\t\t// Emit skips empty sets, so a stale file from the previous emit survives\n\t\t// and the parser's on-disk fallback would resurrect it — delete explicitly.\n\t\tif (remainingHooks.length === 0) rmSync(path.join(dest, \"hooks\", \"hooks.json\"), { force: true });\n\t\tif (remainingMcp.length === 0) rmSync(path.join(dest, \".mcp.json\"), { force: true });\n\t}\n\n\treturn { dest, removed, missing };\n}\n"]}
@@ -103,7 +103,7 @@ export declare function authoredHooksToConfig(hooks: AuthoredHook[]): Record<str
103
103
  export declare function slug(name: string): string;
104
104
  /**
105
105
  * Render a comma-separated tool allowlist (Claude Code convention, e.g.
106
- * "read, grep") as a YAML flow sequence (`['read', 'grep']`) for formats whose
106
+ * "read, search") as a YAML flow sequence (`['read', 'search']`) for formats whose
107
107
  * frontmatter takes tools as a list (Copilot custom agents / prompt files).
108
108
  */
109
109
  export declare function toolsYamlList(tools: string | undefined): string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/shared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared, format-agnostic helpers used by the plugin format adapters.\n *\n * Kept deliberately free of any runtime dependency on `../manifest.js` (it only\n * imports *types* from there) so the adapter registry can be wired without a\n * module cycle: `manifest.ts → formats/index.ts → formats/<adapter>.ts →\n * shared.ts`, with the back-reference to manifest types erased at compile time.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { CANVAS_ENTRY_FILE } from \"../../../canvas/discovery.js\";\nimport type { PluginCanvasExtension, PluginHooksConfig } from \"../manifest.js\";\nimport type { AuthoredHook, WorkspaceLayout } from \"./types.js\";\n\n/** Raw manifest shape accepted by the `plugin.json`-style formats (agents/claude/copilot). */\nexport interface RawManifest {\n\tname?: string;\n\tversion?: string;\n\tdescription?: string;\n\tauthor?: string | { name?: string };\n\t/** Optional capability-dir override(s): a path (or list of paths) relative to the plugin root, e.g. `\"skills\": \"./skills/\"`. */\n\tskills?: unknown;\n\tcommands?: unknown;\n\tagents?: unknown;\n\tthemes?: unknown;\n\thooks?: PluginHooksConfig | { hooks?: PluginHooksConfig };\n\t/** Inline server map, or a path (Claude Code form, e.g. `\"./.mcp.json\"`) relative to the plugin root. */\n\tmcpServers?: Record<string, unknown> | string;\n\t/** Native-only. */\n\tproviders?: unknown;\n\t/**\n\t * Copilot: canvas-extension directory (a path, or list of paths, relative to\n\t * the plugin root — e.g. `\"extensions\": \"extensions\"`). The Agent Plugins spec\n\t * gives the same key a second, unrelated meaning: a map of vendor metadata\n\t * namespaces (`{ \"com.github.copilot\": { logo } }`). Both readings are handled\n\t * — see {@link detectCanvasExtensions} — and the map form is preserved\n\t * verbatim through `unknownFields`.\n\t */\n\textensions?: unknown;\n\t/** Copilot: LSP config path or inline definitions. Parsed for preservation only. */\n\tlspServers?: unknown;\n\t/** Any key the adapter does not model. */\n\t[key: string]: unknown;\n}\n\n/**\n * Manifest keys every adapter models; anything else is preserved via\n * `unknownFields`.\n *\n * Surfaced through {@link declaredVocabulary} so the Tier 2 drift check has\n * something to diff the vendor references against. A checker that inferred our\n * coverage by reading the parser would be checking its own inference; a declared\n * set is a claim the codebase makes and the check can falsify.\n */\nconst MODELLED_MANIFEST_KEYS = new Set([\n\t\"name\",\n\t\"version\",\n\t\"description\",\n\t\"author\",\n\t\"skills\",\n\t\"commands\",\n\t\"agents\",\n\t\"themes\",\n\t\"hooks\",\n\t\"mcpServers\",\n\t\"providers\",\n\t\"$schema\",\n]);\n\n/** Manifest keys not modelled here, preserved verbatim so a re-emit cannot drop them. */\nexport function unknownManifestFields(raw: RawManifest): Record<string, unknown> | undefined {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(raw)) {\n\t\tif (!MODELLED_MANIFEST_KEYS.has(key)) out[key] = value;\n\t}\n\treturn Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * Vendor content namespace directory. The Agent Plugins layout both vendors are\n * converging on keeps portable capabilities at the plugin root (`skills/`) and\n * puts vendor-specific ones under a reverse-DNS directory, so Copilot's agents\n * and canvas extensions ship as `com.github.copilot/<capability>/`.\n * `github/awesome-copilot` publishes its whole catalog this way.\n */\nexport const COPILOT_CONTENT_DIR = \"com.github.copilot\";\n\n/** Conventional canvas-extension container, relative to a plugin root. */\nconst CANVAS_EXTENSIONS_DIR = \"extensions\";\n\n/**\n * Canvas-extension containers a plugin may ship, starting with the manifest's own\n * `extensions` path (Copilot's key, e.g. `\"extensions\": \"extensions\"`). Both are\n * real: `extensions/` is what a standalone canvas plugin uses, and the namespaced\n * one is what a materialized `awesome-copilot` entry carries.\n */\nfunction canvasContainerDirs(root: string, override: unknown): string[] {\n\tconst dirs: string[] = [];\n\t// `extensions` is also the key the Agent Plugins spec uses for a *map* of\n\t// vendor metadata (`{ \"com.github.copilot\": { logo } }`). `resolveCapabilityDir`\n\t// ignores anything that is not a string or string array, so the two readings\n\t// of one key cannot collide — and the map form stays in `unknownFields`, which\n\t// is what keeps a re-emit from dropping it.\n\tconst declared = resolveCapabilityDir(root, override, CANVAS_EXTENSIONS_DIR);\n\tif (declared) dirs.push(declared);\n\tconst namespaced = dirIfExists(root, path.join(COPILOT_CONTENT_DIR, CANVAS_EXTENSIONS_DIR));\n\tif (namespaced && !dirs.includes(namespaced)) dirs.push(namespaced);\n\treturn dirs;\n}\n\n/**\n * Canvas extensions a plugin ships (see `docs/canvas-extensions-design.md` §4.3).\n *\n * Discovery keys off `<dir>/extension.mjs` and nothing else, exactly as\n * `core/canvas/discovery.ts` does for the workspace and user search roots — the\n * entry file is the whole contract, so a plugin's canvases are found by the same\n * rule as everyone else's.\n *\n * A plugin whose *root* carries `extension.mjs` is itself one canvas extension,\n * which is how a single-canvas repository is laid out; its id is the plugin id,\n * since there is no directory name below the root to take one from.\n */\nexport function detectCanvasExtensions(\n\troot: string,\n\tpluginId: string,\n\toverride: unknown,\n): PluginCanvasExtension[] | undefined {\n\tconst found: PluginCanvasExtension[] = [];\n\tconst seen = new Set<string>();\n\tconst add = (id: string, dir: string): void => {\n\t\tif (seen.has(id)) return;\n\t\tif (!fs.existsSync(path.join(dir, CANVAS_ENTRY_FILE))) return;\n\t\tseen.add(id);\n\t\tfound.push({ id, dir });\n\t};\n\n\tadd(pluginId, root);\n\tfor (const container of canvasContainerDirs(root, override)) {\n\t\tlet entries: fs.Dirent[];\n\t\ttry {\n\t\t\tentries = fs.readdirSync(container, { withFileTypes: true });\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n\t\t\tif (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n\t\t\tadd(entry.name, path.join(container, entry.name));\n\t\t}\n\t}\n\treturn found.length > 0 ? found : undefined;\n}\n\n/**\n * On-disk component surfaces hoocode does not load, checked against both vendors'\n * file-location tables. The files are left alone; naming them is what makes the\n * gap visible (see NormalizedPlugin.unsupportedSurfaces).\n */\nconst UNSUPPORTED_SURFACES: ReadonlyArray<{ rel: string; label: string }> = [\n\t{ rel: \"workflows\", label: \"workflows/\" },\n\t{ rel: \"output-styles\", label: \"output-styles/\" },\n\t{ rel: \"monitors/monitors.json\", label: \"monitors/\" },\n\t{ rel: \"bin\", label: \"bin/\" },\n\t{ rel: \"settings.json\", label: \"settings.json\" },\n\t{ rel: \".lsp.json\", label: \".lsp.json\" },\n\t{ rel: \"lsp.json\", label: \"lsp.json\" },\n\t{ rel: path.join(\".github\", \"lsp.json\"), label: \".github/lsp.json\" },\n];\n\n/** Which unsupported surfaces are present under `root`. */\nexport function detectUnsupportedSurfaces(root: string): string[] | undefined {\n\tconst found = UNSUPPORTED_SURFACES.filter((s) => fs.existsSync(path.join(root, s.rel))).map((s) => s.label);\n\treturn found.length > 0 ? found : undefined;\n}\n\nexport function readJson<T>(file: string): T | null {\n\ttry {\n\t\treturn JSON.parse(fs.readFileSync(file, \"utf8\")) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function dirIfExists(root: string, name: string): string | undefined {\n\tconst p = path.join(root, name);\n\treturn fs.existsSync(p) && fs.statSync(p).isDirectory() ? p : undefined;\n}\n\n/**\n * Resolve a capability directory: an explicit manifest override — a path (or\n * list of paths, first existing wins) relative to the plugin root, e.g.\n * `\"skills\": \"./skills/\"` — beats the conventional directory.\n */\nexport function resolveCapabilityDir(root: string, override: unknown, conventional: string): string | undefined {\n\tconst candidates = Array.isArray(override) ? override : [override];\n\tfor (const c of candidates) {\n\t\tif (typeof c !== \"string\" || !c.trim()) continue;\n\t\tconst p = path.resolve(root, c.trim());\n\t\tif (fs.existsSync(p) && fs.statSync(p).isDirectory()) return p;\n\t}\n\treturn dirIfExists(root, conventional);\n}\n\n/** Coerce an author field (string or `{ name }`) to a plain string. */\nexport function parseAuthor(author: RawManifest[\"author\"]): string | undefined {\n\treturn typeof author === \"string\" ? author : author?.name;\n}\n\n/** Accept either `{ hooks: {...} }` or a bare event map, falling back to `hooks/hooks.json`. */\nexport function normalizeHooks(raw: RawManifest[\"hooks\"], root: string): PluginHooksConfig | undefined {\n\tlet config: PluginHooksConfig | undefined;\n\tif (raw && typeof raw === \"object\") {\n\t\tconfig = \"hooks\" in raw && raw.hooks ? (raw.hooks as PluginHooksConfig) : (raw as PluginHooksConfig);\n\t}\n\t// Fall back to the conventional hooks/hooks.json file.\n\tif (!config) {\n\t\tconst hooksFile = path.join(root, \"hooks\", \"hooks.json\");\n\t\tif (fs.existsSync(hooksFile)) {\n\t\t\tconst fileRaw = readJson<RawManifest[\"hooks\"]>(hooksFile);\n\t\t\tif (fileRaw && typeof fileRaw === \"object\") {\n\t\t\t\tconfig =\n\t\t\t\t\t\"hooks\" in fileRaw && fileRaw.hooks\n\t\t\t\t\t\t? (fileRaw.hooks as PluginHooksConfig)\n\t\t\t\t\t\t: (fileRaw as PluginHooksConfig);\n\t\t\t}\n\t\t}\n\t}\n\treturn config && Object.keys(config).length > 0 ? config : undefined;\n}\n\n/**\n * Resolve inline `mcpServers`, a manifest-supplied file path, or a `.mcp.json`\n * file at `root`.\n *\n * `raw` may be:\n * - a string path (Claude Code form: `\"mcpServers\": \"./.mcp.json\"`), resolved\n * relative to the plugin root and read as a server file;\n * - an inline server map (returned as-is);\n * - undefined, falling back to `<root>/<mcpFileName>`.\n *\n * Server files use `{ mcpServers }` (Claude/native) or `{ servers }` (Code/Copilot);\n * both keys are accepted.\n */\nexport function normalizeMcp(\n\traw: Record<string, unknown> | string | undefined,\n\troot: string,\n\tmcpFileName = \".mcp.json\",\n): Record<string, unknown> | undefined {\n\t// Claude Code form: a path to a server file, relative to the plugin root.\n\tif (typeof raw === \"string\") {\n\t\treturn raw.trim() ? readMcpFile(path.resolve(root, raw.trim())) : undefined;\n\t}\n\tif (raw && Object.keys(raw).length > 0) return raw;\n\treturn readMcpFile(path.join(root, mcpFileName));\n}\n\n/** Read a server file, accepting both `{ mcpServers }` and `{ servers }` keys. */\nfunction readMcpFile(mcpFile: string): Record<string, unknown> | undefined {\n\tif (!fs.existsSync(mcpFile)) return undefined;\n\tconst fileRaw = readJson<{ mcpServers?: Record<string, unknown>; servers?: Record<string, unknown> }>(mcpFile);\n\tconst servers = fileRaw?.mcpServers ?? fileRaw?.servers;\n\treturn servers && Object.keys(servers).length > 0 ? servers : undefined;\n}\n\n// ============================================================================\n// Emit helpers (used by the writer / scaffolding half of each adapter)\n// ============================================================================\n\n/** Serialize a small set of frontmatter fields to YAML. Values are strings only. */\n/**\n * Render frontmatter, or nothing at all when every field is empty.\n *\n * Emitting bare `---\\n---` looks harmless and is not: YAML parses an empty\n * document as `null`, and Claude Code rejects a component whose frontmatter is\n * not a mapping. A command authored without a description hit exactly that, and\n * the artifact was invalid in the ecosystem it was written for while\n * round-tripping happily through our own reader.\n */\nfunction emitFrontmatter(fields: Record<string, string | undefined>): string {\n\tconst lines: string[] = [];\n\tfor (const [key, value] of Object.entries(fields)) {\n\t\tif (value === undefined || value === \"\") continue;\n\t\t// Quote values that could be misparsed as YAML (contain a colon-space or start punctuation).\n\t\tconst needsQuote = /[:#]|^[\\s>|@`&*!%]/.test(value) || value.includes(\"\\n\");\n\t\tlines.push(`${key}: ${needsQuote ? JSON.stringify(value) : value}`);\n\t}\n\treturn lines.length > 0 ? [\"---\", ...lines, \"---\"].join(\"\\n\") : \"\";\n}\n\n/** A markdown capability file: frontmatter block + body. */\nexport function emitMarkdown(fields: Record<string, string | undefined>, body: string): string {\n\tconst frontmatter = emitFrontmatter(fields);\n\treturn frontmatter ? `${frontmatter}\\n\\n${body.trimEnd()}\\n` : `${body.trimEnd()}\\n`;\n}\n\n/** Pretty-print a JSON manifest with a trailing newline (matches repo convention). */\nexport function emitJson(value: unknown): string {\n\treturn `${JSON.stringify(value, null, 2)}\\n`;\n}\n\n/** Convert authored hooks into the on-disk `hooks.json` event-map shape shared by all formats. */\nexport function authoredHooksToConfig(hooks: AuthoredHook[]): Record<string, unknown> {\n\tconst byEvent: Record<string, Array<{ matcher?: string; hooks: unknown[] }>> = {};\n\tfor (const h of hooks) {\n\t\tconst group = byEvent[h.event] ?? [];\n\t\tbyEvent[h.event] = group;\n\t\tgroup.push({\n\t\t\t...(h.matcher ? { matcher: h.matcher } : {}),\n\t\t\thooks: [{ type: \"command\", command: h.command, ...(h.timeout ? { timeout: h.timeout } : {}) }],\n\t\t});\n\t}\n\treturn byEvent;\n}\n\n/** Slug-safe filename component (no path separators, conservative charset). */\nexport function slug(name: string): string {\n\treturn name\n\t\t.trim()\n\t\t.replace(/[^a-zA-Z0-9._-]+/g, \"-\")\n\t\t.replace(/^-+|-+$/g, \"\")\n\t\t.slice(0, 80);\n}\n\n/**\n * Render a comma-separated tool allowlist (Claude Code convention, e.g.\n * \"read, grep\") as a YAML flow sequence (`['read', 'grep']`) for formats whose\n * frontmatter takes tools as a list (Copilot custom agents / prompt files).\n */\nexport function toolsYamlList(tools: string | undefined): string | undefined {\n\tconst items = (tools ?? \"\")\n\t\t.split(/[,\\s]+/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\tif (items.length === 0) return undefined;\n\treturn `[${items.map((t) => `'${t.replace(/'/g, \"''\")}'`).join(\", \")}]`;\n}\n\n/**\n * The workspace layout shared by the `.agents/` and `.claude/` conventions:\n * `<root>/skills/<name>/SKILL.md`, `<root>/agents/<name>.md`,\n * `<root>/commands/<name>.md`. Copilot's differs and lives in its adapter.\n */\nexport function claudeStyleWorkspace(root: string): WorkspaceLayout {\n\treturn {\n\t\troot,\n\t\temitSkill: (s) => ({\n\t\t\tpath: path.join(root, \"skills\", slug(s.name), \"SKILL.md\"),\n\t\t\tcontent: emitMarkdown({ name: s.name, description: s.description }, s.body),\n\t\t}),\n\t\temitAgent: (a) => ({\n\t\t\tpath: path.join(root, \"agents\", `${slug(a.name)}.md`),\n\t\t\tcontent: emitMarkdown({ name: a.name, description: a.description, tools: a.tools, model: a.model }, a.body),\n\t\t}),\n\t\temitCommand: (c) => ({\n\t\t\tpath: path.join(root, \"commands\", `${slug(c.name)}.md`),\n\t\t\tcontent: emitMarkdown({ name: c.name, description: c.description }, c.body),\n\t\t}),\n\t};\n}\n\n/** The manifest keys the adapters model, as a sorted list. Input to the drift check (§2.2). */\nexport function modelledManifestKeys(): string[] {\n\treturn [...MODELLED_MANIFEST_KEYS].sort();\n}\n\n/**\n * Surfaces we know about and deliberately do not load, as the **relative paths**\n * they actually occupy rather than their display labels.\n *\n * The distinction bit once already: the labels are written for humans\n * (`\"monitors/\"`), the vendor reference writes the real path\n * (`monitors/monitors.json`), and a drift check comparing the two reported a\n * known surface as a new finding.\n */\nexport function knownUnsupportedSurfaces(): string[] {\n\treturn UNSUPPORTED_SURFACES.map((s) => s.rel.replace(/\\\\/g, \"/\")).sort();\n}\n"]}
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/shared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared, format-agnostic helpers used by the plugin format adapters.\n *\n * Kept deliberately free of any runtime dependency on `../manifest.js` (it only\n * imports *types* from there) so the adapter registry can be wired without a\n * module cycle: `manifest.ts → formats/index.ts → formats/<adapter>.ts →\n * shared.ts`, with the back-reference to manifest types erased at compile time.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { CANVAS_ENTRY_FILE } from \"../../../canvas/discovery.js\";\nimport type { PluginCanvasExtension, PluginHooksConfig } from \"../manifest.js\";\nimport type { AuthoredHook, WorkspaceLayout } from \"./types.js\";\n\n/** Raw manifest shape accepted by the `plugin.json`-style formats (agents/claude/copilot). */\nexport interface RawManifest {\n\tname?: string;\n\tversion?: string;\n\tdescription?: string;\n\tauthor?: string | { name?: string };\n\t/** Optional capability-dir override(s): a path (or list of paths) relative to the plugin root, e.g. `\"skills\": \"./skills/\"`. */\n\tskills?: unknown;\n\tcommands?: unknown;\n\tagents?: unknown;\n\tthemes?: unknown;\n\thooks?: PluginHooksConfig | { hooks?: PluginHooksConfig };\n\t/** Inline server map, or a path (Claude Code form, e.g. `\"./.mcp.json\"`) relative to the plugin root. */\n\tmcpServers?: Record<string, unknown> | string;\n\t/** Native-only. */\n\tproviders?: unknown;\n\t/**\n\t * Copilot: canvas-extension directory (a path, or list of paths, relative to\n\t * the plugin root — e.g. `\"extensions\": \"extensions\"`). The Agent Plugins spec\n\t * gives the same key a second, unrelated meaning: a map of vendor metadata\n\t * namespaces (`{ \"com.github.copilot\": { logo } }`). Both readings are handled\n\t * — see {@link detectCanvasExtensions} — and the map form is preserved\n\t * verbatim through `unknownFields`.\n\t */\n\textensions?: unknown;\n\t/** Copilot: LSP config path or inline definitions. Parsed for preservation only. */\n\tlspServers?: unknown;\n\t/** Any key the adapter does not model. */\n\t[key: string]: unknown;\n}\n\n/**\n * Manifest keys every adapter models; anything else is preserved via\n * `unknownFields`.\n *\n * Surfaced through {@link declaredVocabulary} so the Tier 2 drift check has\n * something to diff the vendor references against. A checker that inferred our\n * coverage by reading the parser would be checking its own inference; a declared\n * set is a claim the codebase makes and the check can falsify.\n */\nconst MODELLED_MANIFEST_KEYS = new Set([\n\t\"name\",\n\t\"version\",\n\t\"description\",\n\t\"author\",\n\t\"skills\",\n\t\"commands\",\n\t\"agents\",\n\t\"themes\",\n\t\"hooks\",\n\t\"mcpServers\",\n\t\"providers\",\n\t\"$schema\",\n]);\n\n/** Manifest keys not modelled here, preserved verbatim so a re-emit cannot drop them. */\nexport function unknownManifestFields(raw: RawManifest): Record<string, unknown> | undefined {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(raw)) {\n\t\tif (!MODELLED_MANIFEST_KEYS.has(key)) out[key] = value;\n\t}\n\treturn Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * Vendor content namespace directory. The Agent Plugins layout both vendors are\n * converging on keeps portable capabilities at the plugin root (`skills/`) and\n * puts vendor-specific ones under a reverse-DNS directory, so Copilot's agents\n * and canvas extensions ship as `com.github.copilot/<capability>/`.\n * `github/awesome-copilot` publishes its whole catalog this way.\n */\nexport const COPILOT_CONTENT_DIR = \"com.github.copilot\";\n\n/** Conventional canvas-extension container, relative to a plugin root. */\nconst CANVAS_EXTENSIONS_DIR = \"extensions\";\n\n/**\n * Canvas-extension containers a plugin may ship, starting with the manifest's own\n * `extensions` path (Copilot's key, e.g. `\"extensions\": \"extensions\"`). Both are\n * real: `extensions/` is what a standalone canvas plugin uses, and the namespaced\n * one is what a materialized `awesome-copilot` entry carries.\n */\nfunction canvasContainerDirs(root: string, override: unknown): string[] {\n\tconst dirs: string[] = [];\n\t// `extensions` is also the key the Agent Plugins spec uses for a *map* of\n\t// vendor metadata (`{ \"com.github.copilot\": { logo } }`). `resolveCapabilityDir`\n\t// ignores anything that is not a string or string array, so the two readings\n\t// of one key cannot collide — and the map form stays in `unknownFields`, which\n\t// is what keeps a re-emit from dropping it.\n\tconst declared = resolveCapabilityDir(root, override, CANVAS_EXTENSIONS_DIR);\n\tif (declared) dirs.push(declared);\n\tconst namespaced = dirIfExists(root, path.join(COPILOT_CONTENT_DIR, CANVAS_EXTENSIONS_DIR));\n\tif (namespaced && !dirs.includes(namespaced)) dirs.push(namespaced);\n\treturn dirs;\n}\n\n/**\n * Canvas extensions a plugin ships (see `docs/canvas-extensions-design.md` §4.3).\n *\n * Discovery keys off `<dir>/extension.mjs` and nothing else, exactly as\n * `core/canvas/discovery.ts` does for the workspace and user search roots — the\n * entry file is the whole contract, so a plugin's canvases are found by the same\n * rule as everyone else's.\n *\n * A plugin whose *root* carries `extension.mjs` is itself one canvas extension,\n * which is how a single-canvas repository is laid out; its id is the plugin id,\n * since there is no directory name below the root to take one from.\n */\nexport function detectCanvasExtensions(\n\troot: string,\n\tpluginId: string,\n\toverride: unknown,\n): PluginCanvasExtension[] | undefined {\n\tconst found: PluginCanvasExtension[] = [];\n\tconst seen = new Set<string>();\n\tconst add = (id: string, dir: string): void => {\n\t\tif (seen.has(id)) return;\n\t\tif (!fs.existsSync(path.join(dir, CANVAS_ENTRY_FILE))) return;\n\t\tseen.add(id);\n\t\tfound.push({ id, dir });\n\t};\n\n\tadd(pluginId, root);\n\tfor (const container of canvasContainerDirs(root, override)) {\n\t\tlet entries: fs.Dirent[];\n\t\ttry {\n\t\t\tentries = fs.readdirSync(container, { withFileTypes: true });\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n\t\t\tif (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n\t\t\tadd(entry.name, path.join(container, entry.name));\n\t\t}\n\t}\n\treturn found.length > 0 ? found : undefined;\n}\n\n/**\n * On-disk component surfaces hoocode does not load, checked against both vendors'\n * file-location tables. The files are left alone; naming them is what makes the\n * gap visible (see NormalizedPlugin.unsupportedSurfaces).\n */\nconst UNSUPPORTED_SURFACES: ReadonlyArray<{ rel: string; label: string }> = [\n\t{ rel: \"workflows\", label: \"workflows/\" },\n\t{ rel: \"output-styles\", label: \"output-styles/\" },\n\t{ rel: \"monitors/monitors.json\", label: \"monitors/\" },\n\t{ rel: \"bin\", label: \"bin/\" },\n\t{ rel: \"settings.json\", label: \"settings.json\" },\n\t{ rel: \".lsp.json\", label: \".lsp.json\" },\n\t{ rel: \"lsp.json\", label: \"lsp.json\" },\n\t{ rel: path.join(\".github\", \"lsp.json\"), label: \".github/lsp.json\" },\n];\n\n/** Which unsupported surfaces are present under `root`. */\nexport function detectUnsupportedSurfaces(root: string): string[] | undefined {\n\tconst found = UNSUPPORTED_SURFACES.filter((s) => fs.existsSync(path.join(root, s.rel))).map((s) => s.label);\n\treturn found.length > 0 ? found : undefined;\n}\n\nexport function readJson<T>(file: string): T | null {\n\ttry {\n\t\treturn JSON.parse(fs.readFileSync(file, \"utf8\")) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function dirIfExists(root: string, name: string): string | undefined {\n\tconst p = path.join(root, name);\n\treturn fs.existsSync(p) && fs.statSync(p).isDirectory() ? p : undefined;\n}\n\n/**\n * Resolve a capability directory: an explicit manifest override — a path (or\n * list of paths, first existing wins) relative to the plugin root, e.g.\n * `\"skills\": \"./skills/\"` — beats the conventional directory.\n */\nexport function resolveCapabilityDir(root: string, override: unknown, conventional: string): string | undefined {\n\tconst candidates = Array.isArray(override) ? override : [override];\n\tfor (const c of candidates) {\n\t\tif (typeof c !== \"string\" || !c.trim()) continue;\n\t\tconst p = path.resolve(root, c.trim());\n\t\tif (fs.existsSync(p) && fs.statSync(p).isDirectory()) return p;\n\t}\n\treturn dirIfExists(root, conventional);\n}\n\n/** Coerce an author field (string or `{ name }`) to a plain string. */\nexport function parseAuthor(author: RawManifest[\"author\"]): string | undefined {\n\treturn typeof author === \"string\" ? author : author?.name;\n}\n\n/** Accept either `{ hooks: {...} }` or a bare event map, falling back to `hooks/hooks.json`. */\nexport function normalizeHooks(raw: RawManifest[\"hooks\"], root: string): PluginHooksConfig | undefined {\n\tlet config: PluginHooksConfig | undefined;\n\tif (raw && typeof raw === \"object\") {\n\t\tconfig = \"hooks\" in raw && raw.hooks ? (raw.hooks as PluginHooksConfig) : (raw as PluginHooksConfig);\n\t}\n\t// Fall back to the conventional hooks/hooks.json file.\n\tif (!config) {\n\t\tconst hooksFile = path.join(root, \"hooks\", \"hooks.json\");\n\t\tif (fs.existsSync(hooksFile)) {\n\t\t\tconst fileRaw = readJson<RawManifest[\"hooks\"]>(hooksFile);\n\t\t\tif (fileRaw && typeof fileRaw === \"object\") {\n\t\t\t\tconfig =\n\t\t\t\t\t\"hooks\" in fileRaw && fileRaw.hooks\n\t\t\t\t\t\t? (fileRaw.hooks as PluginHooksConfig)\n\t\t\t\t\t\t: (fileRaw as PluginHooksConfig);\n\t\t\t}\n\t\t}\n\t}\n\treturn config && Object.keys(config).length > 0 ? config : undefined;\n}\n\n/**\n * Resolve inline `mcpServers`, a manifest-supplied file path, or a `.mcp.json`\n * file at `root`.\n *\n * `raw` may be:\n * - a string path (Claude Code form: `\"mcpServers\": \"./.mcp.json\"`), resolved\n * relative to the plugin root and read as a server file;\n * - an inline server map (returned as-is);\n * - undefined, falling back to `<root>/<mcpFileName>`.\n *\n * Server files use `{ mcpServers }` (Claude/native) or `{ servers }` (Code/Copilot);\n * both keys are accepted.\n */\nexport function normalizeMcp(\n\traw: Record<string, unknown> | string | undefined,\n\troot: string,\n\tmcpFileName = \".mcp.json\",\n): Record<string, unknown> | undefined {\n\t// Claude Code form: a path to a server file, relative to the plugin root.\n\tif (typeof raw === \"string\") {\n\t\treturn raw.trim() ? readMcpFile(path.resolve(root, raw.trim())) : undefined;\n\t}\n\tif (raw && Object.keys(raw).length > 0) return raw;\n\treturn readMcpFile(path.join(root, mcpFileName));\n}\n\n/** Read a server file, accepting both `{ mcpServers }` and `{ servers }` keys. */\nfunction readMcpFile(mcpFile: string): Record<string, unknown> | undefined {\n\tif (!fs.existsSync(mcpFile)) return undefined;\n\tconst fileRaw = readJson<{ mcpServers?: Record<string, unknown>; servers?: Record<string, unknown> }>(mcpFile);\n\tconst servers = fileRaw?.mcpServers ?? fileRaw?.servers;\n\treturn servers && Object.keys(servers).length > 0 ? servers : undefined;\n}\n\n// ============================================================================\n// Emit helpers (used by the writer / scaffolding half of each adapter)\n// ============================================================================\n\n/** Serialize a small set of frontmatter fields to YAML. Values are strings only. */\n/**\n * Render frontmatter, or nothing at all when every field is empty.\n *\n * Emitting bare `---\\n---` looks harmless and is not: YAML parses an empty\n * document as `null`, and Claude Code rejects a component whose frontmatter is\n * not a mapping. A command authored without a description hit exactly that, and\n * the artifact was invalid in the ecosystem it was written for while\n * round-tripping happily through our own reader.\n */\nfunction emitFrontmatter(fields: Record<string, string | undefined>): string {\n\tconst lines: string[] = [];\n\tfor (const [key, value] of Object.entries(fields)) {\n\t\tif (value === undefined || value === \"\") continue;\n\t\t// Quote values that could be misparsed as YAML (contain a colon-space or start punctuation).\n\t\tconst needsQuote = /[:#]|^[\\s>|@`&*!%]/.test(value) || value.includes(\"\\n\");\n\t\tlines.push(`${key}: ${needsQuote ? JSON.stringify(value) : value}`);\n\t}\n\treturn lines.length > 0 ? [\"---\", ...lines, \"---\"].join(\"\\n\") : \"\";\n}\n\n/** A markdown capability file: frontmatter block + body. */\nexport function emitMarkdown(fields: Record<string, string | undefined>, body: string): string {\n\tconst frontmatter = emitFrontmatter(fields);\n\treturn frontmatter ? `${frontmatter}\\n\\n${body.trimEnd()}\\n` : `${body.trimEnd()}\\n`;\n}\n\n/** Pretty-print a JSON manifest with a trailing newline (matches repo convention). */\nexport function emitJson(value: unknown): string {\n\treturn `${JSON.stringify(value, null, 2)}\\n`;\n}\n\n/** Convert authored hooks into the on-disk `hooks.json` event-map shape shared by all formats. */\nexport function authoredHooksToConfig(hooks: AuthoredHook[]): Record<string, unknown> {\n\tconst byEvent: Record<string, Array<{ matcher?: string; hooks: unknown[] }>> = {};\n\tfor (const h of hooks) {\n\t\tconst group = byEvent[h.event] ?? [];\n\t\tbyEvent[h.event] = group;\n\t\tgroup.push({\n\t\t\t...(h.matcher ? { matcher: h.matcher } : {}),\n\t\t\thooks: [{ type: \"command\", command: h.command, ...(h.timeout ? { timeout: h.timeout } : {}) }],\n\t\t});\n\t}\n\treturn byEvent;\n}\n\n/** Slug-safe filename component (no path separators, conservative charset). */\nexport function slug(name: string): string {\n\treturn name\n\t\t.trim()\n\t\t.replace(/[^a-zA-Z0-9._-]+/g, \"-\")\n\t\t.replace(/^-+|-+$/g, \"\")\n\t\t.slice(0, 80);\n}\n\n/**\n * Render a comma-separated tool allowlist (Claude Code convention, e.g.\n * \"read, search\") as a YAML flow sequence (`['read', 'search']`) for formats whose\n * frontmatter takes tools as a list (Copilot custom agents / prompt files).\n */\nexport function toolsYamlList(tools: string | undefined): string | undefined {\n\tconst items = (tools ?? \"\")\n\t\t.split(/[,\\s]+/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\tif (items.length === 0) return undefined;\n\treturn `[${items.map((t) => `'${t.replace(/'/g, \"''\")}'`).join(\", \")}]`;\n}\n\n/**\n * The workspace layout shared by the `.agents/` and `.claude/` conventions:\n * `<root>/skills/<name>/SKILL.md`, `<root>/agents/<name>.md`,\n * `<root>/commands/<name>.md`. Copilot's differs and lives in its adapter.\n */\nexport function claudeStyleWorkspace(root: string): WorkspaceLayout {\n\treturn {\n\t\troot,\n\t\temitSkill: (s) => ({\n\t\t\tpath: path.join(root, \"skills\", slug(s.name), \"SKILL.md\"),\n\t\t\tcontent: emitMarkdown({ name: s.name, description: s.description }, s.body),\n\t\t}),\n\t\temitAgent: (a) => ({\n\t\t\tpath: path.join(root, \"agents\", `${slug(a.name)}.md`),\n\t\t\tcontent: emitMarkdown({ name: a.name, description: a.description, tools: a.tools, model: a.model }, a.body),\n\t\t}),\n\t\temitCommand: (c) => ({\n\t\t\tpath: path.join(root, \"commands\", `${slug(c.name)}.md`),\n\t\t\tcontent: emitMarkdown({ name: c.name, description: c.description }, c.body),\n\t\t}),\n\t};\n}\n\n/** The manifest keys the adapters model, as a sorted list. Input to the drift check (§2.2). */\nexport function modelledManifestKeys(): string[] {\n\treturn [...MODELLED_MANIFEST_KEYS].sort();\n}\n\n/**\n * Surfaces we know about and deliberately do not load, as the **relative paths**\n * they actually occupy rather than their display labels.\n *\n * The distinction bit once already: the labels are written for humans\n * (`\"monitors/\"`), the vendor reference writes the real path\n * (`monitors/monitors.json`), and a drift check comparing the two reported a\n * known surface as a new finding.\n */\nexport function knownUnsupportedSurfaces(): string[] {\n\treturn UNSUPPORTED_SURFACES.map((s) => s.rel.replace(/\\\\/g, \"/\")).sort();\n}\n"]}
@@ -271,7 +271,7 @@ export function slug(name) {
271
271
  }
272
272
  /**
273
273
  * Render a comma-separated tool allowlist (Claude Code convention, e.g.
274
- * "read, grep") as a YAML flow sequence (`['read', 'grep']`) for formats whose
274
+ * "read, search") as a YAML flow sequence (`['read', 'search']`) for formats whose
275
275
  * frontmatter takes tools as a list (Copilot custom agents / prompt files).
276
276
  */
277
277
  export function toolsYamlList(tools) {
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/shared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared, format-agnostic helpers used by the plugin format adapters.\n *\n * Kept deliberately free of any runtime dependency on `../manifest.js` (it only\n * imports *types* from there) so the adapter registry can be wired without a\n * module cycle: `manifest.ts → formats/index.ts → formats/<adapter>.ts →\n * shared.ts`, with the back-reference to manifest types erased at compile time.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { CANVAS_ENTRY_FILE } from \"../../../canvas/discovery.js\";\nimport type { PluginCanvasExtension, PluginHooksConfig } from \"../manifest.js\";\nimport type { AuthoredHook, WorkspaceLayout } from \"./types.js\";\n\n/** Raw manifest shape accepted by the `plugin.json`-style formats (agents/claude/copilot). */\nexport interface RawManifest {\n\tname?: string;\n\tversion?: string;\n\tdescription?: string;\n\tauthor?: string | { name?: string };\n\t/** Optional capability-dir override(s): a path (or list of paths) relative to the plugin root, e.g. `\"skills\": \"./skills/\"`. */\n\tskills?: unknown;\n\tcommands?: unknown;\n\tagents?: unknown;\n\tthemes?: unknown;\n\thooks?: PluginHooksConfig | { hooks?: PluginHooksConfig };\n\t/** Inline server map, or a path (Claude Code form, e.g. `\"./.mcp.json\"`) relative to the plugin root. */\n\tmcpServers?: Record<string, unknown> | string;\n\t/** Native-only. */\n\tproviders?: unknown;\n\t/**\n\t * Copilot: canvas-extension directory (a path, or list of paths, relative to\n\t * the plugin root — e.g. `\"extensions\": \"extensions\"`). The Agent Plugins spec\n\t * gives the same key a second, unrelated meaning: a map of vendor metadata\n\t * namespaces (`{ \"com.github.copilot\": { logo } }`). Both readings are handled\n\t * — see {@link detectCanvasExtensions} — and the map form is preserved\n\t * verbatim through `unknownFields`.\n\t */\n\textensions?: unknown;\n\t/** Copilot: LSP config path or inline definitions. Parsed for preservation only. */\n\tlspServers?: unknown;\n\t/** Any key the adapter does not model. */\n\t[key: string]: unknown;\n}\n\n/**\n * Manifest keys every adapter models; anything else is preserved via\n * `unknownFields`.\n *\n * Surfaced through {@link declaredVocabulary} so the Tier 2 drift check has\n * something to diff the vendor references against. A checker that inferred our\n * coverage by reading the parser would be checking its own inference; a declared\n * set is a claim the codebase makes and the check can falsify.\n */\nconst MODELLED_MANIFEST_KEYS = new Set([\n\t\"name\",\n\t\"version\",\n\t\"description\",\n\t\"author\",\n\t\"skills\",\n\t\"commands\",\n\t\"agents\",\n\t\"themes\",\n\t\"hooks\",\n\t\"mcpServers\",\n\t\"providers\",\n\t\"$schema\",\n]);\n\n/** Manifest keys not modelled here, preserved verbatim so a re-emit cannot drop them. */\nexport function unknownManifestFields(raw: RawManifest): Record<string, unknown> | undefined {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(raw)) {\n\t\tif (!MODELLED_MANIFEST_KEYS.has(key)) out[key] = value;\n\t}\n\treturn Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * Vendor content namespace directory. The Agent Plugins layout both vendors are\n * converging on keeps portable capabilities at the plugin root (`skills/`) and\n * puts vendor-specific ones under a reverse-DNS directory, so Copilot's agents\n * and canvas extensions ship as `com.github.copilot/<capability>/`.\n * `github/awesome-copilot` publishes its whole catalog this way.\n */\nexport const COPILOT_CONTENT_DIR = \"com.github.copilot\";\n\n/** Conventional canvas-extension container, relative to a plugin root. */\nconst CANVAS_EXTENSIONS_DIR = \"extensions\";\n\n/**\n * Canvas-extension containers a plugin may ship, starting with the manifest's own\n * `extensions` path (Copilot's key, e.g. `\"extensions\": \"extensions\"`). Both are\n * real: `extensions/` is what a standalone canvas plugin uses, and the namespaced\n * one is what a materialized `awesome-copilot` entry carries.\n */\nfunction canvasContainerDirs(root: string, override: unknown): string[] {\n\tconst dirs: string[] = [];\n\t// `extensions` is also the key the Agent Plugins spec uses for a *map* of\n\t// vendor metadata (`{ \"com.github.copilot\": { logo } }`). `resolveCapabilityDir`\n\t// ignores anything that is not a string or string array, so the two readings\n\t// of one key cannot collide — and the map form stays in `unknownFields`, which\n\t// is what keeps a re-emit from dropping it.\n\tconst declared = resolveCapabilityDir(root, override, CANVAS_EXTENSIONS_DIR);\n\tif (declared) dirs.push(declared);\n\tconst namespaced = dirIfExists(root, path.join(COPILOT_CONTENT_DIR, CANVAS_EXTENSIONS_DIR));\n\tif (namespaced && !dirs.includes(namespaced)) dirs.push(namespaced);\n\treturn dirs;\n}\n\n/**\n * Canvas extensions a plugin ships (see `docs/canvas-extensions-design.md` §4.3).\n *\n * Discovery keys off `<dir>/extension.mjs` and nothing else, exactly as\n * `core/canvas/discovery.ts` does for the workspace and user search roots — the\n * entry file is the whole contract, so a plugin's canvases are found by the same\n * rule as everyone else's.\n *\n * A plugin whose *root* carries `extension.mjs` is itself one canvas extension,\n * which is how a single-canvas repository is laid out; its id is the plugin id,\n * since there is no directory name below the root to take one from.\n */\nexport function detectCanvasExtensions(\n\troot: string,\n\tpluginId: string,\n\toverride: unknown,\n): PluginCanvasExtension[] | undefined {\n\tconst found: PluginCanvasExtension[] = [];\n\tconst seen = new Set<string>();\n\tconst add = (id: string, dir: string): void => {\n\t\tif (seen.has(id)) return;\n\t\tif (!fs.existsSync(path.join(dir, CANVAS_ENTRY_FILE))) return;\n\t\tseen.add(id);\n\t\tfound.push({ id, dir });\n\t};\n\n\tadd(pluginId, root);\n\tfor (const container of canvasContainerDirs(root, override)) {\n\t\tlet entries: fs.Dirent[];\n\t\ttry {\n\t\t\tentries = fs.readdirSync(container, { withFileTypes: true });\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n\t\t\tif (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n\t\t\tadd(entry.name, path.join(container, entry.name));\n\t\t}\n\t}\n\treturn found.length > 0 ? found : undefined;\n}\n\n/**\n * On-disk component surfaces hoocode does not load, checked against both vendors'\n * file-location tables. The files are left alone; naming them is what makes the\n * gap visible (see NormalizedPlugin.unsupportedSurfaces).\n */\nconst UNSUPPORTED_SURFACES: ReadonlyArray<{ rel: string; label: string }> = [\n\t{ rel: \"workflows\", label: \"workflows/\" },\n\t{ rel: \"output-styles\", label: \"output-styles/\" },\n\t{ rel: \"monitors/monitors.json\", label: \"monitors/\" },\n\t{ rel: \"bin\", label: \"bin/\" },\n\t{ rel: \"settings.json\", label: \"settings.json\" },\n\t{ rel: \".lsp.json\", label: \".lsp.json\" },\n\t{ rel: \"lsp.json\", label: \"lsp.json\" },\n\t{ rel: path.join(\".github\", \"lsp.json\"), label: \".github/lsp.json\" },\n];\n\n/** Which unsupported surfaces are present under `root`. */\nexport function detectUnsupportedSurfaces(root: string): string[] | undefined {\n\tconst found = UNSUPPORTED_SURFACES.filter((s) => fs.existsSync(path.join(root, s.rel))).map((s) => s.label);\n\treturn found.length > 0 ? found : undefined;\n}\n\nexport function readJson<T>(file: string): T | null {\n\ttry {\n\t\treturn JSON.parse(fs.readFileSync(file, \"utf8\")) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function dirIfExists(root: string, name: string): string | undefined {\n\tconst p = path.join(root, name);\n\treturn fs.existsSync(p) && fs.statSync(p).isDirectory() ? p : undefined;\n}\n\n/**\n * Resolve a capability directory: an explicit manifest override — a path (or\n * list of paths, first existing wins) relative to the plugin root, e.g.\n * `\"skills\": \"./skills/\"` — beats the conventional directory.\n */\nexport function resolveCapabilityDir(root: string, override: unknown, conventional: string): string | undefined {\n\tconst candidates = Array.isArray(override) ? override : [override];\n\tfor (const c of candidates) {\n\t\tif (typeof c !== \"string\" || !c.trim()) continue;\n\t\tconst p = path.resolve(root, c.trim());\n\t\tif (fs.existsSync(p) && fs.statSync(p).isDirectory()) return p;\n\t}\n\treturn dirIfExists(root, conventional);\n}\n\n/** Coerce an author field (string or `{ name }`) to a plain string. */\nexport function parseAuthor(author: RawManifest[\"author\"]): string | undefined {\n\treturn typeof author === \"string\" ? author : author?.name;\n}\n\n/** Accept either `{ hooks: {...} }` or a bare event map, falling back to `hooks/hooks.json`. */\nexport function normalizeHooks(raw: RawManifest[\"hooks\"], root: string): PluginHooksConfig | undefined {\n\tlet config: PluginHooksConfig | undefined;\n\tif (raw && typeof raw === \"object\") {\n\t\tconfig = \"hooks\" in raw && raw.hooks ? (raw.hooks as PluginHooksConfig) : (raw as PluginHooksConfig);\n\t}\n\t// Fall back to the conventional hooks/hooks.json file.\n\tif (!config) {\n\t\tconst hooksFile = path.join(root, \"hooks\", \"hooks.json\");\n\t\tif (fs.existsSync(hooksFile)) {\n\t\t\tconst fileRaw = readJson<RawManifest[\"hooks\"]>(hooksFile);\n\t\t\tif (fileRaw && typeof fileRaw === \"object\") {\n\t\t\t\tconfig =\n\t\t\t\t\t\"hooks\" in fileRaw && fileRaw.hooks\n\t\t\t\t\t\t? (fileRaw.hooks as PluginHooksConfig)\n\t\t\t\t\t\t: (fileRaw as PluginHooksConfig);\n\t\t\t}\n\t\t}\n\t}\n\treturn config && Object.keys(config).length > 0 ? config : undefined;\n}\n\n/**\n * Resolve inline `mcpServers`, a manifest-supplied file path, or a `.mcp.json`\n * file at `root`.\n *\n * `raw` may be:\n * - a string path (Claude Code form: `\"mcpServers\": \"./.mcp.json\"`), resolved\n * relative to the plugin root and read as a server file;\n * - an inline server map (returned as-is);\n * - undefined, falling back to `<root>/<mcpFileName>`.\n *\n * Server files use `{ mcpServers }` (Claude/native) or `{ servers }` (Code/Copilot);\n * both keys are accepted.\n */\nexport function normalizeMcp(\n\traw: Record<string, unknown> | string | undefined,\n\troot: string,\n\tmcpFileName = \".mcp.json\",\n): Record<string, unknown> | undefined {\n\t// Claude Code form: a path to a server file, relative to the plugin root.\n\tif (typeof raw === \"string\") {\n\t\treturn raw.trim() ? readMcpFile(path.resolve(root, raw.trim())) : undefined;\n\t}\n\tif (raw && Object.keys(raw).length > 0) return raw;\n\treturn readMcpFile(path.join(root, mcpFileName));\n}\n\n/** Read a server file, accepting both `{ mcpServers }` and `{ servers }` keys. */\nfunction readMcpFile(mcpFile: string): Record<string, unknown> | undefined {\n\tif (!fs.existsSync(mcpFile)) return undefined;\n\tconst fileRaw = readJson<{ mcpServers?: Record<string, unknown>; servers?: Record<string, unknown> }>(mcpFile);\n\tconst servers = fileRaw?.mcpServers ?? fileRaw?.servers;\n\treturn servers && Object.keys(servers).length > 0 ? servers : undefined;\n}\n\n// ============================================================================\n// Emit helpers (used by the writer / scaffolding half of each adapter)\n// ============================================================================\n\n/** Serialize a small set of frontmatter fields to YAML. Values are strings only. */\n/**\n * Render frontmatter, or nothing at all when every field is empty.\n *\n * Emitting bare `---\\n---` looks harmless and is not: YAML parses an empty\n * document as `null`, and Claude Code rejects a component whose frontmatter is\n * not a mapping. A command authored without a description hit exactly that, and\n * the artifact was invalid in the ecosystem it was written for while\n * round-tripping happily through our own reader.\n */\nfunction emitFrontmatter(fields: Record<string, string | undefined>): string {\n\tconst lines: string[] = [];\n\tfor (const [key, value] of Object.entries(fields)) {\n\t\tif (value === undefined || value === \"\") continue;\n\t\t// Quote values that could be misparsed as YAML (contain a colon-space or start punctuation).\n\t\tconst needsQuote = /[:#]|^[\\s>|@`&*!%]/.test(value) || value.includes(\"\\n\");\n\t\tlines.push(`${key}: ${needsQuote ? JSON.stringify(value) : value}`);\n\t}\n\treturn lines.length > 0 ? [\"---\", ...lines, \"---\"].join(\"\\n\") : \"\";\n}\n\n/** A markdown capability file: frontmatter block + body. */\nexport function emitMarkdown(fields: Record<string, string | undefined>, body: string): string {\n\tconst frontmatter = emitFrontmatter(fields);\n\treturn frontmatter ? `${frontmatter}\\n\\n${body.trimEnd()}\\n` : `${body.trimEnd()}\\n`;\n}\n\n/** Pretty-print a JSON manifest with a trailing newline (matches repo convention). */\nexport function emitJson(value: unknown): string {\n\treturn `${JSON.stringify(value, null, 2)}\\n`;\n}\n\n/** Convert authored hooks into the on-disk `hooks.json` event-map shape shared by all formats. */\nexport function authoredHooksToConfig(hooks: AuthoredHook[]): Record<string, unknown> {\n\tconst byEvent: Record<string, Array<{ matcher?: string; hooks: unknown[] }>> = {};\n\tfor (const h of hooks) {\n\t\tconst group = byEvent[h.event] ?? [];\n\t\tbyEvent[h.event] = group;\n\t\tgroup.push({\n\t\t\t...(h.matcher ? { matcher: h.matcher } : {}),\n\t\t\thooks: [{ type: \"command\", command: h.command, ...(h.timeout ? { timeout: h.timeout } : {}) }],\n\t\t});\n\t}\n\treturn byEvent;\n}\n\n/** Slug-safe filename component (no path separators, conservative charset). */\nexport function slug(name: string): string {\n\treturn name\n\t\t.trim()\n\t\t.replace(/[^a-zA-Z0-9._-]+/g, \"-\")\n\t\t.replace(/^-+|-+$/g, \"\")\n\t\t.slice(0, 80);\n}\n\n/**\n * Render a comma-separated tool allowlist (Claude Code convention, e.g.\n * \"read, grep\") as a YAML flow sequence (`['read', 'grep']`) for formats whose\n * frontmatter takes tools as a list (Copilot custom agents / prompt files).\n */\nexport function toolsYamlList(tools: string | undefined): string | undefined {\n\tconst items = (tools ?? \"\")\n\t\t.split(/[,\\s]+/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\tif (items.length === 0) return undefined;\n\treturn `[${items.map((t) => `'${t.replace(/'/g, \"''\")}'`).join(\", \")}]`;\n}\n\n/**\n * The workspace layout shared by the `.agents/` and `.claude/` conventions:\n * `<root>/skills/<name>/SKILL.md`, `<root>/agents/<name>.md`,\n * `<root>/commands/<name>.md`. Copilot's differs and lives in its adapter.\n */\nexport function claudeStyleWorkspace(root: string): WorkspaceLayout {\n\treturn {\n\t\troot,\n\t\temitSkill: (s) => ({\n\t\t\tpath: path.join(root, \"skills\", slug(s.name), \"SKILL.md\"),\n\t\t\tcontent: emitMarkdown({ name: s.name, description: s.description }, s.body),\n\t\t}),\n\t\temitAgent: (a) => ({\n\t\t\tpath: path.join(root, \"agents\", `${slug(a.name)}.md`),\n\t\t\tcontent: emitMarkdown({ name: a.name, description: a.description, tools: a.tools, model: a.model }, a.body),\n\t\t}),\n\t\temitCommand: (c) => ({\n\t\t\tpath: path.join(root, \"commands\", `${slug(c.name)}.md`),\n\t\t\tcontent: emitMarkdown({ name: c.name, description: c.description }, c.body),\n\t\t}),\n\t};\n}\n\n/** The manifest keys the adapters model, as a sorted list. Input to the drift check (§2.2). */\nexport function modelledManifestKeys(): string[] {\n\treturn [...MODELLED_MANIFEST_KEYS].sort();\n}\n\n/**\n * Surfaces we know about and deliberately do not load, as the **relative paths**\n * they actually occupy rather than their display labels.\n *\n * The distinction bit once already: the labels are written for humans\n * (`\"monitors/\"`), the vendor reference writes the real path\n * (`monitors/monitors.json`), and a drift check comparing the two reported a\n * known surface as a new finding.\n */\nexport function knownUnsupportedSurfaces(): string[] {\n\treturn UNSUPPORTED_SURFACES.map((s) => s.rel.replace(/\\\\/g, \"/\")).sort();\n}\n"]}
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/shared.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared, format-agnostic helpers used by the plugin format adapters.\n *\n * Kept deliberately free of any runtime dependency on `../manifest.js` (it only\n * imports *types* from there) so the adapter registry can be wired without a\n * module cycle: `manifest.ts → formats/index.ts → formats/<adapter>.ts →\n * shared.ts`, with the back-reference to manifest types erased at compile time.\n */\n\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { CANVAS_ENTRY_FILE } from \"../../../canvas/discovery.js\";\nimport type { PluginCanvasExtension, PluginHooksConfig } from \"../manifest.js\";\nimport type { AuthoredHook, WorkspaceLayout } from \"./types.js\";\n\n/** Raw manifest shape accepted by the `plugin.json`-style formats (agents/claude/copilot). */\nexport interface RawManifest {\n\tname?: string;\n\tversion?: string;\n\tdescription?: string;\n\tauthor?: string | { name?: string };\n\t/** Optional capability-dir override(s): a path (or list of paths) relative to the plugin root, e.g. `\"skills\": \"./skills/\"`. */\n\tskills?: unknown;\n\tcommands?: unknown;\n\tagents?: unknown;\n\tthemes?: unknown;\n\thooks?: PluginHooksConfig | { hooks?: PluginHooksConfig };\n\t/** Inline server map, or a path (Claude Code form, e.g. `\"./.mcp.json\"`) relative to the plugin root. */\n\tmcpServers?: Record<string, unknown> | string;\n\t/** Native-only. */\n\tproviders?: unknown;\n\t/**\n\t * Copilot: canvas-extension directory (a path, or list of paths, relative to\n\t * the plugin root — e.g. `\"extensions\": \"extensions\"`). The Agent Plugins spec\n\t * gives the same key a second, unrelated meaning: a map of vendor metadata\n\t * namespaces (`{ \"com.github.copilot\": { logo } }`). Both readings are handled\n\t * — see {@link detectCanvasExtensions} — and the map form is preserved\n\t * verbatim through `unknownFields`.\n\t */\n\textensions?: unknown;\n\t/** Copilot: LSP config path or inline definitions. Parsed for preservation only. */\n\tlspServers?: unknown;\n\t/** Any key the adapter does not model. */\n\t[key: string]: unknown;\n}\n\n/**\n * Manifest keys every adapter models; anything else is preserved via\n * `unknownFields`.\n *\n * Surfaced through {@link declaredVocabulary} so the Tier 2 drift check has\n * something to diff the vendor references against. A checker that inferred our\n * coverage by reading the parser would be checking its own inference; a declared\n * set is a claim the codebase makes and the check can falsify.\n */\nconst MODELLED_MANIFEST_KEYS = new Set([\n\t\"name\",\n\t\"version\",\n\t\"description\",\n\t\"author\",\n\t\"skills\",\n\t\"commands\",\n\t\"agents\",\n\t\"themes\",\n\t\"hooks\",\n\t\"mcpServers\",\n\t\"providers\",\n\t\"$schema\",\n]);\n\n/** Manifest keys not modelled here, preserved verbatim so a re-emit cannot drop them. */\nexport function unknownManifestFields(raw: RawManifest): Record<string, unknown> | undefined {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [key, value] of Object.entries(raw)) {\n\t\tif (!MODELLED_MANIFEST_KEYS.has(key)) out[key] = value;\n\t}\n\treturn Object.keys(out).length > 0 ? out : undefined;\n}\n\n/**\n * Vendor content namespace directory. The Agent Plugins layout both vendors are\n * converging on keeps portable capabilities at the plugin root (`skills/`) and\n * puts vendor-specific ones under a reverse-DNS directory, so Copilot's agents\n * and canvas extensions ship as `com.github.copilot/<capability>/`.\n * `github/awesome-copilot` publishes its whole catalog this way.\n */\nexport const COPILOT_CONTENT_DIR = \"com.github.copilot\";\n\n/** Conventional canvas-extension container, relative to a plugin root. */\nconst CANVAS_EXTENSIONS_DIR = \"extensions\";\n\n/**\n * Canvas-extension containers a plugin may ship, starting with the manifest's own\n * `extensions` path (Copilot's key, e.g. `\"extensions\": \"extensions\"`). Both are\n * real: `extensions/` is what a standalone canvas plugin uses, and the namespaced\n * one is what a materialized `awesome-copilot` entry carries.\n */\nfunction canvasContainerDirs(root: string, override: unknown): string[] {\n\tconst dirs: string[] = [];\n\t// `extensions` is also the key the Agent Plugins spec uses for a *map* of\n\t// vendor metadata (`{ \"com.github.copilot\": { logo } }`). `resolveCapabilityDir`\n\t// ignores anything that is not a string or string array, so the two readings\n\t// of one key cannot collide — and the map form stays in `unknownFields`, which\n\t// is what keeps a re-emit from dropping it.\n\tconst declared = resolveCapabilityDir(root, override, CANVAS_EXTENSIONS_DIR);\n\tif (declared) dirs.push(declared);\n\tconst namespaced = dirIfExists(root, path.join(COPILOT_CONTENT_DIR, CANVAS_EXTENSIONS_DIR));\n\tif (namespaced && !dirs.includes(namespaced)) dirs.push(namespaced);\n\treturn dirs;\n}\n\n/**\n * Canvas extensions a plugin ships (see `docs/canvas-extensions-design.md` §4.3).\n *\n * Discovery keys off `<dir>/extension.mjs` and nothing else, exactly as\n * `core/canvas/discovery.ts` does for the workspace and user search roots — the\n * entry file is the whole contract, so a plugin's canvases are found by the same\n * rule as everyone else's.\n *\n * A plugin whose *root* carries `extension.mjs` is itself one canvas extension,\n * which is how a single-canvas repository is laid out; its id is the plugin id,\n * since there is no directory name below the root to take one from.\n */\nexport function detectCanvasExtensions(\n\troot: string,\n\tpluginId: string,\n\toverride: unknown,\n): PluginCanvasExtension[] | undefined {\n\tconst found: PluginCanvasExtension[] = [];\n\tconst seen = new Set<string>();\n\tconst add = (id: string, dir: string): void => {\n\t\tif (seen.has(id)) return;\n\t\tif (!fs.existsSync(path.join(dir, CANVAS_ENTRY_FILE))) return;\n\t\tseen.add(id);\n\t\tfound.push({ id, dir });\n\t};\n\n\tadd(pluginId, root);\n\tfor (const container of canvasContainerDirs(root, override)) {\n\t\tlet entries: fs.Dirent[];\n\t\ttry {\n\t\t\tentries = fs.readdirSync(container, { withFileTypes: true });\n\t\t} catch {\n\t\t\tcontinue;\n\t\t}\n\t\tfor (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {\n\t\t\tif (!entry.isDirectory() && !entry.isSymbolicLink()) continue;\n\t\t\tadd(entry.name, path.join(container, entry.name));\n\t\t}\n\t}\n\treturn found.length > 0 ? found : undefined;\n}\n\n/**\n * On-disk component surfaces hoocode does not load, checked against both vendors'\n * file-location tables. The files are left alone; naming them is what makes the\n * gap visible (see NormalizedPlugin.unsupportedSurfaces).\n */\nconst UNSUPPORTED_SURFACES: ReadonlyArray<{ rel: string; label: string }> = [\n\t{ rel: \"workflows\", label: \"workflows/\" },\n\t{ rel: \"output-styles\", label: \"output-styles/\" },\n\t{ rel: \"monitors/monitors.json\", label: \"monitors/\" },\n\t{ rel: \"bin\", label: \"bin/\" },\n\t{ rel: \"settings.json\", label: \"settings.json\" },\n\t{ rel: \".lsp.json\", label: \".lsp.json\" },\n\t{ rel: \"lsp.json\", label: \"lsp.json\" },\n\t{ rel: path.join(\".github\", \"lsp.json\"), label: \".github/lsp.json\" },\n];\n\n/** Which unsupported surfaces are present under `root`. */\nexport function detectUnsupportedSurfaces(root: string): string[] | undefined {\n\tconst found = UNSUPPORTED_SURFACES.filter((s) => fs.existsSync(path.join(root, s.rel))).map((s) => s.label);\n\treturn found.length > 0 ? found : undefined;\n}\n\nexport function readJson<T>(file: string): T | null {\n\ttry {\n\t\treturn JSON.parse(fs.readFileSync(file, \"utf8\")) as T;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function dirIfExists(root: string, name: string): string | undefined {\n\tconst p = path.join(root, name);\n\treturn fs.existsSync(p) && fs.statSync(p).isDirectory() ? p : undefined;\n}\n\n/**\n * Resolve a capability directory: an explicit manifest override — a path (or\n * list of paths, first existing wins) relative to the plugin root, e.g.\n * `\"skills\": \"./skills/\"` — beats the conventional directory.\n */\nexport function resolveCapabilityDir(root: string, override: unknown, conventional: string): string | undefined {\n\tconst candidates = Array.isArray(override) ? override : [override];\n\tfor (const c of candidates) {\n\t\tif (typeof c !== \"string\" || !c.trim()) continue;\n\t\tconst p = path.resolve(root, c.trim());\n\t\tif (fs.existsSync(p) && fs.statSync(p).isDirectory()) return p;\n\t}\n\treturn dirIfExists(root, conventional);\n}\n\n/** Coerce an author field (string or `{ name }`) to a plain string. */\nexport function parseAuthor(author: RawManifest[\"author\"]): string | undefined {\n\treturn typeof author === \"string\" ? author : author?.name;\n}\n\n/** Accept either `{ hooks: {...} }` or a bare event map, falling back to `hooks/hooks.json`. */\nexport function normalizeHooks(raw: RawManifest[\"hooks\"], root: string): PluginHooksConfig | undefined {\n\tlet config: PluginHooksConfig | undefined;\n\tif (raw && typeof raw === \"object\") {\n\t\tconfig = \"hooks\" in raw && raw.hooks ? (raw.hooks as PluginHooksConfig) : (raw as PluginHooksConfig);\n\t}\n\t// Fall back to the conventional hooks/hooks.json file.\n\tif (!config) {\n\t\tconst hooksFile = path.join(root, \"hooks\", \"hooks.json\");\n\t\tif (fs.existsSync(hooksFile)) {\n\t\t\tconst fileRaw = readJson<RawManifest[\"hooks\"]>(hooksFile);\n\t\t\tif (fileRaw && typeof fileRaw === \"object\") {\n\t\t\t\tconfig =\n\t\t\t\t\t\"hooks\" in fileRaw && fileRaw.hooks\n\t\t\t\t\t\t? (fileRaw.hooks as PluginHooksConfig)\n\t\t\t\t\t\t: (fileRaw as PluginHooksConfig);\n\t\t\t}\n\t\t}\n\t}\n\treturn config && Object.keys(config).length > 0 ? config : undefined;\n}\n\n/**\n * Resolve inline `mcpServers`, a manifest-supplied file path, or a `.mcp.json`\n * file at `root`.\n *\n * `raw` may be:\n * - a string path (Claude Code form: `\"mcpServers\": \"./.mcp.json\"`), resolved\n * relative to the plugin root and read as a server file;\n * - an inline server map (returned as-is);\n * - undefined, falling back to `<root>/<mcpFileName>`.\n *\n * Server files use `{ mcpServers }` (Claude/native) or `{ servers }` (Code/Copilot);\n * both keys are accepted.\n */\nexport function normalizeMcp(\n\traw: Record<string, unknown> | string | undefined,\n\troot: string,\n\tmcpFileName = \".mcp.json\",\n): Record<string, unknown> | undefined {\n\t// Claude Code form: a path to a server file, relative to the plugin root.\n\tif (typeof raw === \"string\") {\n\t\treturn raw.trim() ? readMcpFile(path.resolve(root, raw.trim())) : undefined;\n\t}\n\tif (raw && Object.keys(raw).length > 0) return raw;\n\treturn readMcpFile(path.join(root, mcpFileName));\n}\n\n/** Read a server file, accepting both `{ mcpServers }` and `{ servers }` keys. */\nfunction readMcpFile(mcpFile: string): Record<string, unknown> | undefined {\n\tif (!fs.existsSync(mcpFile)) return undefined;\n\tconst fileRaw = readJson<{ mcpServers?: Record<string, unknown>; servers?: Record<string, unknown> }>(mcpFile);\n\tconst servers = fileRaw?.mcpServers ?? fileRaw?.servers;\n\treturn servers && Object.keys(servers).length > 0 ? servers : undefined;\n}\n\n// ============================================================================\n// Emit helpers (used by the writer / scaffolding half of each adapter)\n// ============================================================================\n\n/** Serialize a small set of frontmatter fields to YAML. Values are strings only. */\n/**\n * Render frontmatter, or nothing at all when every field is empty.\n *\n * Emitting bare `---\\n---` looks harmless and is not: YAML parses an empty\n * document as `null`, and Claude Code rejects a component whose frontmatter is\n * not a mapping. A command authored without a description hit exactly that, and\n * the artifact was invalid in the ecosystem it was written for while\n * round-tripping happily through our own reader.\n */\nfunction emitFrontmatter(fields: Record<string, string | undefined>): string {\n\tconst lines: string[] = [];\n\tfor (const [key, value] of Object.entries(fields)) {\n\t\tif (value === undefined || value === \"\") continue;\n\t\t// Quote values that could be misparsed as YAML (contain a colon-space or start punctuation).\n\t\tconst needsQuote = /[:#]|^[\\s>|@`&*!%]/.test(value) || value.includes(\"\\n\");\n\t\tlines.push(`${key}: ${needsQuote ? JSON.stringify(value) : value}`);\n\t}\n\treturn lines.length > 0 ? [\"---\", ...lines, \"---\"].join(\"\\n\") : \"\";\n}\n\n/** A markdown capability file: frontmatter block + body. */\nexport function emitMarkdown(fields: Record<string, string | undefined>, body: string): string {\n\tconst frontmatter = emitFrontmatter(fields);\n\treturn frontmatter ? `${frontmatter}\\n\\n${body.trimEnd()}\\n` : `${body.trimEnd()}\\n`;\n}\n\n/** Pretty-print a JSON manifest with a trailing newline (matches repo convention). */\nexport function emitJson(value: unknown): string {\n\treturn `${JSON.stringify(value, null, 2)}\\n`;\n}\n\n/** Convert authored hooks into the on-disk `hooks.json` event-map shape shared by all formats. */\nexport function authoredHooksToConfig(hooks: AuthoredHook[]): Record<string, unknown> {\n\tconst byEvent: Record<string, Array<{ matcher?: string; hooks: unknown[] }>> = {};\n\tfor (const h of hooks) {\n\t\tconst group = byEvent[h.event] ?? [];\n\t\tbyEvent[h.event] = group;\n\t\tgroup.push({\n\t\t\t...(h.matcher ? { matcher: h.matcher } : {}),\n\t\t\thooks: [{ type: \"command\", command: h.command, ...(h.timeout ? { timeout: h.timeout } : {}) }],\n\t\t});\n\t}\n\treturn byEvent;\n}\n\n/** Slug-safe filename component (no path separators, conservative charset). */\nexport function slug(name: string): string {\n\treturn name\n\t\t.trim()\n\t\t.replace(/[^a-zA-Z0-9._-]+/g, \"-\")\n\t\t.replace(/^-+|-+$/g, \"\")\n\t\t.slice(0, 80);\n}\n\n/**\n * Render a comma-separated tool allowlist (Claude Code convention, e.g.\n * \"read, search\") as a YAML flow sequence (`['read', 'search']`) for formats whose\n * frontmatter takes tools as a list (Copilot custom agents / prompt files).\n */\nexport function toolsYamlList(tools: string | undefined): string | undefined {\n\tconst items = (tools ?? \"\")\n\t\t.split(/[,\\s]+/)\n\t\t.map((t) => t.trim())\n\t\t.filter(Boolean);\n\tif (items.length === 0) return undefined;\n\treturn `[${items.map((t) => `'${t.replace(/'/g, \"''\")}'`).join(\", \")}]`;\n}\n\n/**\n * The workspace layout shared by the `.agents/` and `.claude/` conventions:\n * `<root>/skills/<name>/SKILL.md`, `<root>/agents/<name>.md`,\n * `<root>/commands/<name>.md`. Copilot's differs and lives in its adapter.\n */\nexport function claudeStyleWorkspace(root: string): WorkspaceLayout {\n\treturn {\n\t\troot,\n\t\temitSkill: (s) => ({\n\t\t\tpath: path.join(root, \"skills\", slug(s.name), \"SKILL.md\"),\n\t\t\tcontent: emitMarkdown({ name: s.name, description: s.description }, s.body),\n\t\t}),\n\t\temitAgent: (a) => ({\n\t\t\tpath: path.join(root, \"agents\", `${slug(a.name)}.md`),\n\t\t\tcontent: emitMarkdown({ name: a.name, description: a.description, tools: a.tools, model: a.model }, a.body),\n\t\t}),\n\t\temitCommand: (c) => ({\n\t\t\tpath: path.join(root, \"commands\", `${slug(c.name)}.md`),\n\t\t\tcontent: emitMarkdown({ name: c.name, description: c.description }, c.body),\n\t\t}),\n\t};\n}\n\n/** The manifest keys the adapters model, as a sorted list. Input to the drift check (§2.2). */\nexport function modelledManifestKeys(): string[] {\n\treturn [...MODELLED_MANIFEST_KEYS].sort();\n}\n\n/**\n * Surfaces we know about and deliberately do not load, as the **relative paths**\n * they actually occupy rather than their display labels.\n *\n * The distinction bit once already: the labels are written for humans\n * (`\"monitors/\"`), the vendor reference writes the real path\n * (`monitors/monitors.json`), and a drift check comparing the two reported a\n * known surface as a new finding.\n */\nexport function knownUnsupportedSurfaces(): string[] {\n\treturn UNSUPPORTED_SURFACES.map((s) => s.rel.replace(/\\\\/g, \"/\")).sort();\n}\n"]}
@@ -47,7 +47,7 @@ interface AuthoredCommand {
47
47
  interface AuthoredAgent {
48
48
  name: string;
49
49
  description?: string;
50
- /** Comma-separated `allowed-tools` string, e.g. "read, grep, glob". */
50
+ /** Comma-separated `allowed-tools` string, e.g. "read, search". */
51
51
  tools?: string;
52
52
  model?: string;
53
53
  /** System-prompt / instruction body (markdown). */
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/types.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plugin format adapter contract.\n *\n * A `PluginFormatAdapter` owns *everything* format-specific for one vendor\n * layout — how a plugin directory is detected and parsed (the reader), how a\n * marketplace index file is located, and how a plugin is scaffolded from a\n * normalized draft (the writer). The rest of the plugin subsystem is written\n * against {@link NormalizedPlugin} / {@link PluginDraft} and never branches on a\n * format again.\n *\n * This is the extension point the plugin system is designed around: Claude Code\n * and GitHub Copilot conventions evolve independently, so each lives in its own\n * adapter file ({@link ./claude.ts}, {@link ./copilot.ts}, {@link ./agents.ts}).\n * Supporting a new vendor — or tracking a change in an existing one — means\n * editing (or adding) exactly one adapter and registering it; no other module\n * changes.\n */\n\nimport type { NormalizedPlugin } from \"../manifest.js\";\n\n/** Internal format id — matches `NormalizedPlugin.format` / `NormalizedMarketplace.format`. */\nexport type PluginFormatId = \"agents\" | \"claude\" | \"copilot\";\n\n/**\n * Public platform token surfaced to users. The Copilot format lives under\n * `.github/`, so it is surfaced as `\"github\"` rather than the internal\n * `\"copilot\"`.\n */\nexport type MarketplacePlatform = \"agents\" | \"claude\" | \"github\";\n\n/** A file produced by a format's scaffolder. `path` is relative to the plugin root (POSIX). */\nexport interface EmittedFile {\n\tpath: string;\n\tcontent: string;\n}\n\n/** An authored skill: passive instructions loaded lazily (SKILL.md-style). */\ninterface AuthoredSkill {\n\tname: string;\n\tdescription?: string;\n\t/** Instruction body (markdown). */\n\tbody: string;\n}\n\n/** An authored slash command: a passive prompt template. */\ninterface AuthoredCommand {\n\tname: string;\n\tdescription?: string;\n\t/** Prompt template body (markdown). */\n\tbody: string;\n}\n\n/** An authored subagent definition. `tools` is a comma-separated allowlist (Claude Code convention). */\ninterface AuthoredAgent {\n\tname: string;\n\tdescription?: string;\n\t/** Comma-separated `allowed-tools` string, e.g. \"read, grep, glob\". */\n\ttools?: string;\n\tmodel?: string;\n\t/** System-prompt / instruction body (markdown). */\n\tbody: string;\n}\n\n/** An authored shell hook wired to a tool event. Active code — gated on authoring. */\nexport interface AuthoredHook {\n\t/** Claude Code event name: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, Stop, ... */\n\tevent: string;\n\t/** Regex matched against the tool name. Empty / \"*\" matches everything. */\n\tmatcher?: string;\n\tcommand: string;\n\t/** Timeout in seconds. */\n\ttimeout?: number;\n}\n\n/** An authored MCP server. Active code — gated on authoring. */\nexport interface AuthoredMcpServer {\n\tname: string;\n\tcommand: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n}\n\n/**\n * Format-agnostic authoring spec consumed by {@link PluginFormatAdapter.emit}.\n * `ProposePlugin` builds one of these and asks each requested adapter to render\n * it, so the same authored capability lands correctly in Claude Code and\n * Copilot layouts without the authoring code knowing either.\n */\nexport interface PluginDraft {\n\tid: string;\n\tversion?: string;\n\tdescription?: string;\n\tauthor?: string;\n\t/**\n\t * Which platform layouts to scaffold this draft into (e.g. `[\"claude\",\n\t * \"github\"]`). Consumed as the default target set by `emitForPlatforms`;\n\t * omit to render every registered format.\n\t */\n\tsupportPlatform?: MarketplacePlatform[];\n\tskills?: AuthoredSkill[];\n\tcommands?: AuthoredCommand[];\n\tagents?: AuthoredAgent[];\n\thooks?: AuthoredHook[];\n\tmcpServers?: AuthoredMcpServer[];\n\t/**\n\t * Manifest keys carried through from an existing plugin that this codebase\n\t * does not model (see {@link NormalizedPlugin.unknownFields}). Emitters write\n\t * them back verbatim so editing a plugin never strips a vendor key we happen\n\t * not to understand. Never set when authoring from scratch.\n\t */\n\tunknownFields?: Record<string, unknown>;\n}\n\n/**\n * Writer for a platform's *workspace-level* (non-plugin) artifact conventions —\n * where a standalone skill, subagent, or command lives inside a repository for\n * that vendor (e.g. Copilot reads `.github/skills/<name>/SKILL.md`,\n * `.github/agents/<name>.agent.md`, `.github/prompts/<name>.prompt.md`).\n * Unlike {@link PluginFormatAdapter.emit}, the returned paths are relative to\n * the **workspace root** (cwd), marker directory included.\n */\nexport interface WorkspaceLayout {\n\t/** Marker root the artifacts land under, e.g. \".github\", \".claude\", \".agents\". */\n\treadonly root: string;\n\temitSkill(skill: AuthoredSkill): EmittedFile;\n\temitAgent(agent: AuthoredAgent): EmittedFile;\n\temitCommand(command: AuthoredCommand): EmittedFile;\n}\n\n/** Reader + writer for a single plugin format. */\nexport interface PluginFormatAdapter {\n\t/** Internal format id (stable; used in `NormalizedPlugin.format`). */\n\treadonly id: PluginFormatId;\n\t/** Public platform token (Copilot → `\"github\"`). */\n\treadonly platform: MarketplacePlatform;\n\t/**\n\t * Precedence when several formats coexist in one directory (lower wins).\n\t * Native `.agents-plugin` beats Claude beats Copilot.\n\t */\n\treadonly precedence: number;\n\t/** Short human label for messages and scaffolding summaries. */\n\treadonly label: string;\n\t/**\n\t * Candidate locations of this format's marketplace index file, relative to a\n\t * marketplace root (POSIX), in precedence order. Formats with more than one\n\t * real-world convention (Copilot uses both `.github/plugin/marketplace.json`\n\t * and `.github/marketplace.json`) list every location they accept.\n\t */\n\treadonly marketplaceFiles: readonly string[];\n\n\t/** True if `root` is a plugin of this format — including, where the vendor allows it, without a manifest. */\n\tdetectPlugin(root: string): boolean;\n\t/** True only if `root` carries this format's manifest *file*, ignoring manifest-optional rules. */\n\thasManifest(root: string): boolean;\n\t/** Parse `root` as a plugin of this format. Returns null when unparseable. */\n\tparsePlugin(root: string): NormalizedPlugin | null;\n\t/** Render `draft` into this format's on-disk layout (paths relative to the plugin root). */\n\temit(draft: PluginDraft): EmittedFile[];\n\t/** This platform's workspace-level artifact conventions (paths relative to the workspace root). */\n\treadonly workspace: WorkspaceLayout;\n}\n"]}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/types.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Plugin format adapter contract.\n *\n * A `PluginFormatAdapter` owns *everything* format-specific for one vendor\n * layout — how a plugin directory is detected and parsed (the reader), how a\n * marketplace index file is located, and how a plugin is scaffolded from a\n * normalized draft (the writer). The rest of the plugin subsystem is written\n * against {@link NormalizedPlugin} / {@link PluginDraft} and never branches on a\n * format again.\n *\n * This is the extension point the plugin system is designed around: Claude Code\n * and GitHub Copilot conventions evolve independently, so each lives in its own\n * adapter file ({@link ./claude.ts}, {@link ./copilot.ts}, {@link ./agents.ts}).\n * Supporting a new vendor — or tracking a change in an existing one — means\n * editing (or adding) exactly one adapter and registering it; no other module\n * changes.\n */\n\nimport type { NormalizedPlugin } from \"../manifest.js\";\n\n/** Internal format id — matches `NormalizedPlugin.format` / `NormalizedMarketplace.format`. */\nexport type PluginFormatId = \"agents\" | \"claude\" | \"copilot\";\n\n/**\n * Public platform token surfaced to users. The Copilot format lives under\n * `.github/`, so it is surfaced as `\"github\"` rather than the internal\n * `\"copilot\"`.\n */\nexport type MarketplacePlatform = \"agents\" | \"claude\" | \"github\";\n\n/** A file produced by a format's scaffolder. `path` is relative to the plugin root (POSIX). */\nexport interface EmittedFile {\n\tpath: string;\n\tcontent: string;\n}\n\n/** An authored skill: passive instructions loaded lazily (SKILL.md-style). */\ninterface AuthoredSkill {\n\tname: string;\n\tdescription?: string;\n\t/** Instruction body (markdown). */\n\tbody: string;\n}\n\n/** An authored slash command: a passive prompt template. */\ninterface AuthoredCommand {\n\tname: string;\n\tdescription?: string;\n\t/** Prompt template body (markdown). */\n\tbody: string;\n}\n\n/** An authored subagent definition. `tools` is a comma-separated allowlist (Claude Code convention). */\ninterface AuthoredAgent {\n\tname: string;\n\tdescription?: string;\n\t/** Comma-separated `allowed-tools` string, e.g. \"read, search\". */\n\ttools?: string;\n\tmodel?: string;\n\t/** System-prompt / instruction body (markdown). */\n\tbody: string;\n}\n\n/** An authored shell hook wired to a tool event. Active code — gated on authoring. */\nexport interface AuthoredHook {\n\t/** Claude Code event name: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, Stop, ... */\n\tevent: string;\n\t/** Regex matched against the tool name. Empty / \"*\" matches everything. */\n\tmatcher?: string;\n\tcommand: string;\n\t/** Timeout in seconds. */\n\ttimeout?: number;\n}\n\n/** An authored MCP server. Active code — gated on authoring. */\nexport interface AuthoredMcpServer {\n\tname: string;\n\tcommand: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n}\n\n/**\n * Format-agnostic authoring spec consumed by {@link PluginFormatAdapter.emit}.\n * `ProposePlugin` builds one of these and asks each requested adapter to render\n * it, so the same authored capability lands correctly in Claude Code and\n * Copilot layouts without the authoring code knowing either.\n */\nexport interface PluginDraft {\n\tid: string;\n\tversion?: string;\n\tdescription?: string;\n\tauthor?: string;\n\t/**\n\t * Which platform layouts to scaffold this draft into (e.g. `[\"claude\",\n\t * \"github\"]`). Consumed as the default target set by `emitForPlatforms`;\n\t * omit to render every registered format.\n\t */\n\tsupportPlatform?: MarketplacePlatform[];\n\tskills?: AuthoredSkill[];\n\tcommands?: AuthoredCommand[];\n\tagents?: AuthoredAgent[];\n\thooks?: AuthoredHook[];\n\tmcpServers?: AuthoredMcpServer[];\n\t/**\n\t * Manifest keys carried through from an existing plugin that this codebase\n\t * does not model (see {@link NormalizedPlugin.unknownFields}). Emitters write\n\t * them back verbatim so editing a plugin never strips a vendor key we happen\n\t * not to understand. Never set when authoring from scratch.\n\t */\n\tunknownFields?: Record<string, unknown>;\n}\n\n/**\n * Writer for a platform's *workspace-level* (non-plugin) artifact conventions —\n * where a standalone skill, subagent, or command lives inside a repository for\n * that vendor (e.g. Copilot reads `.github/skills/<name>/SKILL.md`,\n * `.github/agents/<name>.agent.md`, `.github/prompts/<name>.prompt.md`).\n * Unlike {@link PluginFormatAdapter.emit}, the returned paths are relative to\n * the **workspace root** (cwd), marker directory included.\n */\nexport interface WorkspaceLayout {\n\t/** Marker root the artifacts land under, e.g. \".github\", \".claude\", \".agents\". */\n\treadonly root: string;\n\temitSkill(skill: AuthoredSkill): EmittedFile;\n\temitAgent(agent: AuthoredAgent): EmittedFile;\n\temitCommand(command: AuthoredCommand): EmittedFile;\n}\n\n/** Reader + writer for a single plugin format. */\nexport interface PluginFormatAdapter {\n\t/** Internal format id (stable; used in `NormalizedPlugin.format`). */\n\treadonly id: PluginFormatId;\n\t/** Public platform token (Copilot → `\"github\"`). */\n\treadonly platform: MarketplacePlatform;\n\t/**\n\t * Precedence when several formats coexist in one directory (lower wins).\n\t * Native `.agents-plugin` beats Claude beats Copilot.\n\t */\n\treadonly precedence: number;\n\t/** Short human label for messages and scaffolding summaries. */\n\treadonly label: string;\n\t/**\n\t * Candidate locations of this format's marketplace index file, relative to a\n\t * marketplace root (POSIX), in precedence order. Formats with more than one\n\t * real-world convention (Copilot uses both `.github/plugin/marketplace.json`\n\t * and `.github/marketplace.json`) list every location they accept.\n\t */\n\treadonly marketplaceFiles: readonly string[];\n\n\t/** True if `root` is a plugin of this format — including, where the vendor allows it, without a manifest. */\n\tdetectPlugin(root: string): boolean;\n\t/** True only if `root` carries this format's manifest *file*, ignoring manifest-optional rules. */\n\thasManifest(root: string): boolean;\n\t/** Parse `root` as a plugin of this format. Returns null when unparseable. */\n\tparsePlugin(root: string): NormalizedPlugin | null;\n\t/** Render `draft` into this format's on-disk layout (paths relative to the plugin root). */\n\temit(draft: PluginDraft): EmittedFile[];\n\t/** This platform's workspace-level artifact conventions (paths relative to the workspace root). */\n\treadonly workspace: WorkspaceLayout;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG","sourcesContent":["/**\n * Plugin format adapter contract.\n *\n * A `PluginFormatAdapter` owns *everything* format-specific for one vendor\n * layout — how a plugin directory is detected and parsed (the reader), how a\n * marketplace index file is located, and how a plugin is scaffolded from a\n * normalized draft (the writer). The rest of the plugin subsystem is written\n * against {@link NormalizedPlugin} / {@link PluginDraft} and never branches on a\n * format again.\n *\n * This is the extension point the plugin system is designed around: Claude Code\n * and GitHub Copilot conventions evolve independently, so each lives in its own\n * adapter file ({@link ./claude.ts}, {@link ./copilot.ts}, {@link ./agents.ts}).\n * Supporting a new vendor — or tracking a change in an existing one — means\n * editing (or adding) exactly one adapter and registering it; no other module\n * changes.\n */\n\nimport type { NormalizedPlugin } from \"../manifest.js\";\n\n/** Internal format id — matches `NormalizedPlugin.format` / `NormalizedMarketplace.format`. */\nexport type PluginFormatId = \"agents\" | \"claude\" | \"copilot\";\n\n/**\n * Public platform token surfaced to users. The Copilot format lives under\n * `.github/`, so it is surfaced as `\"github\"` rather than the internal\n * `\"copilot\"`.\n */\nexport type MarketplacePlatform = \"agents\" | \"claude\" | \"github\";\n\n/** A file produced by a format's scaffolder. `path` is relative to the plugin root (POSIX). */\nexport interface EmittedFile {\n\tpath: string;\n\tcontent: string;\n}\n\n/** An authored skill: passive instructions loaded lazily (SKILL.md-style). */\ninterface AuthoredSkill {\n\tname: string;\n\tdescription?: string;\n\t/** Instruction body (markdown). */\n\tbody: string;\n}\n\n/** An authored slash command: a passive prompt template. */\ninterface AuthoredCommand {\n\tname: string;\n\tdescription?: string;\n\t/** Prompt template body (markdown). */\n\tbody: string;\n}\n\n/** An authored subagent definition. `tools` is a comma-separated allowlist (Claude Code convention). */\ninterface AuthoredAgent {\n\tname: string;\n\tdescription?: string;\n\t/** Comma-separated `allowed-tools` string, e.g. \"read, grep, glob\". */\n\ttools?: string;\n\tmodel?: string;\n\t/** System-prompt / instruction body (markdown). */\n\tbody: string;\n}\n\n/** An authored shell hook wired to a tool event. Active code — gated on authoring. */\nexport interface AuthoredHook {\n\t/** Claude Code event name: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, Stop, ... */\n\tevent: string;\n\t/** Regex matched against the tool name. Empty / \"*\" matches everything. */\n\tmatcher?: string;\n\tcommand: string;\n\t/** Timeout in seconds. */\n\ttimeout?: number;\n}\n\n/** An authored MCP server. Active code — gated on authoring. */\nexport interface AuthoredMcpServer {\n\tname: string;\n\tcommand: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n}\n\n/**\n * Format-agnostic authoring spec consumed by {@link PluginFormatAdapter.emit}.\n * `ProposePlugin` builds one of these and asks each requested adapter to render\n * it, so the same authored capability lands correctly in Claude Code and\n * Copilot layouts without the authoring code knowing either.\n */\nexport interface PluginDraft {\n\tid: string;\n\tversion?: string;\n\tdescription?: string;\n\tauthor?: string;\n\t/**\n\t * Which platform layouts to scaffold this draft into (e.g. `[\"claude\",\n\t * \"github\"]`). Consumed as the default target set by `emitForPlatforms`;\n\t * omit to render every registered format.\n\t */\n\tsupportPlatform?: MarketplacePlatform[];\n\tskills?: AuthoredSkill[];\n\tcommands?: AuthoredCommand[];\n\tagents?: AuthoredAgent[];\n\thooks?: AuthoredHook[];\n\tmcpServers?: AuthoredMcpServer[];\n\t/**\n\t * Manifest keys carried through from an existing plugin that this codebase\n\t * does not model (see {@link NormalizedPlugin.unknownFields}). Emitters write\n\t * them back verbatim so editing a plugin never strips a vendor key we happen\n\t * not to understand. Never set when authoring from scratch.\n\t */\n\tunknownFields?: Record<string, unknown>;\n}\n\n/**\n * Writer for a platform's *workspace-level* (non-plugin) artifact conventions —\n * where a standalone skill, subagent, or command lives inside a repository for\n * that vendor (e.g. Copilot reads `.github/skills/<name>/SKILL.md`,\n * `.github/agents/<name>.agent.md`, `.github/prompts/<name>.prompt.md`).\n * Unlike {@link PluginFormatAdapter.emit}, the returned paths are relative to\n * the **workspace root** (cwd), marker directory included.\n */\nexport interface WorkspaceLayout {\n\t/** Marker root the artifacts land under, e.g. \".github\", \".claude\", \".agents\". */\n\treadonly root: string;\n\temitSkill(skill: AuthoredSkill): EmittedFile;\n\temitAgent(agent: AuthoredAgent): EmittedFile;\n\temitCommand(command: AuthoredCommand): EmittedFile;\n}\n\n/** Reader + writer for a single plugin format. */\nexport interface PluginFormatAdapter {\n\t/** Internal format id (stable; used in `NormalizedPlugin.format`). */\n\treadonly id: PluginFormatId;\n\t/** Public platform token (Copilot → `\"github\"`). */\n\treadonly platform: MarketplacePlatform;\n\t/**\n\t * Precedence when several formats coexist in one directory (lower wins).\n\t * Native `.agents-plugin` beats Claude beats Copilot.\n\t */\n\treadonly precedence: number;\n\t/** Short human label for messages and scaffolding summaries. */\n\treadonly label: string;\n\t/**\n\t * Candidate locations of this format's marketplace index file, relative to a\n\t * marketplace root (POSIX), in precedence order. Formats with more than one\n\t * real-world convention (Copilot uses both `.github/plugin/marketplace.json`\n\t * and `.github/marketplace.json`) list every location they accept.\n\t */\n\treadonly marketplaceFiles: readonly string[];\n\n\t/** True if `root` is a plugin of this format — including, where the vendor allows it, without a manifest. */\n\tdetectPlugin(root: string): boolean;\n\t/** True only if `root` carries this format's manifest *file*, ignoring manifest-optional rules. */\n\thasManifest(root: string): boolean;\n\t/** Parse `root` as a plugin of this format. Returns null when unparseable. */\n\tparsePlugin(root: string): NormalizedPlugin | null;\n\t/** Render `draft` into this format's on-disk layout (paths relative to the plugin root). */\n\temit(draft: PluginDraft): EmittedFile[];\n\t/** This platform's workspace-level artifact conventions (paths relative to the workspace root). */\n\treadonly workspace: WorkspaceLayout;\n}\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../src/core/extensions/plugins/formats/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG","sourcesContent":["/**\n * Plugin format adapter contract.\n *\n * A `PluginFormatAdapter` owns *everything* format-specific for one vendor\n * layout — how a plugin directory is detected and parsed (the reader), how a\n * marketplace index file is located, and how a plugin is scaffolded from a\n * normalized draft (the writer). The rest of the plugin subsystem is written\n * against {@link NormalizedPlugin} / {@link PluginDraft} and never branches on a\n * format again.\n *\n * This is the extension point the plugin system is designed around: Claude Code\n * and GitHub Copilot conventions evolve independently, so each lives in its own\n * adapter file ({@link ./claude.ts}, {@link ./copilot.ts}, {@link ./agents.ts}).\n * Supporting a new vendor — or tracking a change in an existing one — means\n * editing (or adding) exactly one adapter and registering it; no other module\n * changes.\n */\n\nimport type { NormalizedPlugin } from \"../manifest.js\";\n\n/** Internal format id — matches `NormalizedPlugin.format` / `NormalizedMarketplace.format`. */\nexport type PluginFormatId = \"agents\" | \"claude\" | \"copilot\";\n\n/**\n * Public platform token surfaced to users. The Copilot format lives under\n * `.github/`, so it is surfaced as `\"github\"` rather than the internal\n * `\"copilot\"`.\n */\nexport type MarketplacePlatform = \"agents\" | \"claude\" | \"github\";\n\n/** A file produced by a format's scaffolder. `path` is relative to the plugin root (POSIX). */\nexport interface EmittedFile {\n\tpath: string;\n\tcontent: string;\n}\n\n/** An authored skill: passive instructions loaded lazily (SKILL.md-style). */\ninterface AuthoredSkill {\n\tname: string;\n\tdescription?: string;\n\t/** Instruction body (markdown). */\n\tbody: string;\n}\n\n/** An authored slash command: a passive prompt template. */\ninterface AuthoredCommand {\n\tname: string;\n\tdescription?: string;\n\t/** Prompt template body (markdown). */\n\tbody: string;\n}\n\n/** An authored subagent definition. `tools` is a comma-separated allowlist (Claude Code convention). */\ninterface AuthoredAgent {\n\tname: string;\n\tdescription?: string;\n\t/** Comma-separated `allowed-tools` string, e.g. \"read, search\". */\n\ttools?: string;\n\tmodel?: string;\n\t/** System-prompt / instruction body (markdown). */\n\tbody: string;\n}\n\n/** An authored shell hook wired to a tool event. Active code — gated on authoring. */\nexport interface AuthoredHook {\n\t/** Claude Code event name: PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, Stop, ... */\n\tevent: string;\n\t/** Regex matched against the tool name. Empty / \"*\" matches everything. */\n\tmatcher?: string;\n\tcommand: string;\n\t/** Timeout in seconds. */\n\ttimeout?: number;\n}\n\n/** An authored MCP server. Active code — gated on authoring. */\nexport interface AuthoredMcpServer {\n\tname: string;\n\tcommand: string;\n\targs?: string[];\n\tenv?: Record<string, string>;\n}\n\n/**\n * Format-agnostic authoring spec consumed by {@link PluginFormatAdapter.emit}.\n * `ProposePlugin` builds one of these and asks each requested adapter to render\n * it, so the same authored capability lands correctly in Claude Code and\n * Copilot layouts without the authoring code knowing either.\n */\nexport interface PluginDraft {\n\tid: string;\n\tversion?: string;\n\tdescription?: string;\n\tauthor?: string;\n\t/**\n\t * Which platform layouts to scaffold this draft into (e.g. `[\"claude\",\n\t * \"github\"]`). Consumed as the default target set by `emitForPlatforms`;\n\t * omit to render every registered format.\n\t */\n\tsupportPlatform?: MarketplacePlatform[];\n\tskills?: AuthoredSkill[];\n\tcommands?: AuthoredCommand[];\n\tagents?: AuthoredAgent[];\n\thooks?: AuthoredHook[];\n\tmcpServers?: AuthoredMcpServer[];\n\t/**\n\t * Manifest keys carried through from an existing plugin that this codebase\n\t * does not model (see {@link NormalizedPlugin.unknownFields}). Emitters write\n\t * them back verbatim so editing a plugin never strips a vendor key we happen\n\t * not to understand. Never set when authoring from scratch.\n\t */\n\tunknownFields?: Record<string, unknown>;\n}\n\n/**\n * Writer for a platform's *workspace-level* (non-plugin) artifact conventions —\n * where a standalone skill, subagent, or command lives inside a repository for\n * that vendor (e.g. Copilot reads `.github/skills/<name>/SKILL.md`,\n * `.github/agents/<name>.agent.md`, `.github/prompts/<name>.prompt.md`).\n * Unlike {@link PluginFormatAdapter.emit}, the returned paths are relative to\n * the **workspace root** (cwd), marker directory included.\n */\nexport interface WorkspaceLayout {\n\t/** Marker root the artifacts land under, e.g. \".github\", \".claude\", \".agents\". */\n\treadonly root: string;\n\temitSkill(skill: AuthoredSkill): EmittedFile;\n\temitAgent(agent: AuthoredAgent): EmittedFile;\n\temitCommand(command: AuthoredCommand): EmittedFile;\n}\n\n/** Reader + writer for a single plugin format. */\nexport interface PluginFormatAdapter {\n\t/** Internal format id (stable; used in `NormalizedPlugin.format`). */\n\treadonly id: PluginFormatId;\n\t/** Public platform token (Copilot → `\"github\"`). */\n\treadonly platform: MarketplacePlatform;\n\t/**\n\t * Precedence when several formats coexist in one directory (lower wins).\n\t * Native `.agents-plugin` beats Claude beats Copilot.\n\t */\n\treadonly precedence: number;\n\t/** Short human label for messages and scaffolding summaries. */\n\treadonly label: string;\n\t/**\n\t * Candidate locations of this format's marketplace index file, relative to a\n\t * marketplace root (POSIX), in precedence order. Formats with more than one\n\t * real-world convention (Copilot uses both `.github/plugin/marketplace.json`\n\t * and `.github/marketplace.json`) list every location they accept.\n\t */\n\treadonly marketplaceFiles: readonly string[];\n\n\t/** True if `root` is a plugin of this format — including, where the vendor allows it, without a manifest. */\n\tdetectPlugin(root: string): boolean;\n\t/** True only if `root` carries this format's manifest *file*, ignoring manifest-optional rules. */\n\thasManifest(root: string): boolean;\n\t/** Parse `root` as a plugin of this format. Returns null when unparseable. */\n\tparsePlugin(root: string): NormalizedPlugin | null;\n\t/** Render `draft` into this format's on-disk layout (paths relative to the plugin root). */\n\temit(draft: PluginDraft): EmittedFile[];\n\t/** This platform's workspace-level artifact conventions (paths relative to the workspace root). */\n\treadonly workspace: WorkspaceLayout;\n}\n"]}