@kolisachint/hoocode-agent 0.5.2 → 0.5.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +31 -0
- package/dist/cli/args.d.ts +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +10 -7
- package/dist/cli/args.js.map +1 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +10 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/capabilities/deferral.d.ts +78 -0
- package/dist/core/capabilities/deferral.d.ts.map +1 -0
- package/dist/core/capabilities/deferral.js +99 -0
- package/dist/core/capabilities/deferral.js.map +1 -0
- package/dist/core/capabilities/dense.d.ts +51 -0
- package/dist/core/capabilities/dense.d.ts.map +1 -0
- package/dist/core/capabilities/dense.js +121 -0
- package/dist/core/capabilities/dense.js.map +1 -0
- package/dist/core/capabilities/lexical.d.ts +43 -0
- package/dist/core/capabilities/lexical.d.ts.map +1 -0
- package/dist/core/capabilities/lexical.js +104 -0
- package/dist/core/capabilities/lexical.js.map +1 -0
- package/dist/core/capabilities/registry.d.ts +56 -0
- package/dist/core/capabilities/registry.d.ts.map +1 -0
- package/dist/core/capabilities/registry.js +0 -0
- package/dist/core/capabilities/registry.js.map +1 -0
- package/dist/core/capabilities/search.d.ts +47 -0
- package/dist/core/capabilities/search.d.ts.map +1 -0
- package/dist/core/capabilities/search.js +82 -0
- package/dist/core/capabilities/search.js.map +1 -0
- package/dist/core/extensions/loader.d.ts +27 -3
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +61 -7
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/plugins/authoring.d.ts +56 -9
- package/dist/core/extensions/plugins/authoring.d.ts.map +1 -1
- package/dist/core/extensions/plugins/authoring.js +0 -0
- package/dist/core/extensions/plugins/authoring.js.map +1 -1
- package/dist/core/extensions/plugins/drift.d.ts +75 -0
- package/dist/core/extensions/plugins/drift.d.ts.map +1 -0
- package/dist/core/extensions/plugins/drift.js +194 -0
- package/dist/core/extensions/plugins/drift.js.map +1 -0
- package/dist/core/extensions/plugins/formats/claude.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/claude.js +5 -0
- package/dist/core/extensions/plugins/formats/claude.js.map +1 -1
- package/dist/core/extensions/plugins/formats/copilot.d.ts +6 -0
- package/dist/core/extensions/plugins/formats/copilot.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/copilot.js +57 -16
- package/dist/core/extensions/plugins/formats/copilot.js.map +1 -1
- package/dist/core/extensions/plugins/formats/index.d.ts +39 -1
- package/dist/core/extensions/plugins/formats/index.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/index.js +90 -13
- package/dist/core/extensions/plugins/formats/index.js.map +1 -1
- package/dist/core/extensions/plugins/formats/jsonManifest.d.ts +14 -0
- package/dist/core/extensions/plugins/formats/jsonManifest.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/jsonManifest.js +37 -4
- package/dist/core/extensions/plugins/formats/jsonManifest.js.map +1 -1
- package/dist/core/extensions/plugins/formats/platform-targets.d.ts +48 -24
- package/dist/core/extensions/plugins/formats/platform-targets.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/platform-targets.js +62 -30
- package/dist/core/extensions/plugins/formats/platform-targets.js.map +1 -1
- package/dist/core/extensions/plugins/formats/shared.d.ts +22 -0
- package/dist/core/extensions/plugins/formats/shared.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/shared.js +81 -4
- package/dist/core/extensions/plugins/formats/shared.js.map +1 -1
- package/dist/core/extensions/plugins/formats/types.d.ts +10 -1
- package/dist/core/extensions/plugins/formats/types.d.ts.map +1 -1
- package/dist/core/extensions/plugins/formats/types.js.map +1 -1
- package/dist/core/extensions/plugins/gates.d.ts +64 -0
- package/dist/core/extensions/plugins/gates.d.ts.map +1 -0
- package/dist/core/extensions/plugins/gates.js +297 -0
- package/dist/core/extensions/plugins/gates.js.map +1 -0
- package/dist/core/extensions/plugins/hooks-bridge.d.ts +1 -1
- package/dist/core/extensions/plugins/hooks-bridge.d.ts.map +1 -1
- package/dist/core/extensions/plugins/hooks-bridge.js +12 -8
- package/dist/core/extensions/plugins/hooks-bridge.js.map +1 -1
- package/dist/core/extensions/plugins/index.d.ts +36 -5
- package/dist/core/extensions/plugins/index.d.ts.map +1 -1
- package/dist/core/extensions/plugins/index.js +66 -15
- package/dist/core/extensions/plugins/index.js.map +1 -1
- package/dist/core/extensions/plugins/install.d.ts +43 -24
- package/dist/core/extensions/plugins/install.d.ts.map +1 -1
- package/dist/core/extensions/plugins/install.js +167 -54
- package/dist/core/extensions/plugins/install.js.map +1 -1
- package/dist/core/extensions/plugins/locations.d.ts +84 -0
- package/dist/core/extensions/plugins/locations.d.ts.map +1 -0
- package/dist/core/extensions/plugins/locations.js +137 -0
- package/dist/core/extensions/plugins/locations.js.map +1 -0
- package/dist/core/extensions/plugins/manifest.d.ts +21 -1
- package/dist/core/extensions/plugins/manifest.d.ts.map +1 -1
- package/dist/core/extensions/plugins/manifest.js +2 -2
- package/dist/core/extensions/plugins/manifest.js.map +1 -1
- package/dist/core/extensions/plugins/packaging.d.ts +115 -0
- package/dist/core/extensions/plugins/packaging.d.ts.map +1 -0
- package/dist/core/extensions/plugins/packaging.js +362 -0
- package/dist/core/extensions/plugins/packaging.js.map +1 -0
- package/dist/core/extensions/plugins/smoke.d.ts +33 -0
- package/dist/core/extensions/plugins/smoke.d.ts.map +1 -0
- package/dist/core/extensions/plugins/smoke.js +231 -0
- package/dist/core/extensions/plugins/smoke.js.map +1 -0
- package/dist/core/extensions/plugins/trigger-eval.d.ts +136 -0
- package/dist/core/extensions/plugins/trigger-eval.d.ts.map +1 -0
- package/dist/core/extensions/plugins/trigger-eval.js +0 -0
- package/dist/core/extensions/plugins/trigger-eval.js.map +1 -0
- package/dist/core/package-manager.d.ts +6 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts +2 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +15 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/settings-manager.d.ts +2 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +3 -3
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/settings-types.d.ts +1 -1
- package/dist/core/settings-types.d.ts.map +1 -1
- package/dist/core/settings-types.js.map +1 -1
- package/dist/core/skills.d.ts +9 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +23 -3
- package/dist/core/skills.js.map +1 -1
- package/dist/core/tools/package-plugin.d.ts +19 -0
- package/dist/core/tools/package-plugin.d.ts.map +1 -0
- package/dist/core/tools/package-plugin.js +81 -0
- package/dist/core/tools/package-plugin.js.map +1 -0
- package/dist/core/tools/plugin-tool-names.d.ts +1 -0
- package/dist/core/tools/plugin-tool-names.d.ts.map +1 -1
- package/dist/core/tools/plugin-tool-names.js +6 -0
- package/dist/core/tools/plugin-tool-names.js.map +1 -1
- package/dist/core/tools/plugins.d.ts.map +1 -1
- package/dist/core/tools/plugins.js +48 -7
- package/dist/core/tools/plugins.js.map +1 -1
- package/dist/core/tools/propose-plugin.d.ts.map +1 -1
- package/dist/core/tools/propose-plugin.js +49 -21
- package/dist/core/tools/propose-plugin.js.map +1 -1
- package/dist/core/tools/webfetch.d.ts +3 -1
- package/dist/core/tools/webfetch.d.ts.map +1 -1
- package/dist/core/tools/webfetch.js +8 -2
- package/dist/core/tools/webfetch.js.map +1 -1
- package/dist/core/tools/websearch.d.ts +2 -0
- package/dist/core/tools/websearch.d.ts.map +1 -1
- package/dist/core/tools/websearch.js +2 -1
- package/dist/core/tools/websearch.js.map +1 -1
- package/dist/core/tools/webtools-shared.d.ts +23 -2
- package/dist/core/tools/webtools-shared.d.ts.map +1 -1
- package/dist/core/tools/webtools-shared.js +59 -9
- package/dist/core/tools/webtools-shared.js.map +1 -1
- package/dist/extensions/core/marketplace.d.ts +14 -3
- package/dist/extensions/core/marketplace.d.ts.map +1 -1
- package/dist/extensions/core/marketplace.js +77 -18
- package/dist/extensions/core/marketplace.js.map +1 -1
- package/dist/extensions/core/mcp-deferred.d.ts +39 -2
- package/dist/extensions/core/mcp-deferred.d.ts.map +1 -1
- package/dist/extensions/core/mcp-deferred.js +74 -10
- package/dist/extensions/core/mcp-deferred.js.map +1 -1
- package/dist/extensions/core/mcp-loader.d.ts.map +1 -1
- package/dist/extensions/core/mcp-loader.js +52 -9
- package/dist/extensions/core/mcp-loader.js.map +1 -1
- package/dist/extensions/core/scaffold.d.ts +3 -3
- package/dist/extensions/core/scaffold.d.ts.map +1 -1
- package/dist/extensions/core/scaffold.js +9 -9
- package/dist/extensions/core/scaffold.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +25 -7
- package/dist/main.js.map +1 -1
- package/dist/utils/tools-manager.d.ts +8 -0
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js +12 -3
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/providers.md +11 -0
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +5 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n *\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@kolisachint/hoocode-agent-core\";\nimport * as _bundledPiAi from \"@kolisachint/hoocode-ai\";\nimport * as _bundledPiAiOauth from \"@kolisachint/hoocode-ai/oauth\";\nimport type { KeyId } from \"@kolisachint/hoocode-tui\";\nimport * as _bundledPiTui from \"@kolisachint/hoocode-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.js\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @kolisachint/hoocode-agent.\nimport * as _bundledPiCodingAgent from \"../../index.js\";\nimport { createEventBus, type EventBus } from \"../event-bus.js\";\nimport type { ExecOptions } from \"../exec.js\";\nimport { execCommand } from \"../exec.js\";\nimport { clearExtensionMcpServers } from \"../extension-mcp-servers.js\";\nimport { createSyntheticSourceInfo } from \"../source-info.js\";\nimport { buildPluginFactory, discoverPlugins } from \"./plugins/index.js\";\nimport type {\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.js\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@kolisachint/hoocode-agent-core\": _bundledPiAgentCore,\n\t\"@kolisachint/hoocode-tui\": _bundledPiTui,\n\t\"@kolisachint/hoocode-ai\": _bundledPiAi,\n\t\"@kolisachint/hoocode-ai/oauth\": _bundledPiAiOauth,\n\t\"@kolisachint/hoocode-agent\": _bundledPiCodingAgent,\n};\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Get aliases for jiti (used in Node.js/development mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst typeboxEntry = require.resolve(\"typebox\");\n\tconst typeboxCompileEntry = require.resolve(\"typebox/compile\");\n\tconst typeboxValueEntry = require.resolve(\"typebox/value\");\n\n\tconst packagesRoot = path.resolve(__dirname, \"../../../../\");\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\tif (fs.existsSync(workspacePath)) {\n\t\t\treturn workspacePath;\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst hooCodingAgentEntry = packageIndex;\n\tconst hooAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@kolisachint/hoocode-agent-core\");\n\tconst hooTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@kolisachint/hoocode-tui\");\n\tconst hooAiEntry = resolveWorkspaceOrImport(\"ai/dist/index.js\", \"@kolisachint/hoocode-ai\");\n\tconst hooAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@kolisachint/hoocode-ai/oauth\");\n\n\t_aliases = {\n\t\t\"@kolisachint/hoocode-agent\": hooCodingAgentEntry,\n\t\t\"@kolisachint/hoocode-agent-core\": hooAgentCoreEntry,\n\t\t\"@kolisachint/hoocode-tui\": hooTuiEntry,\n\t\t\"@kolisachint/hoocode-ai\": hooAiEntry,\n\t\t\"@kolisachint/hoocode-ai/oauth\": hooAiOauthEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\nfunction resolvePath(extPath: string, cwd: string): string {\n\tconst expanded = expandPath(extPath);\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\treturn path.resolve(cwd, expanded);\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tmodeSearchPaths: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tstate.staleMessage ??=\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.js\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\taddModeSearchPath(dirPath: string): void {\n\t\t\truntime.assertActive();\n\t\t\tconst resolved = resolvePath(dirPath, cwd);\n\t\t\tif (!runtime.modeSearchPaths.includes(resolved)) {\n\t\t\t\truntime.modeSearchPaths.push(resolved);\n\t\t\t}\n\t\t},\n\n\t\tgetModeSearchPaths(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn [...runtime.modeSearchPaths];\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(name: string, config: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerProvider(name, config, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\tevents: eventBus,\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nasync function loadExtensionModule(extensionPath: string) {\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)\n\t\t// Also disable tryNative so jiti handles ALL imports (not just the entry point)\n\t\t// In Node.js/dev: use aliases to resolve to node_modules paths\n\t\t...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),\n\t});\n\n\tconst module = await jiti.import(extensionPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\treturn typeof factory !== \"function\" ? undefined : factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t};\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd);\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\n\t\treturn { extension, error: null };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n\tdisplayName?: string,\n): Promise<Extension> {\n\tconst effectivePath = displayName ?? extensionPath;\n\tconst extension = createExtension(effectivePath, extensionPath);\n\tif (displayName) {\n\t\textension.sourceInfo = createSyntheticSourceInfo(displayName, {\n\t\t\tsource: \"inline\",\n\t\t\tscope: \"temporary\",\n\t\t\torigin: \"top-level\",\n\t\t});\n\t}\n\textension.displayName = displayName;\n\textension.internal = factory.internal === true;\n\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\tawait factory(api);\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst runtime = createExtensionRuntime();\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, runtime);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\truntime,\n\t};\n}\n\ninterface HooCodeManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n}\n\nfunction readHooCodeManifest(packageJsonPath: string): HooCodeManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.hoocode && typeof pkg.hoocode === \"object\") {\n\t\t\treturn pkg.hoocode as HooCodeManifest;\n\t\t}\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as HooCodeManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): string[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readHooCodeManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst entries: string[] = [];\n\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\tconst resolvedExtPath = path.resolve(dir, extPath);\n\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\tentries.push(resolvedExtPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn entries;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [indexTs];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [indexJs];\n\t}\n\n\treturn null;\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: string[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push(entryPath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(cwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(agentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, cwd);\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst result = await loadExtensions(allPaths, cwd, resolvedEventBus);\n\n\t// Plugins: directories under plugins/ with a recognized manifest.\n\tconst pluginDirs = defaultPluginDirs(cwd, agentDir);\n\tconst pluginResult = await loadPlugins(pluginDirs, cwd, resolvedEventBus, result.runtime);\n\tresult.extensions.push(...pluginResult.extensions);\n\tresult.errors.push(...pluginResult.errors);\n\n\treturn result;\n}\n\n/**\n * Standard plugin discovery directories, highest precedence first.\n *\n * `.agents/plugins/` is the cross-vendor, primary home and is listed ahead of the\n * `.hoocode/plugins/` fallback at each scope, so an `.agents`-installed plugin\n * wins over a same-id `.hoocode` one (discoverPlugins is first-wins by id).\n * Project scope beats global. The global `.agents` sibling lives next to the\n * agent dir (`~/.agents` alongside `~/.hoocode`), so it stays parameterized on\n * `agentDir` rather than hardcoding the home directory.\n */\nexport function defaultPluginDirs(cwd: string, agentDir: string = getAgentDir()): string[] {\n\tconst globalAgentsPlugins = path.join(path.dirname(agentDir), \".agents\", \"plugins\");\n\treturn [\n\t\tpath.join(cwd, \".agents\", \"plugins\"),\n\t\tpath.join(cwd, CONFIG_DIR_NAME, \"plugins\"),\n\t\tglobalAgentsPlugins,\n\t\tpath.join(agentDir, \"plugins\"),\n\t];\n}\n\n/**\n * Discover plugins under `pluginDirs` and load each as a synthetic extension into\n * the given runtime/event bus. Clears the extension MCP registry first so reloads\n * rebuild the set cleanly.\n */\nexport async function loadPlugins(\n\tpluginDirs: string[],\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extensions: Extension[]; errors: Array<{ path: string; error: string }> }> {\n\tclearExtensionMcpServers();\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\n\tfor (const plugin of discoverPlugins(pluginDirs)) {\n\t\ttry {\n\t\t\tconst extension = await loadExtensionFromFactory(\n\t\t\t\tbuildPluginFactory(plugin),\n\t\t\t\tcwd,\n\t\t\t\teventBus,\n\t\t\t\truntime,\n\t\t\t\t`<plugin:${plugin.id}>`,\n\t\t\t\t`plugin:${plugin.id}`,\n\t\t\t);\n\t\t\textensions.push(extension);\n\t\t} catch (err) {\n\t\t\terrors.push({\n\t\t\t\tpath: plugin.manifestPath,\n\t\t\t\terror: `Failed to load plugin \"${plugin.id}\": ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn { extensions, errors };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../../src/core/extensions/loader.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Extension loader - loads TypeScript extension modules using jiti.\n *\n */\n\nimport * as fs from \"node:fs\";\nimport { createRequire } from \"node:module\";\nimport * as os from \"node:os\";\nimport * as path from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport * as _bundledPiAgentCore from \"@kolisachint/hoocode-agent-core\";\nimport * as _bundledPiAi from \"@kolisachint/hoocode-ai\";\nimport * as _bundledPiAiOauth from \"@kolisachint/hoocode-ai/oauth\";\nimport type { KeyId } from \"@kolisachint/hoocode-tui\";\nimport * as _bundledPiTui from \"@kolisachint/hoocode-tui\";\nimport { createJiti } from \"jiti/static\";\n// Static imports of packages that extensions may use.\n// These MUST be static so Bun bundles them into the compiled binary.\n// The virtualModules option then makes them available to extensions.\nimport * as _bundledTypebox from \"typebox\";\nimport * as _bundledTypeboxCompile from \"typebox/compile\";\nimport * as _bundledTypeboxValue from \"typebox/value\";\nimport { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from \"../../config.js\";\n// NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,\n// avoiding a circular dependency. Extensions can import from @kolisachint/hoocode-agent.\nimport * as _bundledPiCodingAgent from \"../../index.js\";\nimport { createEventBus, type EventBus } from \"../event-bus.js\";\nimport type { ExecOptions } from \"../exec.js\";\nimport { execCommand } from \"../exec.js\";\nimport { clearExtensionMcpServers } from \"../extension-mcp-servers.js\";\nimport { createSyntheticSourceInfo } from \"../source-info.js\";\nimport { buildPluginFactory, discoverPlugins, pluginExtensionPath, withheldCapabilities } from \"./plugins/index.js\";\nimport type {\n\tExtension,\n\tExtensionAPI,\n\tExtensionFactory,\n\tExtensionRuntime,\n\tLoadExtensionsResult,\n\tMessageRenderer,\n\tProviderConfig,\n\tRegisteredCommand,\n\tToolDefinition,\n} from \"./types.js\";\n\n/** Modules available to extensions via virtualModules (for compiled Bun binary) */\nconst VIRTUAL_MODULES: Record<string, unknown> = {\n\ttypebox: _bundledTypebox,\n\t\"typebox/compile\": _bundledTypeboxCompile,\n\t\"typebox/value\": _bundledTypeboxValue,\n\t\"@sinclair/typebox\": _bundledTypebox,\n\t\"@sinclair/typebox/compile\": _bundledTypeboxCompile,\n\t\"@sinclair/typebox/value\": _bundledTypeboxValue,\n\t\"@kolisachint/hoocode-agent-core\": _bundledPiAgentCore,\n\t\"@kolisachint/hoocode-tui\": _bundledPiTui,\n\t\"@kolisachint/hoocode-ai\": _bundledPiAi,\n\t\"@kolisachint/hoocode-ai/oauth\": _bundledPiAiOauth,\n\t\"@kolisachint/hoocode-agent\": _bundledPiCodingAgent,\n};\n\nconst require = createRequire(import.meta.url);\n\n/**\n * Get aliases for jiti (used in Node.js/development mode).\n * In Bun binary mode, virtualModules is used instead.\n */\nlet _aliases: Record<string, string> | null = null;\n\nfunction getAliases(): Record<string, string> {\n\tif (_aliases) return _aliases;\n\n\tconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\tconst packageIndex = path.resolve(__dirname, \"../..\", \"index.js\");\n\n\tconst typeboxEntry = require.resolve(\"typebox\");\n\tconst typeboxCompileEntry = require.resolve(\"typebox/compile\");\n\tconst typeboxValueEntry = require.resolve(\"typebox/value\");\n\n\tconst packagesRoot = path.resolve(__dirname, \"../../../../\");\n\tconst resolveWorkspaceOrImport = (workspaceRelativePath: string, specifier: string): string => {\n\t\tconst workspacePath = path.join(packagesRoot, workspaceRelativePath);\n\t\tif (fs.existsSync(workspacePath)) {\n\t\t\treturn workspacePath;\n\t\t}\n\t\treturn fileURLToPath(import.meta.resolve(specifier));\n\t};\n\n\tconst hooCodingAgentEntry = packageIndex;\n\tconst hooAgentCoreEntry = resolveWorkspaceOrImport(\"agent/dist/index.js\", \"@kolisachint/hoocode-agent-core\");\n\tconst hooTuiEntry = resolveWorkspaceOrImport(\"tui/dist/index.js\", \"@kolisachint/hoocode-tui\");\n\tconst hooAiEntry = resolveWorkspaceOrImport(\"ai/dist/index.js\", \"@kolisachint/hoocode-ai\");\n\tconst hooAiOauthEntry = resolveWorkspaceOrImport(\"ai/dist/oauth.js\", \"@kolisachint/hoocode-ai/oauth\");\n\n\t_aliases = {\n\t\t\"@kolisachint/hoocode-agent\": hooCodingAgentEntry,\n\t\t\"@kolisachint/hoocode-agent-core\": hooAgentCoreEntry,\n\t\t\"@kolisachint/hoocode-tui\": hooTuiEntry,\n\t\t\"@kolisachint/hoocode-ai\": hooAiEntry,\n\t\t\"@kolisachint/hoocode-ai/oauth\": hooAiOauthEntry,\n\t\ttypebox: typeboxEntry,\n\t\t\"typebox/compile\": typeboxCompileEntry,\n\t\t\"typebox/value\": typeboxValueEntry,\n\t\t\"@sinclair/typebox\": typeboxEntry,\n\t\t\"@sinclair/typebox/compile\": typeboxCompileEntry,\n\t\t\"@sinclair/typebox/value\": typeboxValueEntry,\n\t};\n\n\treturn _aliases;\n}\n\nconst UNICODE_SPACES = /[\\u00A0\\u2000-\\u200A\\u202F\\u205F\\u3000]/g;\n\nfunction normalizeUnicodeSpaces(str: string): string {\n\treturn str.replace(UNICODE_SPACES, \" \");\n}\n\nfunction expandPath(p: string): string {\n\tconst normalized = normalizeUnicodeSpaces(p);\n\tif (normalized.startsWith(\"~/\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(2));\n\t}\n\tif (normalized.startsWith(\"~\")) {\n\t\treturn path.join(os.homedir(), normalized.slice(1));\n\t}\n\treturn normalized;\n}\n\nfunction resolvePath(extPath: string, cwd: string): string {\n\tconst expanded = expandPath(extPath);\n\tif (path.isAbsolute(expanded)) {\n\t\treturn expanded;\n\t}\n\treturn path.resolve(cwd, expanded);\n}\n\ntype HandlerFn = (...args: unknown[]) => Promise<unknown>;\n\n/**\n * Create a runtime with throwing stubs for action methods.\n * Runner.bindCore() replaces these with real implementations.\n */\nexport function createExtensionRuntime(): ExtensionRuntime {\n\tconst notInitialized = () => {\n\t\tthrow new Error(\"Extension runtime not initialized. Action methods cannot be called during extension loading.\");\n\t};\n\tconst state: { staleMessage?: string } = {};\n\tconst assertActive = () => {\n\t\tif (state.staleMessage) {\n\t\t\tthrow new Error(state.staleMessage);\n\t\t}\n\t};\n\n\tconst runtime: ExtensionRuntime = {\n\t\tsendMessage: notInitialized,\n\t\tsendUserMessage: notInitialized,\n\t\tappendEntry: notInitialized,\n\t\tsetSessionName: notInitialized,\n\t\tgetSessionName: notInitialized,\n\t\tsetLabel: notInitialized,\n\t\tgetActiveTools: notInitialized,\n\t\tgetAllTools: notInitialized,\n\t\tsetActiveTools: notInitialized,\n\t\t// registerTool() is valid during extension load; refresh is only needed post-bind.\n\t\trefreshTools: () => {},\n\t\tgetCommands: notInitialized,\n\t\tsetModel: () => Promise.reject(new Error(\"Extension runtime not initialized\")),\n\t\tgetThinkingLevel: notInitialized,\n\t\tsetThinkingLevel: notInitialized,\n\t\tflagValues: new Map(),\n\t\tpendingProviderRegistrations: [],\n\t\tmodeSearchPaths: [],\n\t\tassertActive,\n\t\tinvalidate: (message) => {\n\t\t\tstate.staleMessage ??=\n\t\t\t\tmessage ??\n\t\t\t\t\"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().\";\n\t\t},\n\t\t// Pre-bind: queue registrations so bindCore() can flush them once the\n\t\t// model registry is available. bindCore() replaces both with direct calls.\n\t\tregisterProvider: (name, config, extensionPath = \"<unknown>\") => {\n\t\t\truntime.pendingProviderRegistrations.push({ name, config, extensionPath });\n\t\t},\n\t\tunregisterProvider: (name) => {\n\t\t\truntime.pendingProviderRegistrations = runtime.pendingProviderRegistrations.filter((r) => r.name !== name);\n\t\t},\n\t};\n\n\treturn runtime;\n}\n\n/**\n * Create the ExtensionAPI for an extension.\n * Registration methods write to the extension object.\n * Action methods delegate to the shared runtime.\n */\nfunction createExtensionAPI(\n\textension: Extension,\n\truntime: ExtensionRuntime,\n\tcwd: string,\n\teventBus: EventBus,\n): ExtensionAPI {\n\tconst api = {\n\t\t// Registration methods - write to extension\n\t\ton(event: string, handler: HandlerFn): void {\n\t\t\truntime.assertActive();\n\t\t\tconst list = extension.handlers.get(event) ?? [];\n\t\t\tlist.push(handler);\n\t\t\textension.handlers.set(event, list);\n\t\t},\n\n\t\tregisterTool(tool: ToolDefinition): void {\n\t\t\truntime.assertActive();\n\t\t\textension.tools.set(tool.name, {\n\t\t\t\tdefinition: tool,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t});\n\t\t\truntime.refreshTools();\n\t\t},\n\n\t\tregisterCommand(name: string, options: Omit<RegisteredCommand, \"name\" | \"sourceInfo\">): void {\n\t\t\truntime.assertActive();\n\t\t\textension.commands.set(name, {\n\t\t\t\tname,\n\t\t\t\tsourceInfo: extension.sourceInfo,\n\t\t\t\t...options,\n\t\t\t});\n\t\t},\n\n\t\tregisterShortcut(\n\t\t\tshortcut: KeyId,\n\t\t\toptions: {\n\t\t\t\tdescription?: string;\n\t\t\t\thandler: (ctx: import(\"./types.js\").ExtensionContext) => Promise<void> | void;\n\t\t\t},\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.shortcuts.set(shortcut, { shortcut, extensionPath: extension.path, ...options });\n\t\t},\n\n\t\tregisterFlag(\n\t\t\tname: string,\n\t\t\toptions: { description?: string; type: \"boolean\" | \"string\"; default?: boolean | string },\n\t\t): void {\n\t\t\truntime.assertActive();\n\t\t\textension.flags.set(name, { name, extensionPath: extension.path, ...options });\n\t\t\tif (options.default !== undefined && !runtime.flagValues.has(name)) {\n\t\t\t\truntime.flagValues.set(name, options.default);\n\t\t\t}\n\t\t},\n\n\t\tregisterMessageRenderer<T>(customType: string, renderer: MessageRenderer<T>): void {\n\t\t\truntime.assertActive();\n\t\t\textension.messageRenderers.set(customType, renderer as MessageRenderer);\n\t\t},\n\n\t\t// Flag access - checks extension registered it, reads from runtime\n\t\tgetFlag(name: string): boolean | string | undefined {\n\t\t\truntime.assertActive();\n\t\t\tif (!extension.flags.has(name)) return undefined;\n\t\t\treturn runtime.flagValues.get(name);\n\t\t},\n\n\t\taddModeSearchPath(dirPath: string): void {\n\t\t\truntime.assertActive();\n\t\t\tconst resolved = resolvePath(dirPath, cwd);\n\t\t\tif (!runtime.modeSearchPaths.includes(resolved)) {\n\t\t\t\truntime.modeSearchPaths.push(resolved);\n\t\t\t}\n\t\t},\n\n\t\tgetModeSearchPaths(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn [...runtime.modeSearchPaths];\n\t\t},\n\n\t\t// Action methods - delegate to shared runtime\n\t\tsendMessage(message, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendMessage(message, options);\n\t\t},\n\n\t\tsendUserMessage(content, options): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.sendUserMessage(content, options);\n\t\t},\n\n\t\tappendEntry(customType: string, data?: unknown): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.appendEntry(customType, data);\n\t\t},\n\n\t\tsetSessionName(name: string): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setSessionName(name);\n\t\t},\n\n\t\tgetSessionName(): string | undefined {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getSessionName();\n\t\t},\n\n\t\tsetLabel(entryId: string, label: string | undefined): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setLabel(entryId, label);\n\t\t},\n\n\t\texec(command: string, args: string[], options?: ExecOptions) {\n\t\t\truntime.assertActive();\n\t\t\treturn execCommand(command, args, options?.cwd ?? cwd, options);\n\t\t},\n\n\t\tgetActiveTools(): string[] {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getActiveTools();\n\t\t},\n\n\t\tgetAllTools() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getAllTools();\n\t\t},\n\n\t\tsetActiveTools(toolNames: string[]): void {\n\t\t\truntime.assertActive();\n\t\t\truntime.setActiveTools(toolNames);\n\t\t},\n\n\t\tgetCommands() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getCommands();\n\t\t},\n\n\t\tsetModel(model) {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.setModel(model);\n\t\t},\n\n\t\tgetThinkingLevel() {\n\t\t\truntime.assertActive();\n\t\t\treturn runtime.getThinkingLevel();\n\t\t},\n\n\t\tsetThinkingLevel(level) {\n\t\t\truntime.assertActive();\n\t\t\truntime.setThinkingLevel(level);\n\t\t},\n\n\t\tregisterProvider(name: string, config: ProviderConfig) {\n\t\t\truntime.assertActive();\n\t\t\truntime.registerProvider(name, config, extension.path);\n\t\t},\n\n\t\tunregisterProvider(name: string) {\n\t\t\truntime.assertActive();\n\t\t\truntime.unregisterProvider(name, extension.path);\n\t\t},\n\n\t\tevents: eventBus,\n\t} as ExtensionAPI;\n\n\treturn api;\n}\n\nasync function loadExtensionModule(extensionPath: string) {\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\t// In Bun binary: use virtualModules for bundled packages (no filesystem resolution)\n\t\t// Also disable tryNative so jiti handles ALL imports (not just the entry point)\n\t\t// In Node.js/dev: use aliases to resolve to node_modules paths\n\t\t...(isBunBinary ? { virtualModules: VIRTUAL_MODULES, tryNative: false } : { alias: getAliases() }),\n\t});\n\n\tconst module = await jiti.import(extensionPath, { default: true });\n\tconst factory = module as ExtensionFactory;\n\treturn typeof factory !== \"function\" ? undefined : factory;\n}\n\n/**\n * Create an Extension object with empty collections.\n */\nfunction createExtension(extensionPath: string, resolvedPath: string): Extension {\n\tconst source =\n\t\textensionPath.startsWith(\"<\") && extensionPath.endsWith(\">\")\n\t\t\t? extensionPath.slice(1, -1).split(\":\")[0] || \"temporary\"\n\t\t\t: \"local\";\n\tconst baseDir = extensionPath.startsWith(\"<\") ? undefined : path.dirname(resolvedPath);\n\n\treturn {\n\t\tpath: extensionPath,\n\t\tresolvedPath,\n\t\tsourceInfo: createSyntheticSourceInfo(extensionPath, { source, baseDir }),\n\t\thandlers: new Map(),\n\t\ttools: new Map(),\n\t\tmessageRenderers: new Map(),\n\t\tcommands: new Map(),\n\t\tflags: new Map(),\n\t\tshortcuts: new Map(),\n\t};\n}\n\nasync function loadExtension(\n\textensionPath: string,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extension: Extension | null; error: string | null }> {\n\tconst resolvedPath = resolvePath(extensionPath, cwd);\n\n\ttry {\n\t\tconst factory = await loadExtensionModule(resolvedPath);\n\t\tif (!factory) {\n\t\t\treturn { extension: null, error: `Extension does not export a valid factory function: ${extensionPath}` };\n\t\t}\n\n\t\tconst extension = createExtension(extensionPath, resolvedPath);\n\t\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\t\tawait factory(api);\n\n\t\treturn { extension, error: null };\n\t} catch (err) {\n\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\treturn { extension: null, error: `Failed to load extension: ${message}` };\n\t}\n}\n\n/**\n * Create an Extension from an inline factory function.\n */\nexport async function loadExtensionFromFactory(\n\tfactory: ExtensionFactory,\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n\textensionPath = \"<inline>\",\n\tdisplayName?: string,\n): Promise<Extension> {\n\tconst effectivePath = displayName ?? extensionPath;\n\tconst extension = createExtension(effectivePath, extensionPath);\n\tif (displayName) {\n\t\textension.sourceInfo = createSyntheticSourceInfo(displayName, {\n\t\t\tsource: \"inline\",\n\t\t\tscope: \"temporary\",\n\t\t\torigin: \"top-level\",\n\t\t});\n\t}\n\textension.displayName = displayName;\n\textension.internal = factory.internal === true;\n\tconst api = createExtensionAPI(extension, runtime, cwd, eventBus);\n\tawait factory(api);\n\treturn extension;\n}\n\n/**\n * Load extensions from paths.\n */\nexport async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst runtime = createExtensionRuntime();\n\n\tfor (const extPath of paths) {\n\t\tconst { extension, error } = await loadExtension(extPath, cwd, resolvedEventBus, runtime);\n\n\t\tif (error) {\n\t\t\terrors.push({ path: extPath, error });\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (extension) {\n\t\t\textensions.push(extension);\n\t\t}\n\t}\n\n\treturn {\n\t\textensions,\n\t\terrors,\n\t\truntime,\n\t};\n}\n\ninterface HooCodeManifest {\n\textensions?: string[];\n\tthemes?: string[];\n\tskills?: string[];\n\tprompts?: string[];\n}\n\nfunction readHooCodeManifest(packageJsonPath: string): HooCodeManifest | null {\n\ttry {\n\t\tconst content = fs.readFileSync(packageJsonPath, \"utf-8\");\n\t\tconst pkg = JSON.parse(content);\n\t\tif (pkg.hoocode && typeof pkg.hoocode === \"object\") {\n\t\t\treturn pkg.hoocode as HooCodeManifest;\n\t\t}\n\t\tif (pkg.pi && typeof pkg.pi === \"object\") {\n\t\t\treturn pkg.pi as HooCodeManifest;\n\t\t}\n\t\treturn null;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction isExtensionFile(name: string): boolean {\n\treturn name.endsWith(\".ts\") || name.endsWith(\".js\");\n}\n\n/**\n * Resolve extension entry points from a directory.\n *\n * Checks for:\n * 1. package.json with \"pi.extensions\" field -> returns declared paths\n * 2. index.ts or index.js -> returns the index file\n *\n * Returns resolved paths or null if no entry points found.\n */\nfunction resolveExtensionEntries(dir: string): string[] | null {\n\t// Check for package.json with \"pi\" field first\n\tconst packageJsonPath = path.join(dir, \"package.json\");\n\tif (fs.existsSync(packageJsonPath)) {\n\t\tconst manifest = readHooCodeManifest(packageJsonPath);\n\t\tif (manifest?.extensions?.length) {\n\t\t\tconst entries: string[] = [];\n\t\t\tfor (const extPath of manifest.extensions) {\n\t\t\t\tconst resolvedExtPath = path.resolve(dir, extPath);\n\t\t\t\tif (fs.existsSync(resolvedExtPath)) {\n\t\t\t\t\tentries.push(resolvedExtPath);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (entries.length > 0) {\n\t\t\t\treturn entries;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check for index.ts or index.js\n\tconst indexTs = path.join(dir, \"index.ts\");\n\tconst indexJs = path.join(dir, \"index.js\");\n\tif (fs.existsSync(indexTs)) {\n\t\treturn [indexTs];\n\t}\n\tif (fs.existsSync(indexJs)) {\n\t\treturn [indexJs];\n\t}\n\n\treturn null;\n}\n\n/**\n * Discover extensions in a directory.\n *\n * Discovery rules:\n * 1. Direct files: `extensions/*.ts` or `*.js` → load\n * 2. Subdirectory with index: `extensions/* /index.ts` or `index.js` → load\n * 3. Subdirectory with package.json: `extensions/* /package.json` with \"pi\" field → load what it declares\n *\n * No recursion beyond one level. Complex packages must use package.json manifest.\n */\nfunction discoverExtensionsInDir(dir: string): string[] {\n\tif (!fs.existsSync(dir)) {\n\t\treturn [];\n\t}\n\n\tconst discovered: string[] = [];\n\n\ttry {\n\t\tconst entries = fs.readdirSync(dir, { withFileTypes: true });\n\n\t\tfor (const entry of entries) {\n\t\t\tconst entryPath = path.join(dir, entry.name);\n\n\t\t\t// 1. Direct files: *.ts or *.js\n\t\t\tif ((entry.isFile() || entry.isSymbolicLink()) && isExtensionFile(entry.name)) {\n\t\t\t\tdiscovered.push(entryPath);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// 2 & 3. Subdirectories\n\t\t\tif (entry.isDirectory() || entry.isSymbolicLink()) {\n\t\t\t\tconst entries = resolveExtensionEntries(entryPath);\n\t\t\t\tif (entries) {\n\t\t\t\t\tdiscovered.push(...entries);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t} catch {\n\t\treturn [];\n\t}\n\n\treturn discovered;\n}\n\n/**\n * Discover and load extensions from standard locations.\n */\nexport async function discoverAndLoadExtensions(\n\tconfiguredPaths: string[],\n\tcwd: string,\n\tagentDir: string = getAgentDir(),\n\teventBus?: EventBus,\n): Promise<LoadExtensionsResult> {\n\tconst allPaths: string[] = [];\n\tconst seen = new Set<string>();\n\n\tconst addPaths = (paths: string[]) => {\n\t\tfor (const p of paths) {\n\t\t\tconst resolved = path.resolve(p);\n\t\t\tif (!seen.has(resolved)) {\n\t\t\t\tseen.add(resolved);\n\t\t\t\tallPaths.push(p);\n\t\t\t}\n\t\t}\n\t};\n\n\t// 1. Project-local extensions: cwd/${CONFIG_DIR_NAME}/extensions/\n\tconst localExtDir = path.join(cwd, CONFIG_DIR_NAME, \"extensions\");\n\taddPaths(discoverExtensionsInDir(localExtDir));\n\n\t// 2. Global extensions: agentDir/extensions/\n\tconst globalExtDir = path.join(agentDir, \"extensions\");\n\taddPaths(discoverExtensionsInDir(globalExtDir));\n\n\t// 3. Explicitly configured paths\n\tfor (const p of configuredPaths) {\n\t\tconst resolved = resolvePath(p, cwd);\n\t\tif (fs.existsSync(resolved) && fs.statSync(resolved).isDirectory()) {\n\t\t\t// Check for package.json with pi manifest or index.ts\n\t\t\tconst entries = resolveExtensionEntries(resolved);\n\t\t\tif (entries) {\n\t\t\t\taddPaths(entries);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// No explicit entries - discover individual files in directory\n\t\t\taddPaths(discoverExtensionsInDir(resolved));\n\t\t\tcontinue;\n\t\t}\n\n\t\taddPaths([resolved]);\n\t}\n\n\tconst resolvedEventBus = eventBus ?? createEventBus();\n\tconst result = await loadExtensions(allPaths, cwd, resolvedEventBus);\n\n\t// Plugins: directories under plugins/ with a recognized manifest.\n\tconst pluginDirs = defaultPluginDirs(cwd, agentDir);\n\tconst pluginResult = await loadPlugins(pluginDirs, cwd, resolvedEventBus, result.runtime);\n\tresult.extensions.push(...pluginResult.extensions);\n\tresult.errors.push(...pluginResult.errors);\n\n\treturn result;\n}\n\n/**\n * Whether a discovered plugin came with the repository rather than from the user.\n *\n * Scoped to `<cwd>/.claude/skills` — the vendor convention for repo-committed,\n * collaborator-shared plugins, which Claude Code puts behind a workspace trust\n * dialog. The other project paths (`.agents/plugins`, `.hoocode/plugins`) are\n * hoocode's own former install homes, holding plugins the user installed\n * deliberately, so treating those as untrusted would break existing setups.\n */\nexport function isProjectSuppliedPlugin(pluginRoot: string, cwd: string): boolean {\n\treturn isUnderDir(pluginRoot, path.join(cwd, \".claude\", \"skills\"));\n}\n\n/** True when `target` is `root` or sits inside it. */\nfunction isUnderDir(target: string, root: string): boolean {\n\tconst normalized = path.resolve(root);\n\tif (path.resolve(target) === normalized) return true;\n\treturn path.resolve(target).startsWith(normalized.endsWith(path.sep) ? normalized : `${normalized}${path.sep}`);\n}\n\n/**\n * Standard plugin discovery directories, highest precedence first.\n *\n * `.agents/plugins/` is the cross-vendor, primary home and is listed ahead of the\n * `.hoocode/plugins/` fallback at each scope, so an `.agents`-installed plugin\n * wins over a same-id `.hoocode` one (discoverPlugins is first-wins by id).\n * Project scope beats global. The global surfaces live next to the agent dir\n * (`~/.agents`, `~/.claude` alongside `~/.hoocode`), so they stay parameterized\n * on `agentDir` rather than hardcoding the home directory.\n *\n * Two of these are *production homes* for plugins hoocode authored, and two are\n * skills directories:\n *\n * - `<cwd>/.agents/plugins` is the legacy project-local install home. Nothing\n * writes there any more; it is read so plugins installed by older versions\n * keep working.\n * - `.claude/skills` (project and personal) implements Claude Code's\n * skills-directory plugins: a folder there carrying `.claude-plugin/plugin.json`\n * is a plugin, and a folder with only a `SKILL.md` stays a plain skill —\n * `parsePluginDir` returns null for the latter, which is exactly the vendor's\n * own rule, so no special-casing is needed here.\n *\n * See docs/plugin-system-architecture.md §5.3 and §5.7.\n */\nexport function defaultPluginDirs(cwd: string, agentDir: string = getAgentDir()): string[] {\n\tconst home = path.dirname(agentDir);\n\treturn [\n\t\tpath.join(cwd, \".agents\", \"plugins\"),\n\t\tpath.join(cwd, CONFIG_DIR_NAME, \"plugins\"),\n\t\tpath.join(cwd, \".claude\", \"skills\"),\n\t\tpath.join(home, \".agents\", \"plugins\"),\n\t\tpath.join(home, \".agents\", \"publish\", \"github\"),\n\t\tpath.join(home, \".claude\", \"skills\"),\n\t\tpath.join(agentDir, \"plugins\"),\n\t];\n}\n\n/**\n * Discover plugins under `pluginDirs` and load each as a synthetic extension into\n * the given runtime/event bus. Clears the extension MCP registry first so reloads\n * rebuild the set cleanly.\n */\nexport async function loadPlugins(\n\tpluginDirs: string[],\n\tcwd: string,\n\teventBus: EventBus,\n\truntime: ExtensionRuntime,\n): Promise<{ extensions: Extension[]; errors: Array<{ path: string; error: string }> }> {\n\tclearExtensionMcpServers();\n\tconst extensions: Extension[] = [];\n\tconst errors: Array<{ path: string; error: string }> = [];\n\n\tfor (const plugin of discoverPlugins(pluginDirs)) {\n\t\ttry {\n\t\t\t// Withhold the executable half of a plugin that came with the repository\n\t\t\t// rather than from the user. Scoped to `<cwd>/.claude/skills` — the\n\t\t\t// vendor convention for repo-committed, collaborator-shared plugins,\n\t\t\t// which Claude Code itself puts behind a workspace trust dialog. The\n\t\t\t// other project paths (`.agents/plugins`, `.hoocode/plugins`) are\n\t\t\t// hoocode's own former install homes, holding plugins the user installed\n\t\t\t// deliberately, so gating those would break existing setups.\n\t\t\t// See PluginFactoryOptions.passiveOnly.\n\t\t\tconst passiveOnly = isProjectSuppliedPlugin(plugin.root, cwd);\n\t\t\tconst withheld = passiveOnly ? withheldCapabilities(plugin) : [];\n\t\t\tconst extension = await loadExtensionFromFactory(\n\t\t\t\tbuildPluginFactory(plugin, { passiveOnly }),\n\t\t\t\tcwd,\n\t\t\t\teventBus,\n\t\t\t\truntime,\n\t\t\t\tpluginExtensionPath(plugin.id),\n\t\t\t\t`plugin:${plugin.id}`,\n\t\t\t);\n\t\t\textensions.push(extension);\n\t\t\tif (withheld.length > 0) {\n\t\t\t\terrors.push({\n\t\t\t\t\tpath: plugin.manifestPath,\n\t\t\t\t\terror:\n\t\t\t\t\t\t`Project-scoped plugin \"${plugin.id}\": ${withheld.join(\" and \")} not loaded. ` +\n\t\t\t\t\t\t\"Executable capabilities from a project directory require a trust gate hoocode does not have; \" +\n\t\t\t\t\t\t\"install the plugin for your user instead if you trust it.\",\n\t\t\t\t});\n\t\t\t}\n\t\t} catch (err) {\n\t\t\terrors.push({\n\t\t\t\tpath: plugin.manifestPath,\n\t\t\t\terror: `Failed to load plugin \"${plugin.id}\": ${err instanceof Error ? err.message : String(err)}`,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn { extensions, errors };\n}\n"]}
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import type { MarketplacePlatform, PluginDraft } from "./formats/types.js";
|
|
16
16
|
import { type NormalizedPlugin } from "./manifest.js";
|
|
17
|
-
export {
|
|
17
|
+
export { resolvePluginPlatforms } from "./formats/platform-targets.js";
|
|
18
18
|
export interface AllowlistClassification {
|
|
19
19
|
/** read-only grants are as safe as a skill; mutating/exec/network/`*` grants need confirmation. */
|
|
20
20
|
risk: "read-only" | "mutating";
|
|
@@ -33,23 +33,70 @@ export interface AllowlistClassification {
|
|
|
33
33
|
*/
|
|
34
34
|
export declare function classifyAllowlist(tools: string | undefined): AllowlistClassification;
|
|
35
35
|
export interface WriteResult {
|
|
36
|
+
/** Where the plugin ended up: a production home, or the draft dir when not promoted. */
|
|
36
37
|
dest: string;
|
|
38
|
+
/** False when the caller asked to stop at the draft (gates still to run). */
|
|
39
|
+
promoted: boolean;
|
|
40
|
+
/** Platforms the draft was emitted for. */
|
|
41
|
+
targets: MarketplacePlatform[];
|
|
37
42
|
/** Written file paths, relative to the plugin root. */
|
|
38
43
|
files: string[];
|
|
39
44
|
/** Re-parsed plugin (confirms the scaffold round-trips). */
|
|
40
45
|
plugin: NormalizedPlugin | null;
|
|
41
46
|
}
|
|
42
|
-
/**
|
|
47
|
+
/** Locate an existing plugin by id across every home, or undefined. */
|
|
48
|
+
export declare function findPluginDir(cwd: string, id: string): string | undefined;
|
|
49
|
+
/** Whether the plugin at `id` was authored here (carries the provenance marker), vs. installed or hand-written. */
|
|
43
50
|
export declare function isAuthoredPlugin(cwd: string, id: string): boolean;
|
|
44
51
|
/**
|
|
45
|
-
* Render `draft` into the requested platform layouts and write it
|
|
46
|
-
*
|
|
47
|
-
*
|
|
52
|
+
* Render `draft` into the requested platform layouts and write it out.
|
|
53
|
+
*
|
|
54
|
+
* Two modes, and the distinction matters:
|
|
55
|
+
*
|
|
56
|
+
* - **Creation** (default): emit into an ephemeral draft dir, then promote into
|
|
57
|
+
* the target platform's production home, replacing whatever was there. A
|
|
58
|
+
* production home is live — `~/.claude/skills/<id>/` is loaded by Claude Code
|
|
59
|
+
* on its next session — so writing there directly would mean a plugin that
|
|
60
|
+
* failed validation, or whose confirmation was declined, is already running.
|
|
61
|
+
* Pass `promote: false` to stop at the draft and promote later with
|
|
62
|
+
* {@link promoteDraft}.
|
|
63
|
+
* - **In-place edit** (`dest` given): write the emitted files over an existing
|
|
64
|
+
* plugin directory, wherever it already lives. An edit must never relocate the
|
|
65
|
+
* plugin — a merge or a removal on a plugin sitting in the consumption home or
|
|
66
|
+
* the legacy project home would otherwise silently move it into a production
|
|
67
|
+
* home. Files not named by the emit are left alone, which is what makes the
|
|
68
|
+
* directory-scanned merge semantics work.
|
|
69
|
+
*/
|
|
70
|
+
export declare function writePluginDraft(draft: PluginDraft, platforms?: MarketplacePlatform[], options?: {
|
|
71
|
+
promote?: boolean;
|
|
72
|
+
dest?: string;
|
|
73
|
+
}): WriteResult;
|
|
74
|
+
/**
|
|
75
|
+
* Move a draft into the production home of its first target platform, replacing
|
|
76
|
+
* whatever is there. The draft directory is consumed either way.
|
|
77
|
+
*
|
|
78
|
+
* A cross-device rename fails when temp and home sit on different filesystems,
|
|
79
|
+
* so this falls back to copy-then-delete rather than assuming `rename` works.
|
|
80
|
+
*/
|
|
81
|
+
export declare function promoteDraft(draftDir: string, id: string, targets: readonly MarketplacePlatform[]): string;
|
|
82
|
+
/**
|
|
83
|
+
* Replace `dest` with the contents of a draft. Used when the destination is
|
|
84
|
+
* already known — an edit stays wherever the plugin lives, which may be the
|
|
85
|
+
* consumption home or a legacy directory rather than a production home.
|
|
86
|
+
*/
|
|
87
|
+
export declare function promoteDraftTo(draftDir: string, dest: string): string;
|
|
88
|
+
/**
|
|
89
|
+
* Whether authoring this id would clobber something **in the target platform's
|
|
90
|
+
* production home**.
|
|
91
|
+
*
|
|
92
|
+
* Scoped to the target rather than every home on purpose: a `claude` `foo` and a
|
|
93
|
+
* `github` `foo` are artifacts for two different ecosystems, not duplicates of
|
|
94
|
+
* each other, and a marketplace-installed `foo` in the consumption home is a
|
|
95
|
+
* third unrelated thing. Only a collision in the directory this write would
|
|
96
|
+
* actually land in is a collision.
|
|
48
97
|
*/
|
|
49
|
-
export declare function
|
|
50
|
-
/**
|
|
51
|
-
export declare function pluginExists(cwd: string, id: string): boolean;
|
|
52
|
-
/** Load an installed/authored plugin by id, or null if it isn't on disk / doesn't parse. */
|
|
98
|
+
export declare function pluginExists(id: string, platforms?: readonly MarketplacePlatform[]): boolean;
|
|
99
|
+
/** Load an installed/authored plugin by id from whichever home holds it, or null. */
|
|
53
100
|
export declare function getPlugin(cwd: string, id: string): NormalizedPlugin | null;
|
|
54
101
|
/**
|
|
55
102
|
* Merge inline-authored `delta` capabilities into the existing local plugin `id`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"authoring.d.ts","sourceRoot":"","sources":["../../../../src/core/extensions/plugins/authoring.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AASH,OAAO,KAAK,EAAmC,mBAAmB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE5G,OAAO,EAAE,KAAK,gBAAgB,EAA0C,MAAM,eAAe,CAAC;AAI9F,OAAO,EAAE,yBAAyB,EAAE,MAAM,+BAA+B,CAAC;AAK1E,MAAM,WAAW,uBAAuB;IACvC,mGAAmG;IACnG,IAAI,EAAE,WAAW,GAAG,UAAU,CAAC;IAC/B,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC;IACf,4GAA0G;IAC1G,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,gCAAgC;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,uBAAuB,CAuCpF;AAED,MAAM,WAAW,WAAW;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,4DAA4D;IAC5D,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAChC;AAWD,sHAAsH;AACtH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAEjE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,mBAAmB,EAAE,GAAG,WAAW,CAiBhH;AAED,yFAAyF;AACzF,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED,4FAA4F;AAC5F,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI,CAG1E;AA6DD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,gBAAgB,CAC/B,GAAG,EAAE,MAAM,EACX,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,OAAO,CAAC,WAAW,CAAC,EAC3B,SAAS,CAAC,EAAE,mBAAmB,EAAE,GAC/B,WAAW,CAuCb;AAED,iGAAiG;AACjG,UAAU,eAAe;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,4DAA4D;AAC5D,MAAM,WAAW,WAAW;IAC3B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,uDAAuD;IACvD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,kFAAkF;IAClF,OAAO,EAAE,MAAM,EAAE,CAAC;CAClB;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,GAAG,YAAY,CA8FzF","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 { existsSync, mkdirSync, 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 { resolveAuthoringPlatforms } from \"./formats/platform-targets.js\";\nimport { slug } from \"./formats/shared.js\";\nimport type { AuthoredHook, AuthoredMcpServer, MarketplacePlatform, PluginDraft } from \"./formats/types.js\";\nimport { installedPluginsDir, sanitizeForDir } from \"./install.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 --support-platform → default) lives in platform-targets.\nexport { resolveAuthoringPlatforms } from \"./formats/platform-targets.js\";\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\tdest: string;\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. Authored and\n * marketplace-installed plugins land in the same `.agents/plugins/` directory,\n * and only authored ones round-trip losslessly through our emitters — so\n * UpdatePlugin (which re-emits manifests and hook/MCP files) is gated on this\n * marker's presence. Existence is the signal; the content is informational.\n */\nconst AUTHORED_MARKER_FILE = \".authored.json\";\n\n/** Whether the plugin at `id` was authored here (carries the provenance marker), vs. installed from a marketplace. */\nexport function isAuthoredPlugin(cwd: string, id: string): boolean {\n\treturn existsSync(path.join(installedPluginsDir(cwd), sanitizeForDir(id), AUTHORED_MARKER_FILE));\n}\n\n/**\n * Render `draft` into the requested platform layouts and write it under\n * `.agents/plugins/<id>/`. Returns the destination, the emitted files, and the\n * re-parsed plugin so callers can confirm the round-trip.\n */\nexport function writePluginDraft(cwd: string, draft: PluginDraft, platforms?: MarketplacePlatform[]): WriteResult {\n\tconst targets = resolveAuthoringPlatforms(platforms ?? draft.supportPlatform);\n\tconst dest = path.join(installedPluginsDir(cwd), sanitizeForDir(draft.id));\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\tmkdirSync(dest, { recursive: true });\n\tfor (const f of byPath.values()) {\n\t\tconst abs = path.join(dest, f.path);\n\t\tmkdirSync(path.dirname(abs), { recursive: true });\n\t\twriteFileSync(abs, f.content);\n\t}\n\twriteFileSync(path.join(dest, AUTHORED_MARKER_FILE), `${JSON.stringify({ authored: true }, null, 2)}\\n`);\n\n\treturn { dest, files: [...byPath.keys(), AUTHORED_MARKER_FILE], plugin: parsePluginDir(dest) };\n}\n\n/** Whether a plugin id already exists on disk (so authoring never silently clobbers). */\nexport function pluginExists(cwd: string, id: string): boolean {\n\treturn existsSync(path.join(installedPluginsDir(cwd), sanitizeForDir(id)));\n}\n\n/** Load an installed/authored plugin by id, or null if it isn't on disk / doesn't parse. */\nexport function getPlugin(cwd: string, id: string): NormalizedPlugin | null {\n\tconst dir = path.join(installedPluginsDir(cwd), sanitizeForDir(id));\n\treturn existsSync(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 = resolveAuthoringPlatforms(platforms ?? existing.supportPlatform);\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// 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\treturn writePluginDraft(cwd, merged, targets);\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 = path.join(installedPluginsDir(cwd), sanitizeForDir(id));\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 = resolveAuthoringPlatforms(existing.supportPlatform);\n\t\twritePluginDraft(\n\t\t\tcwd,\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\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);\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.d.ts","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"]}
|
|
Binary file
|
|
@@ -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 { existsSync, mkdirSync, 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 { resolveAuthoringPlatforms } from \"./formats/platform-targets.js\";\nimport { slug } from \"./formats/shared.js\";\nimport type { AuthoredHook, AuthoredMcpServer, MarketplacePlatform, PluginDraft } from \"./formats/types.js\";\nimport { installedPluginsDir, sanitizeForDir } from \"./install.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 --support-platform → default) lives in platform-targets.\nexport { resolveAuthoringPlatforms } from \"./formats/platform-targets.js\";\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\tdest: string;\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. Authored and\n * marketplace-installed plugins land in the same `.agents/plugins/` directory,\n * and only authored ones round-trip losslessly through our emitters — so\n * UpdatePlugin (which re-emits manifests and hook/MCP files) is gated on this\n * marker's presence. Existence is the signal; the content is informational.\n */\nconst AUTHORED_MARKER_FILE = \".authored.json\";\n\n/** Whether the plugin at `id` was authored here (carries the provenance marker), vs. installed from a marketplace. */\nexport function isAuthoredPlugin(cwd: string, id: string): boolean {\n\treturn existsSync(path.join(installedPluginsDir(cwd), sanitizeForDir(id), AUTHORED_MARKER_FILE));\n}\n\n/**\n * Render `draft` into the requested platform layouts and write it under\n * `.agents/plugins/<id>/`. Returns the destination, the emitted files, and the\n * re-parsed plugin so callers can confirm the round-trip.\n */\nexport function writePluginDraft(cwd: string, draft: PluginDraft, platforms?: MarketplacePlatform[]): WriteResult {\n\tconst targets = resolveAuthoringPlatforms(platforms ?? draft.supportPlatform);\n\tconst dest = path.join(installedPluginsDir(cwd), sanitizeForDir(draft.id));\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\tmkdirSync(dest, { recursive: true });\n\tfor (const f of byPath.values()) {\n\t\tconst abs = path.join(dest, f.path);\n\t\tmkdirSync(path.dirname(abs), { recursive: true });\n\t\twriteFileSync(abs, f.content);\n\t}\n\twriteFileSync(path.join(dest, AUTHORED_MARKER_FILE), `${JSON.stringify({ authored: true }, null, 2)}\\n`);\n\n\treturn { dest, files: [...byPath.keys(), AUTHORED_MARKER_FILE], plugin: parsePluginDir(dest) };\n}\n\n/** Whether a plugin id already exists on disk (so authoring never silently clobbers). */\nexport function pluginExists(cwd: string, id: string): boolean {\n\treturn existsSync(path.join(installedPluginsDir(cwd), sanitizeForDir(id)));\n}\n\n/** Load an installed/authored plugin by id, or null if it isn't on disk / doesn't parse. */\nexport function getPlugin(cwd: string, id: string): NormalizedPlugin | null {\n\tconst dir = path.join(installedPluginsDir(cwd), sanitizeForDir(id));\n\treturn existsSync(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 = resolveAuthoringPlatforms(platforms ?? existing.supportPlatform);\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// 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\treturn writePluginDraft(cwd, merged, targets);\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 = path.join(installedPluginsDir(cwd), sanitizeForDir(id));\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 = resolveAuthoringPlatforms(existing.supportPlatform);\n\t\twritePluginDraft(\n\t\t\tcwd,\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\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);\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":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC3F,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAC5E,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACzF,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAE3C,OAAO,EAAE,mBAAmB,EAAE,eAAe,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACzG,OAAO,EAAiD,cAAc,EAAE,MAAM,eAAe,CAAC;AAE9F,8EAA8E;AAC9E,2EAAuE;AACvE,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAEvE;;;;;;;GAOG;AACH,SAAS,cAAc,CAAC,QAA0B,EAAE,QAAyC,EAAyB;IACrH,IAAI,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;IAC1D,IAAI,QAAQ,CAAC,eAAe,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAC;IAC9E,OAAO,sBAAsB,EAAE,CAAC;AAAA,CAChC;AAED,sGAAsG;AACtG,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,WAAW,CAAC,CAAC,CAAC;AAaxF;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,KAAyB,EAA2B;IACrF,MAAM,MAAM,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;SAC1B,KAAK,CAAC,QAAQ,CAAC;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC,CAAC;IAClB,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,wBAAwB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;IAEpH,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,kBAAkB,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IAC/E,CAAC;IAED,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACxB,MAAM,GAAG,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YAChC,QAAQ,GAAG,IAAI,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;YACrC,SAAS;QACV,CAAC;QACD,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC;YAAE,SAAS,CAAC,+CAA+C;QAC/G,MAAM,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC;QACxC,IAAI,CAAC,MAAM,EAAE,CAAC;YACb,QAAQ,GAAG,IAAI,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,sDAAoD,CAAC,CAAC;YAC/E,SAAS;QACV,CAAC;QACD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;YACjC,QAAQ,GAAG,IAAI,CAAC;YAChB,OAAO,CAAC,IAAI,CAAC,WAAW,MAAM,mBAAmB,CAAC,CAAC;QACpD,CAAC;IACF,CAAC;IAED,OAAO;QACN,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW;QACzC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,sBAAsB;QACpD,WAAW;QACX,MAAM;KACN,CAAC;AAAA,CACF;AAeD;;;;;;;GAOG;AACH,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AAE9C,uEAAuE;AACvE,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,EAAU,EAAsB;IAC1E,OAAO,mBAAmB,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AAAA,CACnE;AAED,mHAAmH;AACnH,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,EAAU,EAAW;IAClE,MAAM,GAAG,GAAG,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACnC,OAAO,CAAC,CAAC,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC,CAAC;AAAA,CACjE;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,gBAAgB,CAC/B,KAAkB,EAClB,SAAiC,EACjC,OAA8C,EAChC;IACd,oFAAoF;IACpF,MAAM,OAAO,GAAG,sBAAsB,CAAC,SAAS,IAAI,KAAK,CAAC,eAAe,EAAE,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACrG,MAAM,KAAK,GAAG,gBAAgB,CAAC,EAAE,GAAG,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;IAEhF,uEAAuE;IACvE,qEAAmE;IACnE,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACtD,MAAM,SAAS,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC;QACnC,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,EAAE,CAAC;YACjC,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACpC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAClD,aAAa,CAAC,GAAG,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;QAC/B,CAAC;QACD,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IAAA,CACzG,CAAC;IACF,MAAM,OAAO,GAAG,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,EAAE,EAAE,oBAAoB,CAAC,EAAE,OAAO,EAAE,CAAC;IAE7E,IAAI,OAAO,EAAE,IAAI,EAAE,CAAC;QACnB,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;IACjG,CAAC;IAED,MAAM,QAAQ,GAAG,YAAY,EAAE,CAAC;IAChC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACpB,IAAI,OAAO,EAAE,OAAO,KAAK,KAAK,EAAE,CAAC;QAChC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC;IAC1F,CAAC;IACD,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IACvD,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;AAAA,CAC1E;AAED;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,EAAU,EAAE,OAAuC,EAAU;IAC3G,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,IAAI,sBAAsB,EAAE,CAAC,CAAC,CAAC,CAAC;IACpF,OAAO,cAAc,CAAC,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,CAAC;AAAA,CACnE;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB,EAAE,IAAY,EAAU;IACtE,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,IAAI,CAAC;QACJ,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;IAAC,MAAM,CAAC;QACR,MAAM,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC5C,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,IAAI,CAAC;AAAA,CACZ;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,YAAY,CAAC,EAAU,EAAE,SAA0C,EAAW;IAC7F,MAAM,MAAM,GAAG,sBAAsB,CAAC,SAAS,EAAE,MAAM,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9E,OAAO,UAAU,CAAC,mBAAmB,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;AAAA,CACnD;AAED,qFAAqF;AACrF,MAAM,UAAU,SAAS,CAAC,GAAW,EAAE,EAAU,EAA2B;IAC3E,MAAM,GAAG,GAAG,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACnC,OAAO,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAAA,CACxC;AAED,wGAAwG;AACxG,SAAS,qBAAqB,CAAC,MAAyB,EAAkB;IACzE,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACtD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC5B,KAAK,MAAM,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;gBAC/B,IAAI,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,IAAI,CAAC,GAAG,CAAC,OAAO;oBAAE,SAAS;gBAC9D,GAAG,CAAC,IAAI,CAAC;oBACR,KAAK;oBACL,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;oBACpD,OAAO,EAAE,GAAG,CAAC,OAAO;oBACpB,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAChD,CAAC,CAAC;YACJ,CAAC;QACF,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAC;AAAA,CACX;AAED;;;;;GAKG;AACH,SAAS,mBAAmB,CAAC,MAA+B,EAAuB;IAClF,MAAM,GAAG,GAAwB,EAAE,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACpD,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,SAAS;QAClD,MAAM,MAAM,GAAG,KAA6D,CAAC;QAC7E,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;YACxC,MAAM,IAAI,KAAK,CACd,6BAA6B,IAAI,+EAA+E;gBAC/G,+CAA+C,CAChD,CAAC;QACH,CAAC;QACD,GAAG,CAAC,IAAI,CAAC;YACR,IAAI;YACJ,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,GAA6B,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtG,CAAC,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AAAA,CACX;AAED,8FAA8F;AAC9F,SAAS,WAAW,CAAC,KAAqB,EAAkB;IAC3D,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,MAAM,GAAG,GAAmB,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,IAAI,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;QACzD,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAC5B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACb,CAAC;IACD,OAAO,GAAG,CAAC;AAAA,CACX;AAED;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,UAAU,gBAAgB,CAC/B,GAAW,EACX,EAAU,EACV,KAA2B,EAC3B,SAAiC,EACnB;IACd,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,yBAAyB,EAAE,6DAA6D,CAAC,CAAC;IAC3G,CAAC;IACD,2EAA2E;IAC3E,8EAA8E;IAC9E,+EAA+E;IAC/E,8DAA8D;IAC9D,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CACd,yBAAyB,EAAE,mCAAmC,oBAAoB,YAAY;YAC7F,8CAA8C,CAC/C,CAAC;IACH,CAAC;IAED,MAAM,aAAa,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,qBAAqB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAClF,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,GAAG,aAAa,EAAE,GAAG,CAAC,KAAK,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAE5E,MAAM,SAAS,GAAG,IAAI,GAAG,EAA6B,CAAC;IACvD,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE;QAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC9G,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,UAAU,IAAI,EAAE;QAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAEjE,MAAM,OAAO,GAAG,cAAc,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACpD,MAAM,MAAM,GAAgB;QAC3B,EAAE;QACF,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,QAAQ,CAAC,OAAO;QAC1C,WAAW,EAAE,KAAK,CAAC,WAAW,IAAI,QAAQ,CAAC,WAAW;QACtD,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,QAAQ,CAAC,MAAM;QACvC,eAAe,EAAE,OAAO;QACxB,qDAAqD;QACrD,aAAa,EAAE,QAAQ,CAAC,aAAa;QACrC,2EAA2E;QAC3E,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,MAAM,EAAE,KAAK,CAAC,MAAM;QACpB,2EAA2E;QAC3E,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;QACnD,UAAU,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;KAChE,CAAC;IACF,uEAAuE;IACvE,OAAO,gBAAgB,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC;AAAA,CAC3E;AA0BD,SAAS,gBAAgB,CAAC,CAAkB,EAAU;IACrD,OAAO,SAAS,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC;AAAA,CAC7I;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAW,EAAE,EAAU,EAAE,IAAiB,EAAgB;IAC1F,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACpC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,8BAA8B,EAAE,uBAAuB,CAAC,CAAC;IAC1E,CAAC;IACD,IAAI,CAAC,gBAAgB,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CACd,8BAA8B,EAAE,mCAAmC,oBAAoB,YAAY;YAClG,8CAA8C,CAC/C,CAAC;IACH,CAAC;IACD,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACpC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,EAAE,uBAAuB,CAAC,CAAC;IACpF,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,4EAA4E;IAC5E,MAAM,WAAW,GAAyD;QACzE,GAAG,CAAC,IAAI,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAA4B,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACvG,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAA4B,EAAE,CAAC;YAC7D,SAAS;YACT,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;SACtC,CAAC;QACF,GAAG,CAAC,IAAI,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAA4B,EAAE,CAAC;YAC9D,UAAU;YACV,CAAC;YACD,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;SACpC,CAAC;KACF,CAAC;IACF,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,WAAW,EAAE,CAAC;QAC7C,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QACjC,IAAI,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9C,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC,CAAC;QACnC,CAAC;aAAM,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,KAAK,IAAI,GAAG,CAAC,CAAC;QACnC,CAAC;IACF,CAAC;IAED,yEAAyE;IACzE,IAAI,iBAAiB,GAAG,KAAK,CAAC;IAC9B,IAAI,cAAc,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,qBAAqB,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjF,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,EAAE,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC;QACrC,cAAc,GAAG,cAAc,CAAC,MAAM,CACrC,CAAC,CAAC,EAAE,EAAE,CACL,CAAC,CACA,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,KAAK;YACnB,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;YAC5D,CAAC,CAAC,CAAC,OAAO,KAAK,SAAS,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,OAAO,CAAC,CACpD,CACF,CAAC;QACF,MAAM,CAAC,GAAG,MAAM,GAAG,cAAc,CAAC,MAAM,CAAC;QACzC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC5C,iBAAiB,GAAG,IAAI,CAAC;QAC1B,CAAC;aAAM,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,CAAC;IACF,CAAC;IACD,IAAI,YAAY,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,mBAAmB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvF,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,IAAI,EAAE,EAAE,CAAC;QAC1C,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC;QACnC,YAAY,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAC3D,IAAI,YAAY,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,eAAe,IAAI,GAAG,CAAC,CAAC;YACrC,iBAAiB,GAAG,IAAI,CAAC;QAC1B,CAAC;aAAM,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,eAAe,IAAI,GAAG,CAAC,CAAC;QACtC,CAAC;IACF,CAAC;IAED,IAAI,iBAAiB,EAAE,CAAC;QACvB,MAAM,OAAO,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QACzC,gBAAgB,CACf;YACC,EAAE;YACF,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,WAAW,EAAE,QAAQ,CAAC,WAAW;YACjC,MAAM,EAAE,QAAQ,CAAC,MAAM;YACvB,eAAe,EAAE,OAAO;YACxB,aAAa,EAAE,QAAQ,CAAC,aAAa;YACrC,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS;YACzD,UAAU,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS;SAC1D,EACD,OAAO,EACP,EAAE,IAAI,EAAE,CACR,CAAC;QACF,yEAAyE;QACzE,8EAA4E;QAC5E,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,YAAY,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACjG,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;YAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAAA,CAClC","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"]}
|