gsd-pi 2.20.0 → 2.22.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 +12 -0
- package/dist/cli.js +21 -18
- package/dist/help-text.d.ts +2 -0
- package/dist/help-text.js +47 -0
- package/dist/loader.js +2 -16
- package/dist/mcp-server.d.ts +18 -0
- package/dist/mcp-server.js +53 -0
- package/dist/onboarding.d.ts +0 -6
- package/dist/onboarding.js +0 -28
- package/dist/resources/agents/javascript-pro.md +280 -0
- package/dist/resources/agents/typescript-pro.md +255 -0
- package/dist/resources/extensions/bg-shell/index.ts +14 -2
- package/dist/resources/extensions/bg-shell/utilities.ts +14 -0
- package/dist/resources/extensions/browser-tools/{core.js → core.ts} +329 -190
- package/dist/resources/extensions/gsd/auto-dashboard.ts +2 -1
- package/dist/resources/extensions/gsd/auto-prompts.ts +42 -1
- package/dist/resources/extensions/gsd/auto-worktree.ts +35 -2
- package/dist/resources/extensions/gsd/auto.ts +116 -10
- package/dist/resources/extensions/gsd/claude-import.ts +656 -0
- package/dist/resources/extensions/gsd/collision-diagnostics.ts +332 -0
- package/dist/resources/extensions/gsd/commands.ts +60 -7
- package/dist/resources/extensions/gsd/diff-context.ts +220 -0
- package/dist/resources/extensions/gsd/docs/claude-marketplace-import.md +214 -0
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +2 -1
- package/dist/resources/extensions/gsd/doctor.ts +12 -4
- package/dist/resources/extensions/gsd/file-watcher.ts +97 -0
- package/dist/resources/extensions/gsd/files.ts +1 -1
- package/dist/resources/extensions/gsd/forensics.ts +596 -0
- package/dist/resources/extensions/gsd/git-service.ts +2 -1
- package/dist/resources/extensions/gsd/github-client.ts +235 -0
- package/dist/resources/extensions/gsd/gitignore.ts +1 -0
- package/dist/resources/extensions/gsd/marketplace-discovery.ts +507 -0
- package/dist/resources/extensions/gsd/mcp-server.ts +87 -0
- package/dist/resources/extensions/gsd/namespaced-registry.ts +467 -0
- package/dist/resources/extensions/gsd/namespaced-resolver.ts +307 -0
- package/dist/resources/extensions/gsd/plugin-importer.ts +410 -0
- package/dist/resources/extensions/gsd/preferences.ts +14 -3
- package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/dist/resources/extensions/gsd/prompts/forensics.md +71 -0
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/system.md +12 -3
- package/dist/resources/extensions/gsd/roadmap-slices.ts +1 -1
- package/dist/resources/extensions/gsd/session-forensics.ts +5 -5
- package/dist/resources/extensions/gsd/tests/claude-import-tui.test.ts +351 -0
- package/dist/resources/extensions/gsd/tests/collision-diagnostics.test.ts +705 -0
- package/dist/resources/extensions/gsd/tests/context-compression.test.ts +13 -0
- package/dist/resources/extensions/gsd/tests/diff-context.test.ts +136 -0
- package/dist/resources/extensions/gsd/tests/doctor-git.test.ts +118 -0
- package/dist/resources/extensions/gsd/tests/marketplace-discovery.test.ts +202 -0
- package/dist/resources/extensions/gsd/tests/marketplace-test-fixtures.ts +91 -0
- package/dist/resources/extensions/gsd/tests/namespaced-registry.test.ts +1027 -0
- package/dist/resources/extensions/gsd/tests/namespaced-resolver.test.ts +671 -0
- package/dist/resources/extensions/gsd/tests/none-mode-gates.test.ts +105 -0
- package/dist/resources/extensions/gsd/tests/plugin-importer-live.test.ts +481 -0
- package/dist/resources/extensions/gsd/tests/plugin-importer.test.ts +1383 -0
- package/dist/resources/extensions/gsd/tests/preferences-git.test.ts +21 -2
- package/dist/resources/extensions/gsd/tests/preferences-schema-validation.test.ts +8 -1
- package/dist/resources/extensions/gsd/tests/visualizer-data.test.ts +11 -0
- package/dist/resources/extensions/gsd/tests/worktree-bugfix.test.ts +120 -0
- package/dist/resources/extensions/gsd/token-counter.ts +45 -0
- package/dist/resources/extensions/gsd/visualizer-data.ts +2 -2
- package/dist/resources/extensions/gsd/worktree-manager.ts +29 -1
- package/dist/resources/extensions/gsd/worktree.ts +3 -0
- package/dist/resources/extensions/mcporter/index.ts +90 -7
- package/dist/resources/extensions/search-the-web/native-search.ts +2 -0
- package/dist/resources/extensions/search-the-web/tool-fetch-page.ts +9 -1
- package/dist/resources/extensions/search-the-web/url-utils.ts +35 -1
- package/dist/resources/extensions/shared/terminal.ts +1 -1
- package/dist/resources/extensions/universal-config/discovery.ts +4 -0
- package/dist/resources/extensions/universal-config/format.ts +35 -4
- package/dist/resources/extensions/universal-config/index.ts +5 -3
- package/dist/resources/extensions/universal-config/scanners.ts +65 -2
- package/dist/resources/extensions/universal-config/tests/discovery.test.ts +9 -1
- package/dist/resources/extensions/universal-config/tests/format.test.ts +22 -6
- package/dist/resources/extensions/universal-config/tests/scanners.test.ts +18 -0
- package/dist/resources/extensions/universal-config/types.ts +20 -1
- package/dist/resources/skills/lint/SKILL.md +141 -0
- package/dist/resources/skills/review/SKILL.md +214 -0
- package/dist/resources/skills/test/SKILL.md +201 -0
- package/dist/tool-bootstrap.js +2 -1
- package/dist/wizard.js +2 -0
- package/package.json +12 -7
- package/packages/pi-ai/dist/providers/azure-openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.js +12 -1
- package/packages/pi-ai/dist/providers/azure-openai-responses.js.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/openai-responses.js +12 -1
- package/packages/pi-ai/dist/providers/openai-responses.js.map +1 -1
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/LICENSE +201 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/README.md +9 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-cjs/index.js +762 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/build-abort-error.js +19 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/constants.js +1 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/get-transformed-headers.js +9 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/index.js +3 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/node-http-handler.js +230 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/node-http2-connection-manager.js +87 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/node-http2-connection-pool.js +32 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/node-http2-handler.js +169 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/readable.mock.js +21 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/server.mock.js +88 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/set-connection-timeout.js +36 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/set-request-timeout.js +21 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/set-socket-keep-alive.js +22 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/set-socket-timeout.js +23 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/stream-collector/collector.js +8 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/stream-collector/index.js +41 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/stream-collector/readable.mock.js +21 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/timing.js +4 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-es/write-request-body.js +63 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/build-abort-error.d.ts +10 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/constants.d.ts +5 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/get-transformed-headers.d.ts +4 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/index.d.ts +3 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/node-http-handler.d.ts +46 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/node-http2-connection-manager.d.ts +24 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/node-http2-connection-pool.d.ts +12 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/node-http2-handler.d.ts +63 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/readable.mock.d.ts +13 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/server.mock.d.ts +12 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/set-connection-timeout.d.ts +2 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/set-request-timeout.d.ts +6 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/set-socket-keep-alive.d.ts +6 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/set-socket-timeout.d.ts +2 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/stream-collector/collector.d.ts +5 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/stream-collector/index.d.ts +6 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/stream-collector/readable.mock.d.ts +13 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/timing.d.ts +8 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/build-abort-error.d.ts +10 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/constants.d.ts +5 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/get-transformed-headers.d.ts +4 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/index.d.ts +3 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/node-http-handler.d.ts +46 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/node-http2-connection-manager.d.ts +24 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/node-http2-connection-pool.d.ts +12 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/node-http2-handler.d.ts +63 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/readable.mock.d.ts +13 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/server.mock.d.ts +12 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/set-connection-timeout.d.ts +2 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/set-request-timeout.d.ts +6 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/set-socket-keep-alive.d.ts +6 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/set-socket-timeout.d.ts +2 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/stream-collector/collector.d.ts +5 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/stream-collector/index.d.ts +6 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/stream-collector/readable.mock.d.ts +13 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/timing.d.ts +8 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/ts3.4/write-request-body.d.ts +12 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/dist-types/write-request-body.d.ts +12 -0
- package/packages/pi-ai/node_modules/@smithy/node-http-handler/package.json +68 -0
- package/packages/pi-ai/package.json +3 -0
- package/packages/pi-ai/pnpm-lock.yaml +2022 -0
- package/packages/pi-ai/src/providers/azure-openai-responses.ts +12 -1
- package/packages/pi-ai/src/providers/openai-responses.ts +12 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.js +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +12 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +113 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/project-trust.d.ts +4 -0
- package/packages/pi-coding-agent/dist/core/extensions/project-trust.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/extensions/project-trust.js +42 -0
- package/packages/pi-coding-agent/dist/core/extensions/project-trust.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/resolve-config-value.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/resolve-config-value.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.js +18 -0
- package/packages/pi-coding-agent/dist/core/resolve-config-value.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +114 -0
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +8 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts +2 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +23 -9
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +67 -0
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/pnpm-lock.yaml +454 -0
- package/packages/pi-coding-agent/scripts/copy-assets.cjs +24 -0
- package/packages/pi-coding-agent/src/core/extensions/index.ts +3 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +141 -0
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +14 -1
- package/packages/pi-coding-agent/src/core/extensions/project-trust.ts +51 -0
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +132 -0
- package/packages/pi-coding-agent/src/core/resolve-config-value.ts +20 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +7 -2
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +98 -0
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +24 -9
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +2 -2
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/package.json +3 -1
- package/packages/pi-tui/src/tui.ts +2 -2
- package/src/resources/agents/javascript-pro.md +280 -0
- package/src/resources/agents/typescript-pro.md +255 -0
- package/src/resources/extensions/bg-shell/index.ts +14 -2
- package/src/resources/extensions/bg-shell/utilities.ts +14 -0
- package/src/resources/extensions/browser-tools/{core.js → core.ts} +329 -190
- package/src/resources/extensions/gsd/auto-dashboard.ts +2 -1
- package/src/resources/extensions/gsd/auto-prompts.ts +42 -1
- package/src/resources/extensions/gsd/auto-worktree.ts +35 -2
- package/src/resources/extensions/gsd/auto.ts +116 -10
- package/src/resources/extensions/gsd/claude-import.ts +656 -0
- package/src/resources/extensions/gsd/collision-diagnostics.ts +332 -0
- package/src/resources/extensions/gsd/commands.ts +60 -7
- package/src/resources/extensions/gsd/diff-context.ts +220 -0
- package/src/resources/extensions/gsd/docs/claude-marketplace-import.md +214 -0
- package/src/resources/extensions/gsd/docs/preferences-reference.md +2 -1
- package/src/resources/extensions/gsd/doctor.ts +12 -4
- package/src/resources/extensions/gsd/file-watcher.ts +97 -0
- package/src/resources/extensions/gsd/files.ts +1 -1
- package/src/resources/extensions/gsd/forensics.ts +596 -0
- package/src/resources/extensions/gsd/git-service.ts +2 -1
- package/src/resources/extensions/gsd/github-client.ts +235 -0
- package/src/resources/extensions/gsd/gitignore.ts +1 -0
- package/src/resources/extensions/gsd/marketplace-discovery.ts +507 -0
- package/src/resources/extensions/gsd/mcp-server.ts +87 -0
- package/src/resources/extensions/gsd/namespaced-registry.ts +467 -0
- package/src/resources/extensions/gsd/namespaced-resolver.ts +307 -0
- package/src/resources/extensions/gsd/plugin-importer.ts +410 -0
- package/src/resources/extensions/gsd/preferences.ts +14 -3
- package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
- package/src/resources/extensions/gsd/prompts/forensics.md +71 -0
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/system.md +12 -3
- package/src/resources/extensions/gsd/roadmap-slices.ts +1 -1
- package/src/resources/extensions/gsd/session-forensics.ts +5 -5
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +351 -0
- package/src/resources/extensions/gsd/tests/collision-diagnostics.test.ts +705 -0
- package/src/resources/extensions/gsd/tests/context-compression.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/diff-context.test.ts +136 -0
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +118 -0
- package/src/resources/extensions/gsd/tests/marketplace-discovery.test.ts +202 -0
- package/src/resources/extensions/gsd/tests/marketplace-test-fixtures.ts +91 -0
- package/src/resources/extensions/gsd/tests/namespaced-registry.test.ts +1027 -0
- package/src/resources/extensions/gsd/tests/namespaced-resolver.test.ts +671 -0
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/plugin-importer-live.test.ts +481 -0
- package/src/resources/extensions/gsd/tests/plugin-importer.test.ts +1383 -0
- package/src/resources/extensions/gsd/tests/preferences-git.test.ts +21 -2
- package/src/resources/extensions/gsd/tests/preferences-schema-validation.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +11 -0
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +120 -0
- package/src/resources/extensions/gsd/token-counter.ts +45 -0
- package/src/resources/extensions/gsd/visualizer-data.ts +2 -2
- package/src/resources/extensions/gsd/worktree-manager.ts +29 -1
- package/src/resources/extensions/gsd/worktree.ts +3 -0
- package/src/resources/extensions/mcporter/index.ts +90 -7
- package/src/resources/extensions/search-the-web/native-search.ts +2 -0
- package/src/resources/extensions/search-the-web/tool-fetch-page.ts +9 -1
- package/src/resources/extensions/search-the-web/url-utils.ts +35 -1
- package/src/resources/extensions/shared/terminal.ts +1 -1
- package/src/resources/extensions/universal-config/discovery.ts +4 -0
- package/src/resources/extensions/universal-config/format.ts +35 -4
- package/src/resources/extensions/universal-config/index.ts +5 -3
- package/src/resources/extensions/universal-config/scanners.ts +65 -2
- package/src/resources/extensions/universal-config/tests/discovery.test.ts +9 -1
- package/src/resources/extensions/universal-config/tests/format.test.ts +22 -6
- package/src/resources/extensions/universal-config/tests/scanners.test.ts +18 -0
- package/src/resources/extensions/universal-config/types.ts +20 -1
- package/src/resources/skills/lint/SKILL.md +141 -0
- package/src/resources/skills/review/SKILL.md +214 -0
- package/src/resources/skills/test/SKILL.md +201 -0
- package/dist/resources/extensions/browser-tools/core.d.ts +0 -205
- package/src/resources/extensions/browser-tools/core.d.ts +0 -205
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Namespaced Resolver Module
|
|
3
|
+
*
|
|
4
|
+
* Implements context-aware resolution with three-tier lookup precedence:
|
|
5
|
+
* 1. Canonical (fully-qualified names with `:`)
|
|
6
|
+
* 2. Local-first (caller namespace + bare name)
|
|
7
|
+
* 3. Shorthand (bare name matched across all namespaces)
|
|
8
|
+
*
|
|
9
|
+
* This is the core logic for D003 (same-plugin local-first) and R007/R008 (safe shorthand).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { NamespacedRegistry, NamespacedComponent, ComponentType } from './namespaced-registry.js';
|
|
13
|
+
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// Type Definitions
|
|
16
|
+
// ============================================================================
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Resolution context provided by the caller.
|
|
20
|
+
* Used to enable local-first resolution within a namespace.
|
|
21
|
+
*/
|
|
22
|
+
export interface ResolutionContext {
|
|
23
|
+
/** The namespace of the calling component (e.g., "farm" from "farm:caller") */
|
|
24
|
+
callerNamespace?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Base structure for all resolution results.
|
|
29
|
+
*/
|
|
30
|
+
interface ResolutionResultBase {
|
|
31
|
+
/** The original name passed to resolve() */
|
|
32
|
+
requestedName: string;
|
|
33
|
+
|
|
34
|
+
/** How the resolution was performed */
|
|
35
|
+
resolution: 'canonical' | 'alias' | 'local-first' | 'shorthand' | 'ambiguous' | 'not-found';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Result when a canonical (fully-qualified) name matches exactly.
|
|
40
|
+
* Example: "farm:call-horse" resolves directly to the component with that canonical name.
|
|
41
|
+
*/
|
|
42
|
+
export interface CanonicalResolution extends ResolutionResultBase {
|
|
43
|
+
resolution: 'canonical';
|
|
44
|
+
/** The matched component */
|
|
45
|
+
component: NamespacedComponent;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Result when an alias resolves to a canonical name.
|
|
50
|
+
* Example: "py3d" resolves via alias to "python-tools:3d-visualizer".
|
|
51
|
+
*/
|
|
52
|
+
export interface AliasResolution extends ResolutionResultBase {
|
|
53
|
+
resolution: 'alias';
|
|
54
|
+
/** The matched component */
|
|
55
|
+
component: NamespacedComponent;
|
|
56
|
+
/** The alias that was resolved */
|
|
57
|
+
alias: string;
|
|
58
|
+
/** The canonical name the alias points to */
|
|
59
|
+
canonicalName: string;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Result when a bare name resolves via local-first lookup.
|
|
64
|
+
* Example: A caller in namespace "farm" resolving bare "call-horse" matches "farm:call-horse".
|
|
65
|
+
*/
|
|
66
|
+
export interface LocalFirstResolution extends ResolutionResultBase {
|
|
67
|
+
resolution: 'local-first';
|
|
68
|
+
/** The matched component */
|
|
69
|
+
component: NamespacedComponent;
|
|
70
|
+
/** The namespace used for local-first resolution */
|
|
71
|
+
matchedNamespace: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Result when a bare name matches exactly one component across all namespaces.
|
|
76
|
+
* Example: "feed-chickens" resolves if only "farm:feed-chickens" exists.
|
|
77
|
+
*/
|
|
78
|
+
export interface ShorthandResolution extends ResolutionResultBase {
|
|
79
|
+
resolution: 'shorthand';
|
|
80
|
+
/** The matched component */
|
|
81
|
+
component: NamespacedComponent;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Result when a bare name matches multiple components across namespaces.
|
|
86
|
+
* Returns all candidates for diagnostic consumption without throwing.
|
|
87
|
+
* Example: "call-horse" matches both "farm:call-horse" and "zoo:call-horse".
|
|
88
|
+
*/
|
|
89
|
+
export interface AmbiguousResolution extends ResolutionResultBase {
|
|
90
|
+
resolution: 'ambiguous';
|
|
91
|
+
/** All components matching the bare name */
|
|
92
|
+
candidates: NamespacedComponent[];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Result when no component matches the requested name.
|
|
97
|
+
*/
|
|
98
|
+
export interface NotFoundResolution extends ResolutionResultBase {
|
|
99
|
+
resolution: 'not-found';
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Discriminated union of all resolution results.
|
|
104
|
+
* The `resolution` field indicates which variant applies.
|
|
105
|
+
*/
|
|
106
|
+
export type ResolutionResult =
|
|
107
|
+
| CanonicalResolution
|
|
108
|
+
| AliasResolution
|
|
109
|
+
| LocalFirstResolution
|
|
110
|
+
| ShorthandResolution
|
|
111
|
+
| AmbiguousResolution
|
|
112
|
+
| NotFoundResolution;
|
|
113
|
+
|
|
114
|
+
// ============================================================================
|
|
115
|
+
// NamespacedResolver Class
|
|
116
|
+
// ============================================================================
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Resolver for namespaced components with context-aware lookup.
|
|
120
|
+
*
|
|
121
|
+
* Implements four-tier resolution precedence:
|
|
122
|
+
* 1. **Canonical**: If name contains `:`, try exact match → return canonical result
|
|
123
|
+
* 2. **Alias**: If name is a registered alias → return alias result
|
|
124
|
+
* 3. **Local-first**: If `context.callerNamespace` exists, try `${callerNamespace}:${name}` → return local-first result
|
|
125
|
+
* 4. **Shorthand**: Scan all components for bare name match → single match returns shorthand, multiple returns ambiguous
|
|
126
|
+
*
|
|
127
|
+
* Usage:
|
|
128
|
+
* ```typescript
|
|
129
|
+
* const registry = new NamespacedRegistry();
|
|
130
|
+
* // ... populate registry ...
|
|
131
|
+
* // ... register aliases ...
|
|
132
|
+
*
|
|
133
|
+
* const resolver = new NamespacedResolver(registry);
|
|
134
|
+
*
|
|
135
|
+
* // Canonical lookup
|
|
136
|
+
* const canon = resolver.resolve('farm:call-horse');
|
|
137
|
+
* // canon.resolution === 'canonical'
|
|
138
|
+
*
|
|
139
|
+
* // Alias resolution
|
|
140
|
+
* const alias = resolver.resolve('py3d');
|
|
141
|
+
* // alias.resolution === 'alias', alias.canonicalName === 'python-tools:3d-visualizer'
|
|
142
|
+
*
|
|
143
|
+
* // Local-first resolution from caller context
|
|
144
|
+
* const local = resolver.resolve('call-horse', { callerNamespace: 'farm' });
|
|
145
|
+
* // local.resolution === 'local-first'
|
|
146
|
+
*
|
|
147
|
+
* // Unambiguous shorthand
|
|
148
|
+
* const short = resolver.resolve('unique-skill');
|
|
149
|
+
* // short.resolution === 'shorthand'
|
|
150
|
+
*
|
|
151
|
+
* // Ambiguous shorthand
|
|
152
|
+
* const amb = resolver.resolve('common-skill');
|
|
153
|
+
* // amb.resolution === 'ambiguous', amb.candidates has all matches
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
export class NamespacedResolver {
|
|
157
|
+
/** The registry to resolve against */
|
|
158
|
+
private registry: NamespacedRegistry;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Create a new resolver for the given registry.
|
|
162
|
+
*
|
|
163
|
+
* @param registry - The namespaced registry to resolve against
|
|
164
|
+
*/
|
|
165
|
+
constructor(registry: NamespacedRegistry) {
|
|
166
|
+
this.registry = registry;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Resolve a component name with context-aware lookup.
|
|
171
|
+
*
|
|
172
|
+
* Implements four-tier resolution precedence:
|
|
173
|
+
* 1. **Canonical**: If name contains `:`, try exact match → return canonical result
|
|
174
|
+
* 2. **Alias**: If name is a registered alias → return alias result
|
|
175
|
+
* 3. **Local-first**: If `context.callerNamespace` exists, try `${callerNamespace}:${name}` → return local-first result
|
|
176
|
+
* 4. **Shorthand**: Scan all components for bare name match → single match returns shorthand, multiple returns ambiguous
|
|
177
|
+
*
|
|
178
|
+
* @param name - The name to resolve (canonical or bare)
|
|
179
|
+
* @param context - Optional resolution context with caller namespace
|
|
180
|
+
* @param type - Optional type filter (skill or agent)
|
|
181
|
+
* @returns Resolution result indicating how the match was found
|
|
182
|
+
*/
|
|
183
|
+
resolve(
|
|
184
|
+
name: string,
|
|
185
|
+
context?: ResolutionContext,
|
|
186
|
+
type?: ComponentType
|
|
187
|
+
): ResolutionResult {
|
|
188
|
+
// Tier 1: Canonical lookup (name contains `:`)
|
|
189
|
+
if (name.includes(':')) {
|
|
190
|
+
const component = this.registry.getByCanonical(name);
|
|
191
|
+
|
|
192
|
+
if (component && this.matchesType(component, type)) {
|
|
193
|
+
return {
|
|
194
|
+
requestedName: name,
|
|
195
|
+
resolution: 'canonical',
|
|
196
|
+
component,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Canonical name not found
|
|
201
|
+
return {
|
|
202
|
+
requestedName: name,
|
|
203
|
+
resolution: 'not-found',
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Tier 2: Alias lookup (before local-first and shorthand)
|
|
208
|
+
const aliasTarget = this.registry.resolveAlias(name);
|
|
209
|
+
if (aliasTarget) {
|
|
210
|
+
const component = this.registry.getByCanonical(aliasTarget);
|
|
211
|
+
if (component && this.matchesType(component, type)) {
|
|
212
|
+
return {
|
|
213
|
+
requestedName: name,
|
|
214
|
+
resolution: 'alias',
|
|
215
|
+
component,
|
|
216
|
+
alias: name,
|
|
217
|
+
canonicalName: aliasTarget,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Tier 3: Local-first resolution (if caller namespace provided)
|
|
223
|
+
if (context?.callerNamespace) {
|
|
224
|
+
const localCanonical = `${context.callerNamespace}:${name}`;
|
|
225
|
+
const component = this.registry.getByCanonical(localCanonical);
|
|
226
|
+
|
|
227
|
+
if (component && this.matchesType(component, type)) {
|
|
228
|
+
return {
|
|
229
|
+
requestedName: name,
|
|
230
|
+
resolution: 'local-first',
|
|
231
|
+
component,
|
|
232
|
+
matchedNamespace: context.callerNamespace,
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Tier 4: Shorthand resolution (scan all components)
|
|
238
|
+
const candidates = this.findBareNameMatches(name, type);
|
|
239
|
+
|
|
240
|
+
if (candidates.length === 0) {
|
|
241
|
+
return {
|
|
242
|
+
requestedName: name,
|
|
243
|
+
resolution: 'not-found',
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
if (candidates.length === 1) {
|
|
248
|
+
return {
|
|
249
|
+
requestedName: name,
|
|
250
|
+
resolution: 'shorthand',
|
|
251
|
+
component: candidates[0],
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Multiple matches - ambiguous
|
|
256
|
+
return {
|
|
257
|
+
requestedName: name,
|
|
258
|
+
resolution: 'ambiguous',
|
|
259
|
+
candidates,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Find all components whose local name (without namespace) matches the given bare name.
|
|
265
|
+
* Optionally filters by component type.
|
|
266
|
+
*
|
|
267
|
+
* @param bareName - The bare name to match
|
|
268
|
+
* @param type - Optional type filter
|
|
269
|
+
* @returns Array of matching components
|
|
270
|
+
*/
|
|
271
|
+
private findBareNameMatches(
|
|
272
|
+
bareName: string,
|
|
273
|
+
type?: ComponentType
|
|
274
|
+
): NamespacedComponent[] {
|
|
275
|
+
const all = this.registry.getAll();
|
|
276
|
+
|
|
277
|
+
return all.filter((component) => {
|
|
278
|
+
// Match by local name (component.name)
|
|
279
|
+
if (component.name !== bareName) {
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Apply type filter if provided
|
|
284
|
+
return this.matchesType(component, type);
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Check if a component matches the optional type filter.
|
|
290
|
+
*
|
|
291
|
+
* @param component - The component to check
|
|
292
|
+
* @param type - Optional type filter
|
|
293
|
+
* @returns true if no filter or type matches
|
|
294
|
+
*/
|
|
295
|
+
private matchesType(
|
|
296
|
+
component: NamespacedComponent,
|
|
297
|
+
type?: ComponentType
|
|
298
|
+
): boolean {
|
|
299
|
+
return type === undefined || component.type === type;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// ============================================================================
|
|
304
|
+
// Exports
|
|
305
|
+
// ============================================================================
|
|
306
|
+
|
|
307
|
+
export default NamespacedResolver;
|
|
@@ -0,0 +1,410 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PluginImporter Service
|
|
3
|
+
*
|
|
4
|
+
* Composes S01-S04 modules into a staged discover → select → validate → commit pipeline.
|
|
5
|
+
* Each stage is independently testable. The service owns no UI — it produces data structures
|
|
6
|
+
* that the command layer (T02) consumes.
|
|
7
|
+
*
|
|
8
|
+
* Pipeline stages:
|
|
9
|
+
* 1. discover(marketplacePaths) - Read marketplace manifests, populate registry
|
|
10
|
+
* 2. selectComponents(filter) - Filter to user-chosen components
|
|
11
|
+
* 3. validateImport(selected) - Check for collisions, return diagnostics
|
|
12
|
+
* 4. getImportManifest(selected) - Produce serializable config structure
|
|
13
|
+
*
|
|
14
|
+
* This service implements R012 (discover/select/import flow) and R013 (canonical name preservation).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
discoverMarketplace,
|
|
19
|
+
type MarketplaceDiscoveryResult,
|
|
20
|
+
type DiscoveredPlugin,
|
|
21
|
+
} from './marketplace-discovery.js';
|
|
22
|
+
import {
|
|
23
|
+
NamespacedRegistry,
|
|
24
|
+
componentsFromDiscovery,
|
|
25
|
+
type NamespacedComponent,
|
|
26
|
+
} from './namespaced-registry.js';
|
|
27
|
+
import { NamespacedResolver } from './namespaced-resolver.js';
|
|
28
|
+
import {
|
|
29
|
+
analyzeCollisions,
|
|
30
|
+
type ClassifiedDiagnostic,
|
|
31
|
+
} from './collision-diagnostics.js';
|
|
32
|
+
|
|
33
|
+
// ============================================================================
|
|
34
|
+
// Type Definitions
|
|
35
|
+
// ============================================================================
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Result of the discovery stage.
|
|
39
|
+
* Contains all discovered plugins and the populated registry.
|
|
40
|
+
*/
|
|
41
|
+
export interface DiscoveryResult {
|
|
42
|
+
/** All discovery results from each marketplace path */
|
|
43
|
+
marketplaceResults: MarketplaceDiscoveryResult[];
|
|
44
|
+
|
|
45
|
+
/** All discovered plugins aggregated */
|
|
46
|
+
plugins: DiscoveredPlugin[];
|
|
47
|
+
|
|
48
|
+
/** The populated registry with all components */
|
|
49
|
+
registry: NamespacedRegistry;
|
|
50
|
+
|
|
51
|
+
/** Summary counts */
|
|
52
|
+
summary: {
|
|
53
|
+
marketplacesProcessed: number;
|
|
54
|
+
marketplacesWithErrors: number;
|
|
55
|
+
totalPlugins: number;
|
|
56
|
+
pluginsWithErrors: number;
|
|
57
|
+
totalComponents: number;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Result of the validation stage.
|
|
63
|
+
* Contains diagnostics and a proceed flag.
|
|
64
|
+
*/
|
|
65
|
+
export interface ValidationResult {
|
|
66
|
+
/** All classified diagnostics (errors and warnings) */
|
|
67
|
+
diagnostics: ClassifiedDiagnostic[];
|
|
68
|
+
|
|
69
|
+
/** True if import can proceed (no error-severity diagnostics) */
|
|
70
|
+
canProceed: boolean;
|
|
71
|
+
|
|
72
|
+
/** Summary counts */
|
|
73
|
+
summary: {
|
|
74
|
+
total: number;
|
|
75
|
+
errors: number;
|
|
76
|
+
warnings: number;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* A single entry in the import manifest config.
|
|
82
|
+
* Represents one component to be imported.
|
|
83
|
+
*/
|
|
84
|
+
export interface ImportManifestEntry {
|
|
85
|
+
/** Canonical name: `namespace:name` or bare `name` */
|
|
86
|
+
canonicalName: string;
|
|
87
|
+
|
|
88
|
+
/** Component type: 'skill' or 'agent' */
|
|
89
|
+
type: 'skill' | 'agent';
|
|
90
|
+
|
|
91
|
+
/** Local component name (without namespace) */
|
|
92
|
+
name: string;
|
|
93
|
+
|
|
94
|
+
/** Plugin namespace (undefined for flat components) */
|
|
95
|
+
namespace: string | undefined;
|
|
96
|
+
|
|
97
|
+
/** Absolute path to the component's definition file */
|
|
98
|
+
filePath: string;
|
|
99
|
+
|
|
100
|
+
/** Source identifier (e.g., "plugin:my-plugin") */
|
|
101
|
+
source: string;
|
|
102
|
+
|
|
103
|
+
/** Optional description */
|
|
104
|
+
description?: string;
|
|
105
|
+
|
|
106
|
+
/** Plugin metadata for provenance */
|
|
107
|
+
metadata: {
|
|
108
|
+
pluginVersion?: string;
|
|
109
|
+
pluginAuthor?: string;
|
|
110
|
+
pluginHomepage?: string;
|
|
111
|
+
pluginCategory?: string;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The complete import manifest structure.
|
|
117
|
+
* Serializable to JSON for persistence.
|
|
118
|
+
*/
|
|
119
|
+
export interface ImportManifest {
|
|
120
|
+
/** Schema version for future compatibility */
|
|
121
|
+
schemaVersion: '1.0';
|
|
122
|
+
|
|
123
|
+
/** Timestamp when manifest was generated */
|
|
124
|
+
generatedAt: string;
|
|
125
|
+
|
|
126
|
+
/** All entries to be imported */
|
|
127
|
+
entries: ImportManifestEntry[];
|
|
128
|
+
|
|
129
|
+
/** Summary counts */
|
|
130
|
+
summary: {
|
|
131
|
+
total: number;
|
|
132
|
+
skills: number;
|
|
133
|
+
agents: number;
|
|
134
|
+
namespaces: string[];
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// ============================================================================
|
|
139
|
+
// PluginImporter Class
|
|
140
|
+
// ============================================================================
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Service for discovering, selecting, validating, and importing plugin components.
|
|
144
|
+
*
|
|
145
|
+
* Usage:
|
|
146
|
+
* ```typescript
|
|
147
|
+
* const importer = new PluginImporter();
|
|
148
|
+
*
|
|
149
|
+
* // Stage 1: Discover
|
|
150
|
+
* const discovery = importer.discover(['../claude-plugins']);
|
|
151
|
+
*
|
|
152
|
+
* // Stage 2: Select
|
|
153
|
+
* const selected = importer.selectComponents(c => c.namespace === 'my-plugin');
|
|
154
|
+
*
|
|
155
|
+
* // Stage 3: Validate
|
|
156
|
+
* const validation = importer.validateImport(selected);
|
|
157
|
+
* if (!validation.canProceed) {
|
|
158
|
+
* console.error('Cannot import:', validation.diagnostics);
|
|
159
|
+
* return;
|
|
160
|
+
* }
|
|
161
|
+
*
|
|
162
|
+
* // Stage 4: Get manifest for persistence
|
|
163
|
+
* const manifest = importer.getImportManifest(selected);
|
|
164
|
+
* ```
|
|
165
|
+
*/
|
|
166
|
+
export class PluginImporter {
|
|
167
|
+
/** The internal registry populated during discovery */
|
|
168
|
+
private registry: NamespacedRegistry | null = null;
|
|
169
|
+
|
|
170
|
+
/** All discovered plugins from the last discovery run */
|
|
171
|
+
private discoveredPlugins: DiscoveredPlugin[] = [];
|
|
172
|
+
|
|
173
|
+
/** Last discovery result for inspection */
|
|
174
|
+
private lastDiscoveryResult: DiscoveryResult | null = null;
|
|
175
|
+
|
|
176
|
+
/** Last validation result for inspection */
|
|
177
|
+
private lastValidationResult: ValidationResult | null = null;
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Stage 1: Discover plugins from marketplace paths.
|
|
181
|
+
*
|
|
182
|
+
* Calls `discoverMarketplace()` for each path and populates a `NamespacedRegistry`
|
|
183
|
+
* via `componentsFromDiscovery()`.
|
|
184
|
+
*
|
|
185
|
+
* @param marketplacePaths - Array of paths to marketplace directories
|
|
186
|
+
* @returns Discovery result with registry and summary
|
|
187
|
+
*/
|
|
188
|
+
discover(marketplacePaths: string[]): DiscoveryResult {
|
|
189
|
+
// Reset state for fresh discovery
|
|
190
|
+
this.registry = new NamespacedRegistry();
|
|
191
|
+
this.discoveredPlugins = [];
|
|
192
|
+
this.lastValidationResult = null;
|
|
193
|
+
|
|
194
|
+
const marketplaceResults: MarketplaceDiscoveryResult[] = [];
|
|
195
|
+
let marketplacesWithErrors = 0;
|
|
196
|
+
let pluginsWithErrors = 0;
|
|
197
|
+
|
|
198
|
+
// Process each marketplace path
|
|
199
|
+
for (const marketplacePath of marketplacePaths) {
|
|
200
|
+
const result = discoverMarketplace(marketplacePath);
|
|
201
|
+
marketplaceResults.push(result);
|
|
202
|
+
|
|
203
|
+
if (result.status === 'error') {
|
|
204
|
+
marketplacesWithErrors++;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Collect all plugins
|
|
208
|
+
for (const plugin of result.plugins) {
|
|
209
|
+
this.discoveredPlugins.push(plugin);
|
|
210
|
+
|
|
211
|
+
if (plugin.status === 'error') {
|
|
212
|
+
pluginsWithErrors++;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Convert plugin inventory to components and register
|
|
216
|
+
const components = componentsFromDiscovery(plugin);
|
|
217
|
+
for (const component of components) {
|
|
218
|
+
this.registry!.register(component);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Build summary
|
|
224
|
+
const summary = {
|
|
225
|
+
marketplacesProcessed: marketplacePaths.length,
|
|
226
|
+
marketplacesWithErrors,
|
|
227
|
+
totalPlugins: this.discoveredPlugins.length,
|
|
228
|
+
pluginsWithErrors,
|
|
229
|
+
totalComponents: this.registry.size,
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
this.lastDiscoveryResult = {
|
|
233
|
+
marketplaceResults,
|
|
234
|
+
plugins: this.discoveredPlugins,
|
|
235
|
+
registry: this.registry,
|
|
236
|
+
summary,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
return this.lastDiscoveryResult;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Stage 2: Select components by filter function.
|
|
244
|
+
*
|
|
245
|
+
* Returns a filtered subset of registered components.
|
|
246
|
+
* Must be called after discover().
|
|
247
|
+
*
|
|
248
|
+
* @param componentFilter - Filter function returning true for selected components
|
|
249
|
+
* @returns Array of selected components
|
|
250
|
+
*/
|
|
251
|
+
selectComponents(
|
|
252
|
+
componentFilter: (component: NamespacedComponent) => boolean
|
|
253
|
+
): NamespacedComponent[] {
|
|
254
|
+
if (!this.registry) {
|
|
255
|
+
throw new Error('Must call discover() before selectComponents()');
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return this.registry.getAll().filter(componentFilter);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Stage 3: Validate selected components for import.
|
|
263
|
+
*
|
|
264
|
+
* Builds a `NamespacedResolver`, runs `analyzeCollisions()`, and returns
|
|
265
|
+
* `{ diagnostics, canProceed }` where `canProceed` is false if any
|
|
266
|
+
* error-severity diagnostics exist.
|
|
267
|
+
*
|
|
268
|
+
* @param selected - Array of components to validate
|
|
269
|
+
* @returns Validation result with diagnostics and proceed flag
|
|
270
|
+
*/
|
|
271
|
+
validateImport(selected: NamespacedComponent[]): ValidationResult {
|
|
272
|
+
if (!this.registry) {
|
|
273
|
+
throw new Error('Must call discover() before validateImport()');
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Create a temporary resolver for the selected components
|
|
277
|
+
const tempRegistry = new NamespacedRegistry();
|
|
278
|
+
|
|
279
|
+
// Register only selected components into temp registry
|
|
280
|
+
for (const component of selected) {
|
|
281
|
+
tempRegistry.register({
|
|
282
|
+
name: component.name,
|
|
283
|
+
namespace: component.namespace,
|
|
284
|
+
type: component.type,
|
|
285
|
+
filePath: component.filePath,
|
|
286
|
+
source: component.source,
|
|
287
|
+
description: component.description,
|
|
288
|
+
metadata: component.metadata,
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Create resolver and analyze collisions
|
|
293
|
+
const resolver = new NamespacedResolver(tempRegistry);
|
|
294
|
+
const diagnostics = analyzeCollisions(tempRegistry, resolver);
|
|
295
|
+
|
|
296
|
+
// Count by severity
|
|
297
|
+
const errors = diagnostics.filter((d) => d.severity === 'error').length;
|
|
298
|
+
const warnings = diagnostics.filter((d) => d.severity === 'warning').length;
|
|
299
|
+
|
|
300
|
+
const summary = {
|
|
301
|
+
total: diagnostics.length,
|
|
302
|
+
errors,
|
|
303
|
+
warnings,
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
// canProceed is false if any error-severity diagnostics exist
|
|
307
|
+
const canProceed = errors === 0;
|
|
308
|
+
|
|
309
|
+
this.lastValidationResult = {
|
|
310
|
+
diagnostics,
|
|
311
|
+
canProceed,
|
|
312
|
+
summary,
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
return this.lastValidationResult;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Stage 4: Generate import manifest for selected components.
|
|
320
|
+
*
|
|
321
|
+
* Produces a serializable config structure with canonical names preserved.
|
|
322
|
+
* The manifest can be persisted to config files.
|
|
323
|
+
*
|
|
324
|
+
* @param selected - Array of components to include in manifest
|
|
325
|
+
* @returns Import manifest with all entries and metadata
|
|
326
|
+
*/
|
|
327
|
+
getImportManifest(selected: NamespacedComponent[]): ImportManifest {
|
|
328
|
+
const entries: ImportManifestEntry[] = selected.map((component) => ({
|
|
329
|
+
canonicalName: component.canonicalName,
|
|
330
|
+
type: component.type,
|
|
331
|
+
name: component.name,
|
|
332
|
+
namespace: component.namespace,
|
|
333
|
+
filePath: component.filePath,
|
|
334
|
+
source: component.source,
|
|
335
|
+
description: component.description,
|
|
336
|
+
metadata: {
|
|
337
|
+
pluginVersion: component.metadata.pluginVersion,
|
|
338
|
+
pluginAuthor: component.metadata.pluginAuthor,
|
|
339
|
+
pluginHomepage: component.metadata.pluginHomepage,
|
|
340
|
+
pluginCategory: component.metadata.pluginCategory,
|
|
341
|
+
},
|
|
342
|
+
}));
|
|
343
|
+
|
|
344
|
+
// Count by type
|
|
345
|
+
const skills = entries.filter((e) => e.type === 'skill').length;
|
|
346
|
+
const agents = entries.filter((e) => e.type === 'agent').length;
|
|
347
|
+
|
|
348
|
+
// Collect unique namespaces
|
|
349
|
+
const namespaces = Array.from(
|
|
350
|
+
new Set(entries.map((e) => e.namespace).filter((n): n is string => n !== undefined))
|
|
351
|
+
).sort();
|
|
352
|
+
|
|
353
|
+
return {
|
|
354
|
+
schemaVersion: '1.0',
|
|
355
|
+
generatedAt: new Date().toISOString(),
|
|
356
|
+
entries,
|
|
357
|
+
summary: {
|
|
358
|
+
total: entries.length,
|
|
359
|
+
skills,
|
|
360
|
+
agents,
|
|
361
|
+
namespaces,
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Get the internal registry for inspection.
|
|
368
|
+
* Useful for debugging or advanced filtering.
|
|
369
|
+
*
|
|
370
|
+
* @returns The registry or null if discover() hasn't been called
|
|
371
|
+
*/
|
|
372
|
+
getRegistry(): NamespacedRegistry | null {
|
|
373
|
+
return this.registry;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Get all discovered plugins.
|
|
378
|
+
*
|
|
379
|
+
* @returns Array of discovered plugins
|
|
380
|
+
*/
|
|
381
|
+
getDiscoveredPlugins(): DiscoveredPlugin[] {
|
|
382
|
+
return this.discoveredPlugins;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
/**
|
|
386
|
+
* Get the last validation result.
|
|
387
|
+
* Useful for re-inspecting validation without re-running.
|
|
388
|
+
*
|
|
389
|
+
* @returns Last validation result or null
|
|
390
|
+
*/
|
|
391
|
+
getLastValidation(): ValidationResult | null {
|
|
392
|
+
return this.lastValidationResult;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Get the last discovery result.
|
|
397
|
+
* Useful for re-inspecting discovery without re-running.
|
|
398
|
+
*
|
|
399
|
+
* @returns Last discovery result or null
|
|
400
|
+
*/
|
|
401
|
+
getLastDiscovery(): DiscoveryResult | null {
|
|
402
|
+
return this.lastDiscoveryResult;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// ============================================================================
|
|
407
|
+
// Exports
|
|
408
|
+
// ============================================================================
|
|
409
|
+
|
|
410
|
+
export default PluginImporter;
|