@hashicorp/kits 0.1.0
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/README.md +619 -0
- package/bin/kits.js +8 -0
- package/dist/adapters/base-adapter.d.ts +231 -0
- package/dist/adapters/base-adapter.d.ts.map +1 -0
- package/dist/adapters/base-adapter.js +703 -0
- package/dist/adapters/base-adapter.js.map +1 -0
- package/dist/adapters/claude-code/detection.d.ts +63 -0
- package/dist/adapters/claude-code/detection.d.ts.map +1 -0
- package/dist/adapters/claude-code/detection.js +154 -0
- package/dist/adapters/claude-code/detection.js.map +1 -0
- package/dist/adapters/claude-code/index.d.ts +178 -0
- package/dist/adapters/claude-code/index.d.ts.map +1 -0
- package/dist/adapters/claude-code/index.js +643 -0
- package/dist/adapters/claude-code/index.js.map +1 -0
- package/dist/adapters/claude-code/installer.d.ts +161 -0
- package/dist/adapters/claude-code/installer.d.ts.map +1 -0
- package/dist/adapters/claude-code/installer.js +413 -0
- package/dist/adapters/claude-code/installer.js.map +1 -0
- package/dist/adapters/claude-code/model-mapping.d.ts +7 -0
- package/dist/adapters/claude-code/model-mapping.d.ts.map +1 -0
- package/dist/adapters/claude-code/model-mapping.js +14 -0
- package/dist/adapters/claude-code/model-mapping.js.map +1 -0
- package/dist/adapters/claude-code/tool-mapping.d.ts +18 -0
- package/dist/adapters/claude-code/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/claude-code/tool-mapping.js +31 -0
- package/dist/adapters/claude-code/tool-mapping.js.map +1 -0
- package/dist/adapters/codex/detection.d.ts +60 -0
- package/dist/adapters/codex/detection.d.ts.map +1 -0
- package/dist/adapters/codex/detection.js +146 -0
- package/dist/adapters/codex/detection.js.map +1 -0
- package/dist/adapters/codex/index.d.ts +167 -0
- package/dist/adapters/codex/index.d.ts.map +1 -0
- package/dist/adapters/codex/index.js +344 -0
- package/dist/adapters/codex/index.js.map +1 -0
- package/dist/adapters/codex/installer.d.ts +147 -0
- package/dist/adapters/codex/installer.d.ts.map +1 -0
- package/dist/adapters/codex/installer.js +229 -0
- package/dist/adapters/codex/installer.js.map +1 -0
- package/dist/adapters/codex/model-mapping.d.ts +7 -0
- package/dist/adapters/codex/model-mapping.d.ts.map +1 -0
- package/dist/adapters/codex/model-mapping.js +14 -0
- package/dist/adapters/codex/model-mapping.js.map +1 -0
- package/dist/adapters/codex/tool-mapping.d.ts +19 -0
- package/dist/adapters/codex/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/codex/tool-mapping.js +32 -0
- package/dist/adapters/codex/tool-mapping.js.map +1 -0
- package/dist/adapters/command-parser.d.ts +72 -0
- package/dist/adapters/command-parser.d.ts.map +1 -0
- package/dist/adapters/command-parser.js +222 -0
- package/dist/adapters/command-parser.js.map +1 -0
- package/dist/adapters/file-operations.d.ts +164 -0
- package/dist/adapters/file-operations.d.ts.map +1 -0
- package/dist/adapters/file-operations.js +526 -0
- package/dist/adapters/file-operations.js.map +1 -0
- package/dist/adapters/gemini-cli/detection.d.ts +57 -0
- package/dist/adapters/gemini-cli/detection.d.ts.map +1 -0
- package/dist/adapters/gemini-cli/detection.js +143 -0
- package/dist/adapters/gemini-cli/detection.js.map +1 -0
- package/dist/adapters/gemini-cli/index.d.ts +182 -0
- package/dist/adapters/gemini-cli/index.d.ts.map +1 -0
- package/dist/adapters/gemini-cli/index.js +598 -0
- package/dist/adapters/gemini-cli/index.js.map +1 -0
- package/dist/adapters/gemini-cli/installer.d.ts +158 -0
- package/dist/adapters/gemini-cli/installer.d.ts.map +1 -0
- package/dist/adapters/gemini-cli/installer.js +457 -0
- package/dist/adapters/gemini-cli/installer.js.map +1 -0
- package/dist/adapters/gemini-cli/model-mapping.d.ts +7 -0
- package/dist/adapters/gemini-cli/model-mapping.d.ts.map +1 -0
- package/dist/adapters/gemini-cli/model-mapping.js +14 -0
- package/dist/adapters/gemini-cli/model-mapping.js.map +1 -0
- package/dist/adapters/gemini-cli/tool-mapping.d.ts +18 -0
- package/dist/adapters/gemini-cli/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/gemini-cli/tool-mapping.js +31 -0
- package/dist/adapters/gemini-cli/tool-mapping.js.map +1 -0
- package/dist/adapters/github-copilot/detection.d.ts +58 -0
- package/dist/adapters/github-copilot/detection.d.ts.map +1 -0
- package/dist/adapters/github-copilot/detection.js +144 -0
- package/dist/adapters/github-copilot/detection.js.map +1 -0
- package/dist/adapters/github-copilot/index.d.ts +203 -0
- package/dist/adapters/github-copilot/index.d.ts.map +1 -0
- package/dist/adapters/github-copilot/index.js +595 -0
- package/dist/adapters/github-copilot/index.js.map +1 -0
- package/dist/adapters/github-copilot/installer.d.ts +124 -0
- package/dist/adapters/github-copilot/installer.d.ts.map +1 -0
- package/dist/adapters/github-copilot/installer.js +343 -0
- package/dist/adapters/github-copilot/installer.js.map +1 -0
- package/dist/adapters/github-copilot/model-mapping.d.ts +7 -0
- package/dist/adapters/github-copilot/model-mapping.d.ts.map +1 -0
- package/dist/adapters/github-copilot/model-mapping.js +14 -0
- package/dist/adapters/github-copilot/model-mapping.js.map +1 -0
- package/dist/adapters/github-copilot/tool-mapping.d.ts +18 -0
- package/dist/adapters/github-copilot/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/github-copilot/tool-mapping.js +31 -0
- package/dist/adapters/github-copilot/tool-mapping.js.map +1 -0
- package/dist/adapters/index.d.ts +39 -0
- package/dist/adapters/index.d.ts.map +1 -0
- package/dist/adapters/index.js +76 -0
- package/dist/adapters/index.js.map +1 -0
- package/dist/adapters/interface.d.ts +9 -0
- package/dist/adapters/interface.d.ts.map +1 -0
- package/dist/adapters/interface.js +8 -0
- package/dist/adapters/interface.js.map +1 -0
- package/dist/adapters/model-templating.d.ts +16 -0
- package/dist/adapters/model-templating.d.ts.map +1 -0
- package/dist/adapters/model-templating.js +52 -0
- package/dist/adapters/model-templating.js.map +1 -0
- package/dist/adapters/opencode/detection.d.ts +57 -0
- package/dist/adapters/opencode/detection.d.ts.map +1 -0
- package/dist/adapters/opencode/detection.js +140 -0
- package/dist/adapters/opencode/detection.js.map +1 -0
- package/dist/adapters/opencode/index.d.ts +168 -0
- package/dist/adapters/opencode/index.d.ts.map +1 -0
- package/dist/adapters/opencode/index.js +494 -0
- package/dist/adapters/opencode/index.js.map +1 -0
- package/dist/adapters/opencode/installer.d.ts +91 -0
- package/dist/adapters/opencode/installer.d.ts.map +1 -0
- package/dist/adapters/opencode/installer.js +290 -0
- package/dist/adapters/opencode/installer.js.map +1 -0
- package/dist/adapters/opencode/model-mapping.d.ts +7 -0
- package/dist/adapters/opencode/model-mapping.d.ts.map +1 -0
- package/dist/adapters/opencode/model-mapping.js +14 -0
- package/dist/adapters/opencode/model-mapping.js.map +1 -0
- package/dist/adapters/opencode/tool-mapping.d.ts +18 -0
- package/dist/adapters/opencode/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/opencode/tool-mapping.js +31 -0
- package/dist/adapters/opencode/tool-mapping.js.map +1 -0
- package/dist/adapters/registry.d.ts +154 -0
- package/dist/adapters/registry.d.ts.map +1 -0
- package/dist/adapters/registry.js +223 -0
- package/dist/adapters/registry.js.map +1 -0
- package/dist/adapters/skill-frontmatter.d.ts +34 -0
- package/dist/adapters/skill-frontmatter.d.ts.map +1 -0
- package/dist/adapters/skill-frontmatter.js +110 -0
- package/dist/adapters/skill-frontmatter.js.map +1 -0
- package/dist/adapters/subagent-frontmatter.d.ts +22 -0
- package/dist/adapters/subagent-frontmatter.d.ts.map +1 -0
- package/dist/adapters/subagent-frontmatter.js +80 -0
- package/dist/adapters/subagent-frontmatter.js.map +1 -0
- package/dist/adapters/tool-templating.d.ts +162 -0
- package/dist/adapters/tool-templating.d.ts.map +1 -0
- package/dist/adapters/tool-templating.js +273 -0
- package/dist/adapters/tool-templating.js.map +1 -0
- package/dist/adapters/types.d.ts +347 -0
- package/dist/adapters/types.d.ts.map +1 -0
- package/dist/adapters/types.js +33 -0
- package/dist/adapters/types.js.map +1 -0
- package/dist/cli/index.d.ts +10 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +261 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/info.d.ts +20 -0
- package/dist/cli/info.d.ts.map +1 -0
- package/dist/cli/info.js +194 -0
- package/dist/cli/info.js.map +1 -0
- package/dist/cli/install.d.ts +21 -0
- package/dist/cli/install.d.ts.map +1 -0
- package/dist/cli/install.js +1624 -0
- package/dist/cli/install.js.map +1 -0
- package/dist/cli/list.d.ts +19 -0
- package/dist/cli/list.d.ts.map +1 -0
- package/dist/cli/list.js +216 -0
- package/dist/cli/list.js.map +1 -0
- package/dist/cli/types.d.ts +246 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +25 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/uninstall.d.ts +20 -0
- package/dist/cli/uninstall.d.ts.map +1 -0
- package/dist/cli/uninstall.js +393 -0
- package/dist/cli/uninstall.js.map +1 -0
- package/dist/cli/upgrade.d.ts +20 -0
- package/dist/cli/upgrade.d.ts.map +1 -0
- package/dist/cli/upgrade.js +372 -0
- package/dist/cli/upgrade.js.map +1 -0
- package/dist/cli/validate.d.ts +14 -0
- package/dist/cli/validate.d.ts.map +1 -0
- package/dist/cli/validate.js +307 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/core/debug.d.ts +23 -0
- package/dist/core/debug.d.ts.map +1 -0
- package/dist/core/debug.js +69 -0
- package/dist/core/debug.js.map +1 -0
- package/dist/core/hook-instance.d.ts +8 -0
- package/dist/core/hook-instance.d.ts.map +1 -0
- package/dist/core/hook-instance.js +62 -0
- package/dist/core/hook-instance.js.map +1 -0
- package/dist/core/mcp-instance.d.ts +13 -0
- package/dist/core/mcp-instance.d.ts.map +1 -0
- package/dist/core/mcp-instance.js +80 -0
- package/dist/core/mcp-instance.js.map +1 -0
- package/dist/core/types.d.ts +461 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +42 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/upgrade-executor.d.ts +70 -0
- package/dist/core/upgrade-executor.d.ts.map +1 -0
- package/dist/core/upgrade-executor.js +368 -0
- package/dist/core/upgrade-executor.js.map +1 -0
- package/dist/discovery/fetcher-registry.d.ts +87 -0
- package/dist/discovery/fetcher-registry.d.ts.map +1 -0
- package/dist/discovery/fetcher-registry.js +119 -0
- package/dist/discovery/fetcher-registry.js.map +1 -0
- package/dist/discovery/git-fetcher.d.ts +61 -0
- package/dist/discovery/git-fetcher.d.ts.map +1 -0
- package/dist/discovery/git-fetcher.js +150 -0
- package/dist/discovery/git-fetcher.js.map +1 -0
- package/dist/discovery/index.d.ts +13 -0
- package/dist/discovery/index.d.ts.map +1 -0
- package/dist/discovery/index.js +15 -0
- package/dist/discovery/index.js.map +1 -0
- package/dist/discovery/kit-scanner.d.ts +55 -0
- package/dist/discovery/kit-scanner.d.ts.map +1 -0
- package/dist/discovery/kit-scanner.js +305 -0
- package/dist/discovery/kit-scanner.js.map +1 -0
- package/dist/discovery/local-fetcher.d.ts +38 -0
- package/dist/discovery/local-fetcher.d.ts.map +1 -0
- package/dist/discovery/local-fetcher.js +100 -0
- package/dist/discovery/local-fetcher.js.map +1 -0
- package/dist/discovery/source-parser.d.ts +33 -0
- package/dist/discovery/source-parser.d.ts.map +1 -0
- package/dist/discovery/source-parser.js +136 -0
- package/dist/discovery/source-parser.js.map +1 -0
- package/dist/discovery/types.d.ts +145 -0
- package/dist/discovery/types.d.ts.map +1 -0
- package/dist/discovery/types.js +18 -0
- package/dist/discovery/types.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest/index.d.ts +79 -0
- package/dist/manifest/index.d.ts.map +1 -0
- package/dist/manifest/index.js +200 -0
- package/dist/manifest/index.js.map +1 -0
- package/dist/manifest/read.d.ts +32 -0
- package/dist/manifest/read.d.ts.map +1 -0
- package/dist/manifest/read.js +88 -0
- package/dist/manifest/read.js.map +1 -0
- package/dist/manifest/types.d.ts +119 -0
- package/dist/manifest/types.d.ts.map +1 -0
- package/dist/manifest/types.js +44 -0
- package/dist/manifest/types.js.map +1 -0
- package/dist/manifest/upgrade-check.d.ts +72 -0
- package/dist/manifest/upgrade-check.d.ts.map +1 -0
- package/dist/manifest/upgrade-check.js +215 -0
- package/dist/manifest/upgrade-check.js.map +1 -0
- package/dist/manifest/utils.d.ts +35 -0
- package/dist/manifest/utils.d.ts.map +1 -0
- package/dist/manifest/utils.js +57 -0
- package/dist/manifest/utils.js.map +1 -0
- package/dist/manifest/write.d.ts +44 -0
- package/dist/manifest/write.d.ts.map +1 -0
- package/dist/manifest/write.js +77 -0
- package/dist/manifest/write.js.map +1 -0
- package/dist/resolution/env-resolver.d.ts +81 -0
- package/dist/resolution/env-resolver.d.ts.map +1 -0
- package/dist/resolution/env-resolver.js +233 -0
- package/dist/resolution/env-resolver.js.map +1 -0
- package/dist/resolution/index.d.ts +55 -0
- package/dist/resolution/index.d.ts.map +1 -0
- package/dist/resolution/index.js +412 -0
- package/dist/resolution/index.js.map +1 -0
- package/dist/resolution/multi-kit-resolver.d.ts +43 -0
- package/dist/resolution/multi-kit-resolver.d.ts.map +1 -0
- package/dist/resolution/multi-kit-resolver.js +258 -0
- package/dist/resolution/multi-kit-resolver.js.map +1 -0
- package/dist/resolution/primitive-paths.d.ts +17 -0
- package/dist/resolution/primitive-paths.d.ts.map +1 -0
- package/dist/resolution/primitive-paths.js +59 -0
- package/dist/resolution/primitive-paths.js.map +1 -0
- package/dist/resolution/primitives-registry.d.ts +137 -0
- package/dist/resolution/primitives-registry.d.ts.map +1 -0
- package/dist/resolution/primitives-registry.js +295 -0
- package/dist/resolution/primitives-registry.js.map +1 -0
- package/dist/resolution/reference-parser.d.ts +62 -0
- package/dist/resolution/reference-parser.d.ts.map +1 -0
- package/dist/resolution/reference-parser.js +182 -0
- package/dist/resolution/reference-parser.js.map +1 -0
- package/dist/resolution/types.d.ts +77 -0
- package/dist/resolution/types.d.ts.map +1 -0
- package/dist/resolution/types.js +13 -0
- package/dist/resolution/types.js.map +1 -0
- package/dist/resolution/version-resolver.d.ts +76 -0
- package/dist/resolution/version-resolver.d.ts.map +1 -0
- package/dist/resolution/version-resolver.js +269 -0
- package/dist/resolution/version-resolver.js.map +1 -0
- package/dist/tui/compatibility.d.ts +80 -0
- package/dist/tui/compatibility.d.ts.map +1 -0
- package/dist/tui/compatibility.js +355 -0
- package/dist/tui/compatibility.js.map +1 -0
- package/dist/tui/env-prompt.d.ts +129 -0
- package/dist/tui/env-prompt.d.ts.map +1 -0
- package/dist/tui/env-prompt.js +488 -0
- package/dist/tui/env-prompt.js.map +1 -0
- package/dist/tui/harness-select.d.ts +54 -0
- package/dist/tui/harness-select.d.ts.map +1 -0
- package/dist/tui/harness-select.js +171 -0
- package/dist/tui/harness-select.js.map +1 -0
- package/dist/tui/index.d.ts +112 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +213 -0
- package/dist/tui/index.js.map +1 -0
- package/dist/tui/kit-select.d.ts +72 -0
- package/dist/tui/kit-select.d.ts.map +1 -0
- package/dist/tui/kit-select.js +209 -0
- package/dist/tui/kit-select.js.map +1 -0
- package/dist/tui/progress.d.ts +75 -0
- package/dist/tui/progress.d.ts.map +1 -0
- package/dist/tui/progress.js +267 -0
- package/dist/tui/progress.js.map +1 -0
- package/dist/tui/resolution.d.ts +62 -0
- package/dist/tui/resolution.d.ts.map +1 -0
- package/dist/tui/resolution.js +261 -0
- package/dist/tui/resolution.js.map +1 -0
- package/dist/tui/scope-compatibility.d.ts +139 -0
- package/dist/tui/scope-compatibility.d.ts.map +1 -0
- package/dist/tui/scope-compatibility.js +230 -0
- package/dist/tui/scope-compatibility.js.map +1 -0
- package/dist/tui/scope-select.d.ts +67 -0
- package/dist/tui/scope-select.d.ts.map +1 -0
- package/dist/tui/scope-select.js +134 -0
- package/dist/tui/scope-select.js.map +1 -0
- package/dist/tui/spinner.d.ts +114 -0
- package/dist/tui/spinner.d.ts.map +1 -0
- package/dist/tui/spinner.js +186 -0
- package/dist/tui/spinner.js.map +1 -0
- package/dist/tui/summary.d.ts +71 -0
- package/dist/tui/summary.d.ts.map +1 -0
- package/dist/tui/summary.js +343 -0
- package/dist/tui/summary.js.map +1 -0
- package/dist/tui/types.d.ts +234 -0
- package/dist/tui/types.d.ts.map +1 -0
- package/dist/tui/types.js +7 -0
- package/dist/tui/types.js.map +1 -0
- package/dist/tui/upgrade-select.d.ts +73 -0
- package/dist/tui/upgrade-select.d.ts.map +1 -0
- package/dist/tui/upgrade-select.js +324 -0
- package/dist/tui/upgrade-select.js.map +1 -0
- package/dist/validation/index.d.ts +13 -0
- package/dist/validation/index.d.ts.map +1 -0
- package/dist/validation/index.js +13 -0
- package/dist/validation/index.js.map +1 -0
- package/dist/validation/source.d.ts +14 -0
- package/dist/validation/source.d.ts.map +1 -0
- package/dist/validation/source.js +51 -0
- package/dist/validation/source.js.map +1 -0
- package/dist/validation/utils.d.ts +29 -0
- package/dist/validation/utils.d.ts.map +1 -0
- package/dist/validation/utils.js +89 -0
- package/dist/validation/utils.js.map +1 -0
- package/dist/validation/validate-commands.d.ts +28 -0
- package/dist/validation/validate-commands.d.ts.map +1 -0
- package/dist/validation/validate-commands.js +151 -0
- package/dist/validation/validate-commands.js.map +1 -0
- package/dist/validation/validate-hooks.d.ts +13 -0
- package/dist/validation/validate-hooks.d.ts.map +1 -0
- package/dist/validation/validate-hooks.js +272 -0
- package/dist/validation/validate-hooks.js.map +1 -0
- package/dist/validation/validate-kits.d.ts +15 -0
- package/dist/validation/validate-kits.d.ts.map +1 -0
- package/dist/validation/validate-kits.js +185 -0
- package/dist/validation/validate-kits.js.map +1 -0
- package/dist/validation/validate-mcp.d.ts +12 -0
- package/dist/validation/validate-mcp.d.ts.map +1 -0
- package/dist/validation/validate-mcp.js +132 -0
- package/dist/validation/validate-mcp.js.map +1 -0
- package/dist/validation/validate-skills.d.ts +24 -0
- package/dist/validation/validate-skills.d.ts.map +1 -0
- package/dist/validation/validate-skills.js +223 -0
- package/dist/validation/validate-skills.js.map +1 -0
- package/dist/validation/validate-subagents.d.ts +27 -0
- package/dist/validation/validate-subagents.d.ts.map +1 -0
- package/dist/validation/validate-subagents.js +269 -0
- package/dist/validation/validate-subagents.js.map +1 -0
- package/package.json +91 -0
- package/schemas/command.schema.json +23 -0
- package/schemas/examples/hook-binding-valid.json +20 -0
- package/schemas/examples/hook-program-valid.json +25 -0
- package/schemas/examples/http-server-valid.json +82 -0
- package/schemas/examples/invalid-sensitive-header-no-envvar.json +16 -0
- package/schemas/examples/invalid-sensitive-header-with-value.json +17 -0
- package/schemas/examples/invalid-sensitive-var-with-default.json +19 -0
- package/schemas/examples/stdio-server-valid.json +55 -0
- package/schemas/hook-binding.schema.json +63 -0
- package/schemas/hook-program.schema.json +104 -0
- package/schemas/kit.schema.json +338 -0
- package/schemas/kits.schema.json +117 -0
- package/schemas/manifest.schema.json +200 -0
- package/schemas/mcp-server.schema.json +305 -0
- package/schemas/primitives.schema.json +118 -0
- package/schemas/skill.schema.json +96 -0
- package/schemas/subagent.schema.json +107 -0
|
@@ -0,0 +1,703 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base adapter class providing common functionality for harness adapters.
|
|
3
|
+
*
|
|
4
|
+
* This abstract class implements shared logic that all harness-specific adapters
|
|
5
|
+
* can use, reducing code duplication and ensuring consistent behavior across
|
|
6
|
+
* different AI agent harnesses.
|
|
7
|
+
*/
|
|
8
|
+
import * as path from "node:path";
|
|
9
|
+
import { expandPath, pathExists, isDirectory, copyFile, copyDirectory, writeTransformed, readFile, createSimpleBackup, rollbackOperations, ensureDirectory, remove, } from "./file-operations.js";
|
|
10
|
+
import { processToolTemplates as processTemplates } from "./tool-templating.js";
|
|
11
|
+
import { parseCommandFrontmatter } from "./command-parser.js";
|
|
12
|
+
import { mapAllowedTools, parseSkillFrontmatter, serializeSkillFrontmatter } from "./skill-frontmatter.js";
|
|
13
|
+
import { mapSubagentTools, parseSubagentFrontmatter, serializeSubagentFrontmatter, } from "./subagent-frontmatter.js";
|
|
14
|
+
import { resolveModelTemplate } from "./model-templating.js";
|
|
15
|
+
/**
|
|
16
|
+
* Namespace separator for primitive names.
|
|
17
|
+
*/
|
|
18
|
+
export const NAMESPACE_SEPARATOR = ".";
|
|
19
|
+
/**
|
|
20
|
+
* Abstract base class for kit adapters.
|
|
21
|
+
*
|
|
22
|
+
* Subclasses must implement abstract methods for harness-specific behavior
|
|
23
|
+
* while inheriting common functionality from this base class.
|
|
24
|
+
*/
|
|
25
|
+
export class BaseAdapter {
|
|
26
|
+
/**
|
|
27
|
+
* Filter subagent frontmatter for this harness.
|
|
28
|
+
*/
|
|
29
|
+
filterSubagentFrontmatter(frontmatter, _metadata) {
|
|
30
|
+
return frontmatter;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Resolve canonical subagent hook bindings to harness-specific format.
|
|
34
|
+
*/
|
|
35
|
+
mapSubagentHooks(frontmatter, _resolvedPrimitives, _kitName, _paths, _scope, _projectRoot) {
|
|
36
|
+
return frontmatter;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Filter skill frontmatter for this harness.
|
|
40
|
+
*
|
|
41
|
+
* Default behavior preserves all fields.
|
|
42
|
+
*/
|
|
43
|
+
filterSkillFrontmatter(frontmatter, _metadata) {
|
|
44
|
+
return frontmatter;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Resolve canonical skill hook bindings to harness-specific format.
|
|
48
|
+
*/
|
|
49
|
+
mapSkillHooks(frontmatter, _resolvedPrimitives, _kitName, _paths, _scope, _projectRoot) {
|
|
50
|
+
return frontmatter;
|
|
51
|
+
}
|
|
52
|
+
// ============================================================
|
|
53
|
+
// Common implementations
|
|
54
|
+
// ============================================================
|
|
55
|
+
/**
|
|
56
|
+
* Check if a kit is compatible with this harness at the given scope.
|
|
57
|
+
*
|
|
58
|
+
* @param kit - Kit manifest to check
|
|
59
|
+
* @param scope - Installation scope (defaults to "global")
|
|
60
|
+
*/
|
|
61
|
+
checkCompatibility(kit, scope) {
|
|
62
|
+
const effectiveScope = scope ?? "global";
|
|
63
|
+
const supportedPrimitives = this.getSupportedPrimitives(effectiveScope);
|
|
64
|
+
const requiredPrimitives = kit.requires.primitives;
|
|
65
|
+
const missingPrimitives = requiredPrimitives.filter((p) => !supportedPrimitives.includes(p));
|
|
66
|
+
// Check for experimental primitives (hooks are often experimental)
|
|
67
|
+
const experimentalPrimitives = requiredPrimitives.filter((p) => p === "hooks" && supportedPrimitives.includes(p));
|
|
68
|
+
if (missingPrimitives.length > 0) {
|
|
69
|
+
return {
|
|
70
|
+
compatible: false,
|
|
71
|
+
missingPrimitives,
|
|
72
|
+
experimentalPrimitives,
|
|
73
|
+
message: `harness does not support at ${effectiveScope} scope: ${missingPrimitives.join(", ")}`,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (experimentalPrimitives.length > 0) {
|
|
77
|
+
return {
|
|
78
|
+
compatible: true,
|
|
79
|
+
missingPrimitives: [],
|
|
80
|
+
experimentalPrimitives,
|
|
81
|
+
message: `harness has experimental support for: ${experimentalPrimitives.join(", ")}`,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
compatible: true,
|
|
86
|
+
missingPrimitives: [],
|
|
87
|
+
experimentalPrimitives: [],
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get a namespaced primitive name.
|
|
92
|
+
*
|
|
93
|
+
* Format: {kitName}.{primitiveName}
|
|
94
|
+
*/
|
|
95
|
+
getNamespacedName(kitName, primitiveName) {
|
|
96
|
+
return `${kitName}${NAMESPACE_SEPARATOR}${primitiveName}`;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Parse a namespaced name into kit and primitive components.
|
|
100
|
+
*/
|
|
101
|
+
parseNamespacedName(namespacedName) {
|
|
102
|
+
const separatorIndex = namespacedName.indexOf(NAMESPACE_SEPARATOR);
|
|
103
|
+
if (separatorIndex === -1) {
|
|
104
|
+
throw new Error(`invalid namespaced name; name=${namespacedName}`);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
kitName: namespacedName.substring(0, separatorIndex),
|
|
108
|
+
primitiveName: namespacedName.substring(separatorIndex + 1),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Process tool templates in content.
|
|
113
|
+
*/
|
|
114
|
+
processToolTemplates(content) {
|
|
115
|
+
return processTemplates(content, this.getToolMapping());
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Validate a kit against this harness's requirements.
|
|
119
|
+
*/
|
|
120
|
+
validate(kit) {
|
|
121
|
+
const errors = [];
|
|
122
|
+
// Validate kit has a name
|
|
123
|
+
if (!kit.name || kit.name.trim() === "") {
|
|
124
|
+
errors.push({
|
|
125
|
+
field: "name",
|
|
126
|
+
message: "kit name is required",
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
// Validate kit has a version
|
|
130
|
+
if (!kit.version || kit.version.trim() === "") {
|
|
131
|
+
errors.push({
|
|
132
|
+
field: "version",
|
|
133
|
+
message: "kit version is required",
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Validate primitives structure
|
|
137
|
+
if (!kit.primitives) {
|
|
138
|
+
errors.push({
|
|
139
|
+
field: "primitives",
|
|
140
|
+
message: "kit must have primitives declaration",
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
// Validate each declared primitive type is in requires
|
|
144
|
+
const declaredTypes = Object.keys(kit.primitives || {});
|
|
145
|
+
const requiredTypes = kit.requires?.primitives || [];
|
|
146
|
+
for (const declaredType of declaredTypes) {
|
|
147
|
+
const primitives = kit.primitives?.[declaredType];
|
|
148
|
+
if (primitives && primitives.length > 0 && !requiredTypes.includes(declaredType)) {
|
|
149
|
+
errors.push({
|
|
150
|
+
field: `requires.primitives`,
|
|
151
|
+
message: `kit declares ${declaredType} primitives but does not list ${declaredType} in requires.primitives`,
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
valid: errors.length === 0,
|
|
157
|
+
errors,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Install a kit to this harness.
|
|
162
|
+
*/
|
|
163
|
+
async install(kit, resolvedPrimitives, options) {
|
|
164
|
+
const { dryRun = false, backup = true, onProgress, scope = "global", projectRoot, envResolutions, } = options;
|
|
165
|
+
const installedPrimitives = [];
|
|
166
|
+
const fileOperations = [];
|
|
167
|
+
const completedOps = [];
|
|
168
|
+
let backupPath;
|
|
169
|
+
const paths = this.getInstallationPaths(scope);
|
|
170
|
+
const configLocations = this.getConfigLocations(scope);
|
|
171
|
+
try {
|
|
172
|
+
// Phase 1: Create directories
|
|
173
|
+
onProgress?.({ scope, phase: "file", operation: "creating directories" });
|
|
174
|
+
const directories = [
|
|
175
|
+
paths.commands,
|
|
176
|
+
paths.skills,
|
|
177
|
+
paths.subagents,
|
|
178
|
+
paths.hooks,
|
|
179
|
+
].filter(Boolean);
|
|
180
|
+
for (const dir of directories) {
|
|
181
|
+
if (!dryRun) {
|
|
182
|
+
const expanded = scope === "project" && projectRoot
|
|
183
|
+
? path.join(projectRoot, dir.replace(/^\.\//, ""))
|
|
184
|
+
: expandPath(dir);
|
|
185
|
+
if (!pathExists(expanded)) {
|
|
186
|
+
await ensureDirectory(expanded);
|
|
187
|
+
completedOps.push({
|
|
188
|
+
type: "directory",
|
|
189
|
+
path: expanded,
|
|
190
|
+
createdNew: true,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Phase 2: Backup config if needed
|
|
196
|
+
if (backup && !dryRun) {
|
|
197
|
+
onProgress?.({ scope, phase: "file", operation: "creating backup" });
|
|
198
|
+
const configPath = scope === "project" && projectRoot
|
|
199
|
+
? path.join(projectRoot, configLocations.primary.replace(/^\.\//, ""))
|
|
200
|
+
: expandPath(configLocations.primary);
|
|
201
|
+
backupPath = await createSimpleBackup(configPath);
|
|
202
|
+
if (backupPath) {
|
|
203
|
+
completedOps.push({
|
|
204
|
+
type: "backup",
|
|
205
|
+
path: backupPath,
|
|
206
|
+
createdNew: true,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Phase 3: Install each primitive
|
|
211
|
+
for (const primitive of resolvedPrimitives) {
|
|
212
|
+
const namespacedName = this.getNamespacedName(kit.name, primitive.name);
|
|
213
|
+
onProgress?.({
|
|
214
|
+
scope,
|
|
215
|
+
phase: "file",
|
|
216
|
+
operation: "installing",
|
|
217
|
+
primitive: primitive.name,
|
|
218
|
+
});
|
|
219
|
+
const result = await this.installPrimitive(kit.name, primitive, resolvedPrimitives, paths, dryRun, completedOps, scope, projectRoot);
|
|
220
|
+
const primitiveStatus = {
|
|
221
|
+
type: primitive.type,
|
|
222
|
+
name: primitive.name,
|
|
223
|
+
namespacedName,
|
|
224
|
+
status: result.existed ? "updated" : "installed",
|
|
225
|
+
destination: result.destination,
|
|
226
|
+
};
|
|
227
|
+
if (primitive.ref !== undefined) {
|
|
228
|
+
primitiveStatus.ref = primitive.ref;
|
|
229
|
+
}
|
|
230
|
+
if (primitive.resolvedVersion !== undefined) {
|
|
231
|
+
primitiveStatus.resolvedVersion = primitive.resolvedVersion;
|
|
232
|
+
}
|
|
233
|
+
installedPrimitives.push(primitiveStatus);
|
|
234
|
+
fileOperations.push(...result.operations);
|
|
235
|
+
}
|
|
236
|
+
// Phase 4: Update configuration (MCP servers, hooks)
|
|
237
|
+
onProgress?.({ scope, phase: "config", operation: "updating configuration" });
|
|
238
|
+
const configResult = await this.updateConfiguration(kit, resolvedPrimitives, dryRun, completedOps, scope, projectRoot, envResolutions);
|
|
239
|
+
fileOperations.push(...configResult.operations);
|
|
240
|
+
// Phase 5: Update manifest
|
|
241
|
+
onProgress?.({ scope, phase: "manifest", operation: "updating manifest" });
|
|
242
|
+
const configPath = scope === "project" && projectRoot
|
|
243
|
+
? path.join(projectRoot, configLocations.primary.replace(/^\.\//, ""))
|
|
244
|
+
: expandPath(configLocations.primary);
|
|
245
|
+
const successResult = {
|
|
246
|
+
success: true,
|
|
247
|
+
scope,
|
|
248
|
+
installedPrimitives,
|
|
249
|
+
fileOperations,
|
|
250
|
+
configPath,
|
|
251
|
+
};
|
|
252
|
+
if (projectRoot !== undefined && scope === "project") {
|
|
253
|
+
successResult.projectRoot = projectRoot;
|
|
254
|
+
}
|
|
255
|
+
if (backupPath !== undefined) {
|
|
256
|
+
successResult.backupPath = backupPath;
|
|
257
|
+
}
|
|
258
|
+
return successResult;
|
|
259
|
+
}
|
|
260
|
+
catch (error) {
|
|
261
|
+
// Rollback on failure
|
|
262
|
+
if (!dryRun && completedOps.length > 0) {
|
|
263
|
+
await rollbackOperations(completedOps);
|
|
264
|
+
}
|
|
265
|
+
const configPath = scope === "project" && projectRoot
|
|
266
|
+
? path.join(projectRoot, configLocations.primary.replace(/^\.\//, ""))
|
|
267
|
+
: expandPath(configLocations.primary);
|
|
268
|
+
const errorResult = {
|
|
269
|
+
success: false,
|
|
270
|
+
scope,
|
|
271
|
+
installedPrimitives,
|
|
272
|
+
fileOperations,
|
|
273
|
+
configPath,
|
|
274
|
+
error: error instanceof Error ? error.message : String(error),
|
|
275
|
+
};
|
|
276
|
+
if (projectRoot !== undefined && scope === "project") {
|
|
277
|
+
errorResult.projectRoot = projectRoot;
|
|
278
|
+
}
|
|
279
|
+
if (backupPath !== undefined) {
|
|
280
|
+
errorResult.backupPath = backupPath;
|
|
281
|
+
}
|
|
282
|
+
return errorResult;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Install a single primitive.
|
|
287
|
+
*
|
|
288
|
+
* Subclasses may override for harness-specific behavior.
|
|
289
|
+
*
|
|
290
|
+
* @param kitName - Name of the kit being installed
|
|
291
|
+
* @param primitive - Resolved primitive to install
|
|
292
|
+
* @param resolvedPrimitives - All resolved primitives for the kit
|
|
293
|
+
* @param paths - Installation paths for the scope
|
|
294
|
+
* @param dryRun - If true, don't actually write files
|
|
295
|
+
* @param completedOps - Array to track completed operations for rollback
|
|
296
|
+
* @param scope - Installation scope
|
|
297
|
+
* @param projectRoot - Project root for project scope
|
|
298
|
+
*/
|
|
299
|
+
async installPrimitive(kitName, primitive, resolvedPrimitives, paths, dryRun, completedOps, scope = "global", projectRoot) {
|
|
300
|
+
const namespacedName = this.getNamespacedName(kitName, primitive.name);
|
|
301
|
+
const operations = [];
|
|
302
|
+
// Helper to resolve path based on scope
|
|
303
|
+
const resolvePath = (p) => {
|
|
304
|
+
if (scope === "project" && projectRoot) {
|
|
305
|
+
return path.join(projectRoot, p.replace(/^\.\//, ""));
|
|
306
|
+
}
|
|
307
|
+
return expandPath(p);
|
|
308
|
+
};
|
|
309
|
+
let destination;
|
|
310
|
+
let existed = false;
|
|
311
|
+
switch (primitive.type) {
|
|
312
|
+
case "commands": {
|
|
313
|
+
destination = path.join(resolvePath(paths.commands), `${namespacedName}.md`);
|
|
314
|
+
existed = pathExists(destination);
|
|
315
|
+
if (!dryRun) {
|
|
316
|
+
// Read content and validate canonical format
|
|
317
|
+
const content = await readFile(primitive.sourcePath);
|
|
318
|
+
// Validate command format (throws CommandParseError if invalid)
|
|
319
|
+
const frontmatter = parseCommandFrontmatter(content);
|
|
320
|
+
// Build metadata from validated frontmatter, preserving any existing metadata
|
|
321
|
+
const metadata = {
|
|
322
|
+
...primitive.metadata,
|
|
323
|
+
description: frontmatter.description,
|
|
324
|
+
};
|
|
325
|
+
if (frontmatter.argumentHint !== undefined) {
|
|
326
|
+
metadata.argumentHint = frontmatter.argumentHint;
|
|
327
|
+
}
|
|
328
|
+
// Transform content using harness-specific adapter
|
|
329
|
+
const transformed = this.transformCommand(content, metadata);
|
|
330
|
+
// Process tool templates
|
|
331
|
+
const { content: processedContent } = this.processToolTemplates(transformed.content);
|
|
332
|
+
await writeTransformed(destination, processedContent);
|
|
333
|
+
completedOps.push({
|
|
334
|
+
type: "file",
|
|
335
|
+
path: destination,
|
|
336
|
+
createdNew: !existed,
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
operations.push({
|
|
340
|
+
operation: "transform",
|
|
341
|
+
source: primitive.sourcePath,
|
|
342
|
+
destination,
|
|
343
|
+
success: true,
|
|
344
|
+
});
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
case "skills": {
|
|
348
|
+
destination = path.join(resolvePath(paths.skills), namespacedName);
|
|
349
|
+
existed = pathExists(destination);
|
|
350
|
+
if (!dryRun) {
|
|
351
|
+
const isDir = await isDirectory(primitive.sourcePath);
|
|
352
|
+
const skillPath = isDir
|
|
353
|
+
? path.join(primitive.sourcePath, "SKILL.md")
|
|
354
|
+
: primitive.sourcePath;
|
|
355
|
+
if (isDir) {
|
|
356
|
+
await copyDirectory(primitive.sourcePath, destination);
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
// Single file skill - create directory and copy
|
|
360
|
+
await ensureDirectory(destination);
|
|
361
|
+
}
|
|
362
|
+
if (pathExists(skillPath)) {
|
|
363
|
+
const content = await readFile(skillPath);
|
|
364
|
+
const { frontmatter, body } = parseSkillFrontmatter(content);
|
|
365
|
+
const nameValue = frontmatter["name"];
|
|
366
|
+
const descriptionValue = frontmatter["description"];
|
|
367
|
+
const allowedToolsValue = frontmatter["allowedTools"];
|
|
368
|
+
const resolvedName = typeof nameValue === "string" && nameValue.length > 0
|
|
369
|
+
? nameValue
|
|
370
|
+
: primitive.name;
|
|
371
|
+
const resolvedDescription = typeof descriptionValue === "string"
|
|
372
|
+
? descriptionValue
|
|
373
|
+
: primitive.metadata.description;
|
|
374
|
+
const resolvedAllowedTools = typeof allowedToolsValue === "string" || Array.isArray(allowedToolsValue)
|
|
375
|
+
? allowedToolsValue
|
|
376
|
+
: undefined;
|
|
377
|
+
const metadata = { name: resolvedName };
|
|
378
|
+
if (resolvedDescription !== undefined) {
|
|
379
|
+
metadata.description = resolvedDescription;
|
|
380
|
+
}
|
|
381
|
+
if (resolvedAllowedTools !== undefined) {
|
|
382
|
+
metadata.allowedTools = resolvedAllowedTools;
|
|
383
|
+
}
|
|
384
|
+
const updatedFrontmatter = {
|
|
385
|
+
...frontmatter,
|
|
386
|
+
name: metadata.name,
|
|
387
|
+
};
|
|
388
|
+
if (typeof metadata.description === "string" && metadata.description.length > 0) {
|
|
389
|
+
updatedFrontmatter["description"] = metadata.description;
|
|
390
|
+
}
|
|
391
|
+
const mappedFrontmatter = mapAllowedTools(updatedFrontmatter, this.getToolMapping());
|
|
392
|
+
const modelResolvedFrontmatter = resolveModelTemplate(mappedFrontmatter, this.getModelMapping());
|
|
393
|
+
const hooksResolvedFrontmatter = this.mapSkillHooks(modelResolvedFrontmatter, resolvedPrimitives, kitName, paths, scope, projectRoot);
|
|
394
|
+
const filteredFrontmatter = this.filterSkillFrontmatter(hooksResolvedFrontmatter, metadata);
|
|
395
|
+
const { content: processedBody } = this.processToolTemplates(body);
|
|
396
|
+
const transformedContent = serializeSkillFrontmatter(filteredFrontmatter, processedBody);
|
|
397
|
+
await writeTransformed(path.join(destination, "SKILL.md"), transformedContent);
|
|
398
|
+
}
|
|
399
|
+
else if (!isDir) {
|
|
400
|
+
await copyFile(primitive.sourcePath, path.join(destination, "SKILL.md"));
|
|
401
|
+
}
|
|
402
|
+
completedOps.push({
|
|
403
|
+
type: "directory",
|
|
404
|
+
path: destination,
|
|
405
|
+
createdNew: !existed,
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
operations.push({
|
|
409
|
+
operation: "transform",
|
|
410
|
+
source: primitive.sourcePath,
|
|
411
|
+
destination,
|
|
412
|
+
success: true,
|
|
413
|
+
});
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
case "subagents": {
|
|
417
|
+
if (!paths.subagents) {
|
|
418
|
+
throw new Error(`harness does not support subagents; harness=${this.name}`);
|
|
419
|
+
}
|
|
420
|
+
destination = path.join(resolvePath(paths.subagents), `${namespacedName}.md`);
|
|
421
|
+
existed = pathExists(destination);
|
|
422
|
+
if (!dryRun) {
|
|
423
|
+
const content = await readFile(primitive.sourcePath);
|
|
424
|
+
let resolvedContent = content;
|
|
425
|
+
const { frontmatter, body, hasFrontmatter } = parseSubagentFrontmatter(content);
|
|
426
|
+
if (hasFrontmatter) {
|
|
427
|
+
const toolMappedFrontmatter = mapSubagentTools(frontmatter, this.getToolMapping());
|
|
428
|
+
const resolvedFrontmatter = resolveModelTemplate(toolMappedFrontmatter, this.getModelMapping());
|
|
429
|
+
const hooksResolvedFrontmatter = this.mapSubagentHooks(resolvedFrontmatter, resolvedPrimitives, kitName, paths, scope, projectRoot);
|
|
430
|
+
const filteredFrontmatter = this.filterSubagentFrontmatter(hooksResolvedFrontmatter, primitive.metadata);
|
|
431
|
+
resolvedContent = serializeSubagentFrontmatter(filteredFrontmatter, body);
|
|
432
|
+
}
|
|
433
|
+
const transformed = this.transformSubagent(resolvedContent, primitive.metadata);
|
|
434
|
+
const { content: processedContent } = this.processToolTemplates(transformed.content);
|
|
435
|
+
await writeTransformed(destination, processedContent);
|
|
436
|
+
completedOps.push({
|
|
437
|
+
type: "file",
|
|
438
|
+
path: destination,
|
|
439
|
+
createdNew: !existed,
|
|
440
|
+
});
|
|
441
|
+
}
|
|
442
|
+
operations.push({
|
|
443
|
+
operation: "transform",
|
|
444
|
+
source: primitive.sourcePath,
|
|
445
|
+
destination,
|
|
446
|
+
success: true,
|
|
447
|
+
});
|
|
448
|
+
break;
|
|
449
|
+
}
|
|
450
|
+
case "hooks": {
|
|
451
|
+
if (!paths.hooks) {
|
|
452
|
+
throw new Error(`harness does not support hooks; harness=${this.name}`);
|
|
453
|
+
}
|
|
454
|
+
const instanceName = primitive.instanceName ?? namespacedName;
|
|
455
|
+
destination = path.join(resolvePath(paths.hooks), instanceName);
|
|
456
|
+
existed = pathExists(destination);
|
|
457
|
+
// Hook programs are installed during adapter configuration updates.
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
case "mcp": {
|
|
461
|
+
// MCP servers are typically config-only, handled in updateConfiguration
|
|
462
|
+
const configLocs = this.getConfigLocations(scope);
|
|
463
|
+
const mcpPath = configLocs.mcp || configLocs.primary;
|
|
464
|
+
destination = resolvePath(mcpPath);
|
|
465
|
+
existed = pathExists(destination);
|
|
466
|
+
operations.push({
|
|
467
|
+
operation: "merge",
|
|
468
|
+
destination,
|
|
469
|
+
success: true,
|
|
470
|
+
});
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
default: {
|
|
474
|
+
throw new Error(`unsupported primitive type; type=${primitive.type}`);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
return { destination, existed, operations };
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Update harness configuration (MCP servers, hooks config).
|
|
481
|
+
*
|
|
482
|
+
* Subclasses should override for harness-specific config handling.
|
|
483
|
+
*
|
|
484
|
+
* @param kit - Kit manifest
|
|
485
|
+
* @param resolvedPrimitives - Resolved primitives to install
|
|
486
|
+
* @param dryRun - If true, don't actually write files
|
|
487
|
+
* @param completedOps - Array to track completed operations for rollback
|
|
488
|
+
* @param scope - Installation scope
|
|
489
|
+
* @param projectRoot - Project root for project scope
|
|
490
|
+
*/
|
|
491
|
+
async updateConfiguration(_kit, _resolvedPrimitives, _dryRun, _completedOps, _scope = "global", _projectRoot, _envResolutions) {
|
|
492
|
+
// Default implementation does nothing
|
|
493
|
+
// Subclasses should override for MCP server and hook configuration
|
|
494
|
+
return { operations: [] };
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Uninstall a kit from this harness.
|
|
498
|
+
*
|
|
499
|
+
* @param kitName - Name of the kit to uninstall
|
|
500
|
+
* @param options - Uninstall options including scope
|
|
501
|
+
*/
|
|
502
|
+
async uninstall(kitName, options) {
|
|
503
|
+
const { dryRun = false, removeEmptyDirs = true, scope = "global", projectRoot } = options;
|
|
504
|
+
// Helper to resolve path based on scope
|
|
505
|
+
const resolvePath = (p) => {
|
|
506
|
+
if (scope === "project" && projectRoot) {
|
|
507
|
+
return path.join(projectRoot, p.replace(/^\.\//, ""));
|
|
508
|
+
}
|
|
509
|
+
return expandPath(p);
|
|
510
|
+
};
|
|
511
|
+
const configLocations = this.getConfigLocations(scope);
|
|
512
|
+
const configPath = resolvePath(configLocations.primary);
|
|
513
|
+
const removedPrimitives = [];
|
|
514
|
+
const removedFiles = [];
|
|
515
|
+
try {
|
|
516
|
+
// Get list of installed kits to find primitives to remove
|
|
517
|
+
const installedKits = await this.list(scope);
|
|
518
|
+
const kit = installedKits.find((k) => k.name === kitName);
|
|
519
|
+
if (!kit) {
|
|
520
|
+
return {
|
|
521
|
+
success: false,
|
|
522
|
+
removedPrimitives: [],
|
|
523
|
+
removedFiles: [],
|
|
524
|
+
configPath,
|
|
525
|
+
error: `kit not found; name=${kitName}`,
|
|
526
|
+
};
|
|
527
|
+
}
|
|
528
|
+
// Remove each primitive
|
|
529
|
+
for (const primitive of kit.primitives) {
|
|
530
|
+
const filePath = scope === "project" && projectRoot
|
|
531
|
+
? path.join(projectRoot, primitive.location.replace(/^\.\//, ""))
|
|
532
|
+
: expandPath(primitive.location);
|
|
533
|
+
if (pathExists(filePath)) {
|
|
534
|
+
if (!dryRun) {
|
|
535
|
+
await remove(filePath);
|
|
536
|
+
}
|
|
537
|
+
removedFiles.push(filePath);
|
|
538
|
+
removedPrimitives.push(primitive.namespacedName);
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
// Remove empty directories if requested
|
|
542
|
+
if (removeEmptyDirs && !dryRun) {
|
|
543
|
+
const paths = this.getInstallationPaths(scope);
|
|
544
|
+
for (const dir of [paths.commands, paths.skills, paths.subagents, paths.hooks]) {
|
|
545
|
+
if (dir) {
|
|
546
|
+
const expanded = resolvePath(dir);
|
|
547
|
+
// Try to remove if empty (will fail silently if not empty)
|
|
548
|
+
try {
|
|
549
|
+
const { rmdir } = await import("node:fs/promises");
|
|
550
|
+
await rmdir(expanded);
|
|
551
|
+
}
|
|
552
|
+
catch {
|
|
553
|
+
// Directory not empty or doesn't exist - ignore
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return {
|
|
559
|
+
success: true,
|
|
560
|
+
removedPrimitives,
|
|
561
|
+
removedFiles,
|
|
562
|
+
configPath,
|
|
563
|
+
};
|
|
564
|
+
}
|
|
565
|
+
catch (error) {
|
|
566
|
+
return {
|
|
567
|
+
success: false,
|
|
568
|
+
removedPrimitives,
|
|
569
|
+
removedFiles,
|
|
570
|
+
configPath,
|
|
571
|
+
error: error instanceof Error ? error.message : String(error),
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
/**
|
|
576
|
+
* List installed kits.
|
|
577
|
+
*
|
|
578
|
+
* Subclasses should implement this based on how they track installations.
|
|
579
|
+
* The default implementation scans installation directories for namespaced files.
|
|
580
|
+
*
|
|
581
|
+
* @param scope - Installation scope (defaults to "global")
|
|
582
|
+
*/
|
|
583
|
+
async list(scope) {
|
|
584
|
+
const effectiveScope = scope ?? "global";
|
|
585
|
+
// Default implementation scans directories
|
|
586
|
+
// Subclasses may override to use manifest or config-based tracking
|
|
587
|
+
const kits = new Map();
|
|
588
|
+
const paths = this.getInstallationPaths(effectiveScope);
|
|
589
|
+
// Scan commands directory
|
|
590
|
+
await this.scanDirectoryForPrimitives(paths.commands, "commands", ".md", kits);
|
|
591
|
+
// Scan skills directory (directories)
|
|
592
|
+
await this.scanDirectoryForPrimitives(paths.skills, "skills", "", kits, true);
|
|
593
|
+
// Scan subagents directory
|
|
594
|
+
if (paths.subagents) {
|
|
595
|
+
await this.scanDirectoryForPrimitives(paths.subagents, "subagents", ".md", kits);
|
|
596
|
+
}
|
|
597
|
+
// Scan hooks directory
|
|
598
|
+
if (paths.hooks) {
|
|
599
|
+
await this.scanDirectoryForPrimitives(paths.hooks, "hooks", "", kits);
|
|
600
|
+
}
|
|
601
|
+
return Array.from(kits.values());
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Scan a directory for primitives and add to kit map.
|
|
605
|
+
*/
|
|
606
|
+
async scanDirectoryForPrimitives(dirPath, primitiveType, extension, kits, isDirectory = false) {
|
|
607
|
+
const expanded = expandPath(dirPath);
|
|
608
|
+
if (!pathExists(expanded)) {
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
const { readdir } = await import("node:fs/promises");
|
|
612
|
+
const entries = await readdir(expanded, { withFileTypes: true });
|
|
613
|
+
for (const entry of entries) {
|
|
614
|
+
// Check if entry matches our expected format
|
|
615
|
+
const entryName = isDirectory ? entry.name : entry.name.replace(extension, "");
|
|
616
|
+
if (!entryName.includes(NAMESPACE_SEPARATOR)) {
|
|
617
|
+
continue; // Not a namespaced primitive
|
|
618
|
+
}
|
|
619
|
+
try {
|
|
620
|
+
const { kitName, primitiveName } = this.parseNamespacedName(entryName);
|
|
621
|
+
if (!kits.has(kitName)) {
|
|
622
|
+
kits.set(kitName, {
|
|
623
|
+
name: kitName,
|
|
624
|
+
version: "unknown", // Would need to read from manifest
|
|
625
|
+
installedAt: "unknown",
|
|
626
|
+
primitives: [],
|
|
627
|
+
});
|
|
628
|
+
}
|
|
629
|
+
kits.get(kitName).primitives.push({
|
|
630
|
+
type: primitiveType,
|
|
631
|
+
name: primitiveName,
|
|
632
|
+
namespacedName: entryName,
|
|
633
|
+
location: path.join(expanded, entry.name),
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
catch {
|
|
637
|
+
// Invalid format - skip
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Get the file extension for a primitive type.
|
|
643
|
+
*/
|
|
644
|
+
getFileExtension(primitiveType) {
|
|
645
|
+
switch (primitiveType) {
|
|
646
|
+
case "commands":
|
|
647
|
+
return ".md";
|
|
648
|
+
case "skills":
|
|
649
|
+
return ""; // Skills are directories
|
|
650
|
+
case "subagents":
|
|
651
|
+
return ".md";
|
|
652
|
+
case "mcp":
|
|
653
|
+
return ".json";
|
|
654
|
+
case "hooks":
|
|
655
|
+
return "";
|
|
656
|
+
default:
|
|
657
|
+
return "";
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Get the destination path for a primitive.
|
|
662
|
+
*
|
|
663
|
+
* @param primitiveType - Type of primitive
|
|
664
|
+
* @param namespacedName - Namespaced name of the primitive
|
|
665
|
+
* @param scope - Installation scope (defaults to "global")
|
|
666
|
+
* @param projectRoot - Project root for project scope
|
|
667
|
+
*/
|
|
668
|
+
getDestinationPath(primitiveType, namespacedName, scope = "global", projectRoot) {
|
|
669
|
+
const paths = this.getInstallationPaths(scope);
|
|
670
|
+
const ext = this.getFileExtension(primitiveType);
|
|
671
|
+
// Helper to resolve path based on scope
|
|
672
|
+
const resolvePath = (p) => {
|
|
673
|
+
if (scope === "project" && projectRoot) {
|
|
674
|
+
return path.join(projectRoot, p.replace(/^\.\//, ""));
|
|
675
|
+
}
|
|
676
|
+
return expandPath(p);
|
|
677
|
+
};
|
|
678
|
+
switch (primitiveType) {
|
|
679
|
+
case "commands":
|
|
680
|
+
return path.join(resolvePath(paths.commands), `${namespacedName}${ext}`);
|
|
681
|
+
case "skills":
|
|
682
|
+
return path.join(resolvePath(paths.skills), namespacedName);
|
|
683
|
+
case "subagents":
|
|
684
|
+
if (!paths.subagents) {
|
|
685
|
+
throw new Error("subagents not supported");
|
|
686
|
+
}
|
|
687
|
+
return path.join(resolvePath(paths.subagents), `${namespacedName}${ext}`);
|
|
688
|
+
case "hooks":
|
|
689
|
+
if (!paths.hooks) {
|
|
690
|
+
throw new Error("hooks not supported");
|
|
691
|
+
}
|
|
692
|
+
return path.join(resolvePath(paths.hooks), `${namespacedName}${ext}`);
|
|
693
|
+
case "mcp":
|
|
694
|
+
{
|
|
695
|
+
const config = this.getConfigLocations(scope);
|
|
696
|
+
return resolvePath(config.mcp || config.primary);
|
|
697
|
+
}
|
|
698
|
+
default:
|
|
699
|
+
throw new Error(`unsupported primitive type; type=${primitiveType}`);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
//# sourceMappingURL=base-adapter.js.map
|