gsd-pi 2.77.0-dev.eaa4973bc → 2.78.0-dev.aeeb2ca00
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 +53 -17
- package/dist/claude-cli-check.js +46 -10
- package/dist/headless.js +49 -4
- package/dist/resource-loader.d.ts +40 -0
- package/dist/resource-loader.js +32 -13
- package/dist/resources/extensions/browser-tools/capture.js +9 -0
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
- package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
- package/dist/resources/extensions/claude-code-cli/readiness.js +72 -16
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
- package/dist/resources/extensions/github-sync/templates.js +103 -0
- package/dist/resources/extensions/google-search/index.js +3 -2
- package/dist/resources/extensions/gsd/auto/loop.js +124 -2
- package/dist/resources/extensions/gsd/auto/phases.js +57 -39
- package/dist/resources/extensions/gsd/auto/session.js +6 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +142 -29
- package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
- package/dist/resources/extensions/gsd/auto-post-unit.js +150 -64
- package/dist/resources/extensions/gsd/auto-prompts.js +372 -104
- package/dist/resources/extensions/gsd/auto-recovery.js +197 -48
- package/dist/resources/extensions/gsd/auto-start.js +107 -29
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
- package/dist/resources/extensions/gsd/auto.js +76 -21
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +19 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
- package/dist/resources/extensions/gsd/component-loader.js +447 -0
- package/dist/resources/extensions/gsd/component-types.js +69 -0
- package/dist/resources/extensions/gsd/context-store.js +23 -7
- package/dist/resources/extensions/gsd/detection.js +49 -1
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -17
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/forensics.js +106 -0
- package/dist/resources/extensions/gsd/gate-registry.js +2 -2
- package/dist/resources/extensions/gsd/git-constants.js +28 -1
- package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
- package/dist/resources/extensions/gsd/git-service.js +126 -2
- package/dist/resources/extensions/gsd/gsd-db.js +6 -3
- package/dist/resources/extensions/gsd/guided-flow.js +39 -13
- package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
- package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
- package/dist/resources/extensions/gsd/milestone-summary-classifier.js +37 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
- package/dist/resources/extensions/gsd/model-router.js +6 -0
- package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
- package/dist/resources/extensions/gsd/preferences-validation.js +23 -0
- package/dist/resources/extensions/gsd/prompt-cache-optimizer.js +4 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
- package/dist/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
- package/dist/resources/extensions/gsd/service-tier.js +5 -2
- package/dist/resources/extensions/gsd/session-lock.js +19 -10
- package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
- package/dist/resources/extensions/gsd/slice-cadence.js +238 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
- package/dist/resources/extensions/gsd/state-transition-matrix.js +118 -0
- package/dist/resources/extensions/gsd/state.js +69 -58
- package/dist/resources/extensions/gsd/sync-lock.js +98 -42
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +7 -2
- package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
- package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +33 -0
- package/dist/resources/extensions/gsd/uok/execution-graph.js +10 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
- package/dist/resources/extensions/gsd/uok/gitops.js +2 -1
- package/dist/resources/extensions/gsd/uok/loop-adapter.js +37 -10
- package/dist/resources/extensions/gsd/uok/parity-report.js +58 -0
- package/dist/resources/extensions/gsd/uok/plan-v2.js +10 -4
- package/dist/resources/extensions/gsd/uok/writer.js +82 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +85 -8
- package/dist/resources/extensions/gsd/worktree-resolver.js +86 -7
- package/dist/resources/extensions/gsd/worktree-telemetry.js +198 -0
- package/dist/resources/extensions/mcp-client/index.js +3 -1
- package/dist/resources/extensions/ollama/index.js +5 -1
- package/dist/resources/extensions/remote-questions/manager.js +11 -5
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
- package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +2 -3
- package/packages/daemon/package.json +2 -2
- package/packages/daemon/src/logger.ts +4 -3
- package/packages/mcp-server/dist/server.d.ts +24 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +88 -87
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
- package/packages/mcp-server/dist/workflow-tools.js +15 -6
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +2 -2
- package/packages/mcp-server/src/mcp-server.test.ts +25 -3
- package/packages/mcp-server/src/readers/graph.test.ts +87 -15
- package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
- package/packages/mcp-server/src/server.ts +131 -105
- package/packages/mcp-server/src/workflow-tools.test.ts +85 -0
- package/packages/mcp-server/src/workflow-tools.ts +19 -6
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +2 -2
- package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
- package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
- package/packages/native/src/__tests__/ps.test.mjs +14 -8
- package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
- package/packages/native/src/__tests__/truncate.test.mjs +17 -2
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
- package/packages/pi-agent-core/src/agent.test.ts +96 -102
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/capability-patches.js +9 -2
- package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
- package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.test.js +43 -70
- package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +36 -11
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +44 -0
- package/packages/pi-ai/src/models/capability-patches.ts +10 -2
- package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
- package/packages/pi-ai/src/models/generated/openai.ts +17 -0
- package/packages/pi-ai/src/models.generated.test.ts +46 -73
- package/packages/pi-ai/src/models.test.ts +48 -11
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
- package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -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 +61 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +36 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +30 -12
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
- package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
- package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
- package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
- package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
- package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
- package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +49 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +48 -9
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
- package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +37 -11
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
- package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
- package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
- package/packages/pi-tui/dist/components/editor.d.ts +14 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +19 -0
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.js +6 -5
- package/packages/pi-tui/dist/components/image.test.js.map +1 -1
- package/packages/pi-tui/dist/editor-component.d.ts +2 -0
- package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
- package/packages/pi-tui/dist/editor-component.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
- package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +42 -11
- package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
- package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
- package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
- package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
- package/packages/pi-tui/src/components/editor.ts +22 -0
- package/packages/pi-tui/src/components/image.test.ts +10 -5
- package/packages/pi-tui/src/editor-component.ts +3 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/dist/rpc-client.test.js +101 -51
- package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/packages/rpc-client/src/rpc-client.test.ts +109 -52
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/pkg/package.json +1 -1
- package/scripts/install.js +15 -1
- package/src/resources/extensions/browser-tools/capture.ts +12 -0
- package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
- package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +75 -16
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
- package/src/resources/extensions/github-sync/templates.ts +151 -0
- package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
- package/src/resources/extensions/github-sync/tests/templates.test.ts +92 -1
- package/src/resources/extensions/google-search/index.ts +3 -2
- package/src/resources/extensions/gsd/auto/loop.ts +142 -2
- package/src/resources/extensions/gsd/auto/phases.ts +62 -38
- package/src/resources/extensions/gsd/auto/session.ts +7 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +156 -29
- package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
- package/src/resources/extensions/gsd/auto-post-unit.ts +163 -73
- package/src/resources/extensions/gsd/auto-prompts.ts +385 -93
- package/src/resources/extensions/gsd/auto-recovery.ts +230 -51
- package/src/resources/extensions/gsd/auto-start.ts +127 -9
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
- package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
- package/src/resources/extensions/gsd/auto.ts +90 -23
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +20 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
- package/src/resources/extensions/gsd/component-loader.ts +598 -0
- package/src/resources/extensions/gsd/component-types.ts +362 -0
- package/src/resources/extensions/gsd/context-store.ts +25 -8
- package/src/resources/extensions/gsd/detection.ts +58 -1
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -20
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/forensics.ts +118 -1
- package/src/resources/extensions/gsd/gate-registry.ts +2 -2
- package/src/resources/extensions/gsd/git-constants.ts +30 -1
- package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
- package/src/resources/extensions/gsd/git-service.ts +149 -2
- package/src/resources/extensions/gsd/gsd-db.ts +6 -3
- package/src/resources/extensions/gsd/guided-flow.ts +57 -14
- package/src/resources/extensions/gsd/journal.ts +11 -1
- package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
- package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
- package/src/resources/extensions/gsd/milestone-summary-classifier.ts +42 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
- package/src/resources/extensions/gsd/model-router.ts +6 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
- package/src/resources/extensions/gsd/preferences-validation.ts +21 -0
- package/src/resources/extensions/gsd/prompt-cache-optimizer.ts +4 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +23 -4
- package/src/resources/extensions/gsd/prompts/doctor-heal.md +5 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
- package/src/resources/extensions/gsd/service-tier.ts +5 -2
- package/src/resources/extensions/gsd/session-lock.ts +20 -10
- package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
- package/src/resources/extensions/gsd/slice-cadence.ts +299 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
- package/src/resources/extensions/gsd/state-transition-matrix.ts +152 -0
- package/src/resources/extensions/gsd/state.ts +76 -66
- package/src/resources/extensions/gsd/sync-lock.ts +97 -39
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
- package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
- package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +133 -292
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +4 -1
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -194
- package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
- package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
- package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
- package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +159 -0
- package/src/resources/extensions/gsd/tests/db-access-guardrails.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/execution-entry-missing-context-4671.test.ts +173 -0
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +8 -104
- package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +117 -0
- package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -56
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
- package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
- package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +9 -3
- package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +64 -0
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +93 -1
- package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -55
- package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
- package/src/resources/extensions/gsd/tests/milestone-summary-classifier.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -48
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -130
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/prompt-cache-optimizer.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +15 -4
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
- package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
- package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
- package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
- package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/sidecar-queue.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
- package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
- package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +242 -0
- package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
- package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +29 -5
- package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
- package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +7 -6
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
- package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/test-helpers.test.ts +98 -0
- package/src/resources/extensions/gsd/tests/test-helpers.ts +153 -0
- package/src/resources/extensions/gsd/tests/token-profile.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
- package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/uok-execution-graph.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
- package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/uok-parity-report.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +19 -2
- package/src/resources/extensions/gsd/tests/uok-writer.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -80
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
- package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +210 -0
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
- package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +8 -2
- package/src/resources/extensions/gsd/types.ts +3 -3
- package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
- package/src/resources/extensions/gsd/uok/contracts.ts +65 -0
- package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +56 -0
- package/src/resources/extensions/gsd/uok/execution-graph.ts +22 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
- package/src/resources/extensions/gsd/uok/gitops.ts +6 -1
- package/src/resources/extensions/gsd/uok/loop-adapter.ts +45 -10
- package/src/resources/extensions/gsd/uok/parity-report.ts +84 -0
- package/src/resources/extensions/gsd/uok/plan-v2.ts +13 -5
- package/src/resources/extensions/gsd/uok/writer.ts +113 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +108 -7
- package/src/resources/extensions/gsd/worktree-resolver.ts +96 -9
- package/src/resources/extensions/gsd/worktree-telemetry.ts +322 -0
- package/src/resources/extensions/mcp-client/index.ts +3 -1
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
- package/src/resources/extensions/ollama/index.ts +5 -1
- package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
- package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
- package/src/resources/extensions/remote-questions/manager.ts +36 -4
- package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
- package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
- package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
- package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -143
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
- package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
- package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
- package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -74
- package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
- package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
- package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -125
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -42
- /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{5wbu35_C2_MQ3Jj1lEVDx → cAJH99yNS1UPbeSEiNRrV}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Component Loader
|
|
3
|
+
*
|
|
4
|
+
* Multi-format loader that handles:
|
|
5
|
+
* 1. New format: component.yaml + SKILL.md/AGENT.md
|
|
6
|
+
* 2. Legacy skill format: SKILL.md with YAML frontmatter
|
|
7
|
+
* 3. Legacy agent format: .md with YAML frontmatter (name, description, tools, model)
|
|
8
|
+
*
|
|
9
|
+
* Auto-detects format by checking for component.yaml first, then falling back
|
|
10
|
+
* to legacy formats based on file naming conventions.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
13
|
+
import { basename, dirname, join } from 'node:path';
|
|
14
|
+
import { parse as parseYaml } from 'yaml';
|
|
15
|
+
import { parseFrontmatter } from '@gsd/pi-coding-agent';
|
|
16
|
+
import { validateComponentName, validateComponentDescription, computeComponentId, } from './component-types.js';
|
|
17
|
+
const SUPPORTED_COMPONENT_KINDS = ['skill', 'agent'];
|
|
18
|
+
const SUPPORTED_API_VERSIONS = ['gsd/v1'];
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// Single Component Loading
|
|
21
|
+
// ============================================================================
|
|
22
|
+
/**
|
|
23
|
+
* Load a component from a directory.
|
|
24
|
+
* Checks for component.yaml first, then legacy formats.
|
|
25
|
+
*/
|
|
26
|
+
export function loadComponentFromDir(dir, source) {
|
|
27
|
+
const diagnostics = [];
|
|
28
|
+
// Try new format first: component.yaml
|
|
29
|
+
const componentYamlPath = join(dir, 'component.yaml');
|
|
30
|
+
if (existsSync(componentYamlPath)) {
|
|
31
|
+
return loadFromComponentYaml(componentYamlPath, dir, source);
|
|
32
|
+
}
|
|
33
|
+
// Try legacy skill format: SKILL.md
|
|
34
|
+
const skillMdPath = join(dir, 'SKILL.md');
|
|
35
|
+
if (existsSync(skillMdPath)) {
|
|
36
|
+
return loadFromLegacySkill(skillMdPath, dir, source);
|
|
37
|
+
}
|
|
38
|
+
// No recognized component format found
|
|
39
|
+
return { component: null, diagnostics };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Load a component from a legacy agent .md file (flat file, not directory).
|
|
43
|
+
*/
|
|
44
|
+
export function loadComponentFromAgentFile(filePath, source) {
|
|
45
|
+
return loadFromLegacyAgent(filePath, source);
|
|
46
|
+
}
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// New Format: component.yaml
|
|
49
|
+
// ============================================================================
|
|
50
|
+
function loadFromComponentYaml(yamlPath, dir, source) {
|
|
51
|
+
const diagnostics = [];
|
|
52
|
+
let raw;
|
|
53
|
+
try {
|
|
54
|
+
raw = readFileSync(yamlPath, 'utf-8');
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
const msg = error instanceof Error ? error.message : 'failed to read component.yaml';
|
|
58
|
+
diagnostics.push({ type: 'error', message: msg, path: yamlPath });
|
|
59
|
+
return { component: null, diagnostics };
|
|
60
|
+
}
|
|
61
|
+
let definition;
|
|
62
|
+
try {
|
|
63
|
+
definition = parseYaml(raw);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
const msg = error instanceof Error ? error.message : 'failed to parse component.yaml';
|
|
67
|
+
diagnostics.push({ type: 'error', message: `invalid YAML: ${msg}`, path: yamlPath });
|
|
68
|
+
return { component: null, diagnostics };
|
|
69
|
+
}
|
|
70
|
+
// Validate required fields
|
|
71
|
+
if (!definition?.apiVersion) {
|
|
72
|
+
diagnostics.push({ type: 'error', message: 'missing apiVersion', path: yamlPath });
|
|
73
|
+
return { component: null, diagnostics };
|
|
74
|
+
}
|
|
75
|
+
if (!SUPPORTED_API_VERSIONS.includes(definition.apiVersion)) {
|
|
76
|
+
diagnostics.push({
|
|
77
|
+
type: 'error',
|
|
78
|
+
message: `unsupported apiVersion "${String(definition.apiVersion)}"`,
|
|
79
|
+
path: yamlPath,
|
|
80
|
+
});
|
|
81
|
+
return { component: null, diagnostics };
|
|
82
|
+
}
|
|
83
|
+
if (!definition.kind) {
|
|
84
|
+
diagnostics.push({ type: 'error', message: 'missing kind', path: yamlPath });
|
|
85
|
+
return { component: null, diagnostics };
|
|
86
|
+
}
|
|
87
|
+
if (!SUPPORTED_COMPONENT_KINDS.includes(definition.kind)) {
|
|
88
|
+
diagnostics.push({
|
|
89
|
+
type: 'error',
|
|
90
|
+
message: `unsupported kind "${definition.kind}"`,
|
|
91
|
+
path: yamlPath,
|
|
92
|
+
});
|
|
93
|
+
return { component: null, diagnostics };
|
|
94
|
+
}
|
|
95
|
+
if (!definition.metadata?.name) {
|
|
96
|
+
diagnostics.push({ type: 'error', message: 'missing metadata.name', path: yamlPath });
|
|
97
|
+
return { component: null, diagnostics };
|
|
98
|
+
}
|
|
99
|
+
if (!definition.metadata?.description) {
|
|
100
|
+
diagnostics.push({ type: 'error', message: 'missing metadata.description', path: yamlPath });
|
|
101
|
+
return { component: null, diagnostics };
|
|
102
|
+
}
|
|
103
|
+
const nameErrors = validateComponentName(definition.metadata.name);
|
|
104
|
+
for (const err of nameErrors) {
|
|
105
|
+
diagnostics.push({ type: 'error', message: err, path: yamlPath });
|
|
106
|
+
}
|
|
107
|
+
const descErrors = validateComponentDescription(definition.metadata.description);
|
|
108
|
+
for (const err of descErrors) {
|
|
109
|
+
diagnostics.push({ type: 'error', message: err, path: yamlPath });
|
|
110
|
+
}
|
|
111
|
+
if (nameErrors.length > 0 || descErrors.length > 0) {
|
|
112
|
+
return { component: null, diagnostics };
|
|
113
|
+
}
|
|
114
|
+
// Validate kind-specific spec
|
|
115
|
+
if (!definition.spec) {
|
|
116
|
+
diagnostics.push({ type: 'error', message: 'missing spec', path: yamlPath });
|
|
117
|
+
return { component: null, diagnostics };
|
|
118
|
+
}
|
|
119
|
+
const entryFileDiagnostic = validateEntryFile(definition.kind, definition.spec, dir, yamlPath);
|
|
120
|
+
if (entryFileDiagnostic) {
|
|
121
|
+
diagnostics.push(entryFileDiagnostic);
|
|
122
|
+
return { component: null, diagnostics };
|
|
123
|
+
}
|
|
124
|
+
const id = computeComponentId(definition.metadata.name, definition.metadata.namespace);
|
|
125
|
+
const component = {
|
|
126
|
+
id,
|
|
127
|
+
kind: definition.kind,
|
|
128
|
+
metadata: definition.metadata,
|
|
129
|
+
spec: definition.spec,
|
|
130
|
+
requires: definition.requires,
|
|
131
|
+
compatibility: definition.compatibility,
|
|
132
|
+
routing: definition.routing,
|
|
133
|
+
dirPath: dir,
|
|
134
|
+
filePath: yamlPath,
|
|
135
|
+
source,
|
|
136
|
+
format: 'component-yaml',
|
|
137
|
+
enabled: true,
|
|
138
|
+
};
|
|
139
|
+
return { component, diagnostics };
|
|
140
|
+
}
|
|
141
|
+
function loadFromLegacySkill(filePath, dir, source) {
|
|
142
|
+
const diagnostics = [];
|
|
143
|
+
let raw;
|
|
144
|
+
try {
|
|
145
|
+
raw = readFileSync(filePath, 'utf-8');
|
|
146
|
+
}
|
|
147
|
+
catch (error) {
|
|
148
|
+
const msg = error instanceof Error ? error.message : 'failed to read SKILL.md';
|
|
149
|
+
diagnostics.push({ type: 'warning', message: msg, path: filePath });
|
|
150
|
+
return { component: null, diagnostics };
|
|
151
|
+
}
|
|
152
|
+
const { frontmatter } = parseFrontmatter(raw);
|
|
153
|
+
const parentDirName = basename(dir);
|
|
154
|
+
const name = frontmatter.name || parentDirName;
|
|
155
|
+
// Validate
|
|
156
|
+
const nameErrors = validateComponentName(name);
|
|
157
|
+
for (const err of nameErrors) {
|
|
158
|
+
diagnostics.push({ type: 'warning', message: err, path: filePath });
|
|
159
|
+
}
|
|
160
|
+
const descErrors = validateComponentDescription(frontmatter.description);
|
|
161
|
+
for (const err of descErrors) {
|
|
162
|
+
diagnostics.push({ type: 'warning', message: err, path: filePath });
|
|
163
|
+
}
|
|
164
|
+
if (!frontmatter.description || frontmatter.description.trim() === '') {
|
|
165
|
+
return { component: null, diagnostics };
|
|
166
|
+
}
|
|
167
|
+
const spec = {
|
|
168
|
+
prompt: 'SKILL.md',
|
|
169
|
+
disableModelInvocation: frontmatter['disable-model-invocation'] === true,
|
|
170
|
+
};
|
|
171
|
+
const id = computeComponentId(name);
|
|
172
|
+
const component = {
|
|
173
|
+
id,
|
|
174
|
+
kind: 'skill',
|
|
175
|
+
metadata: {
|
|
176
|
+
name,
|
|
177
|
+
description: frontmatter.description,
|
|
178
|
+
},
|
|
179
|
+
spec,
|
|
180
|
+
dirPath: dir,
|
|
181
|
+
filePath,
|
|
182
|
+
source,
|
|
183
|
+
format: 'skill-md',
|
|
184
|
+
enabled: true,
|
|
185
|
+
};
|
|
186
|
+
return { component, diagnostics };
|
|
187
|
+
}
|
|
188
|
+
function loadFromLegacyAgent(filePath, source) {
|
|
189
|
+
const diagnostics = [];
|
|
190
|
+
let raw;
|
|
191
|
+
try {
|
|
192
|
+
raw = readFileSync(filePath, 'utf-8');
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
const msg = error instanceof Error ? error.message : 'failed to read agent file';
|
|
196
|
+
diagnostics.push({ type: 'warning', message: msg, path: filePath });
|
|
197
|
+
return { component: null, diagnostics };
|
|
198
|
+
}
|
|
199
|
+
const { frontmatter } = parseFrontmatter(raw);
|
|
200
|
+
if (!frontmatter.name || !frontmatter.description) {
|
|
201
|
+
diagnostics.push({
|
|
202
|
+
type: 'warning',
|
|
203
|
+
message: 'agent file missing name or description in frontmatter',
|
|
204
|
+
path: filePath,
|
|
205
|
+
});
|
|
206
|
+
return { component: null, diagnostics };
|
|
207
|
+
}
|
|
208
|
+
// Parse tools from comma-separated string
|
|
209
|
+
const tools = frontmatter.tools
|
|
210
|
+
? {
|
|
211
|
+
allow: frontmatter.tools
|
|
212
|
+
.split(',')
|
|
213
|
+
.map((t) => t.trim())
|
|
214
|
+
.filter(Boolean),
|
|
215
|
+
}
|
|
216
|
+
: undefined;
|
|
217
|
+
const spec = {
|
|
218
|
+
systemPrompt: basename(filePath),
|
|
219
|
+
model: frontmatter.model,
|
|
220
|
+
tools,
|
|
221
|
+
};
|
|
222
|
+
const id = computeComponentId(frontmatter.name);
|
|
223
|
+
const dir = dirname(filePath);
|
|
224
|
+
const component = {
|
|
225
|
+
id,
|
|
226
|
+
kind: 'agent',
|
|
227
|
+
metadata: {
|
|
228
|
+
name: frontmatter.name,
|
|
229
|
+
description: frontmatter.description,
|
|
230
|
+
},
|
|
231
|
+
spec,
|
|
232
|
+
dirPath: dir,
|
|
233
|
+
filePath,
|
|
234
|
+
source,
|
|
235
|
+
format: 'agent-md',
|
|
236
|
+
enabled: true,
|
|
237
|
+
};
|
|
238
|
+
return { component, diagnostics };
|
|
239
|
+
}
|
|
240
|
+
// ============================================================================
|
|
241
|
+
// Directory Scanning
|
|
242
|
+
// ============================================================================
|
|
243
|
+
/**
|
|
244
|
+
* Scan a directory for components (skills format).
|
|
245
|
+
* Handles both new and legacy directory layouts.
|
|
246
|
+
*
|
|
247
|
+
* Expected layouts:
|
|
248
|
+
* - dir/{component-name}/component.yaml (new format)
|
|
249
|
+
* - dir/{component-name}/SKILL.md (legacy skill)
|
|
250
|
+
* - dir/{name}.md (legacy root-level skill)
|
|
251
|
+
*/
|
|
252
|
+
export function scanComponentDir(dir, source, kind) {
|
|
253
|
+
const components = [];
|
|
254
|
+
const diagnostics = [];
|
|
255
|
+
if (!existsSync(dir)) {
|
|
256
|
+
return { components, diagnostics };
|
|
257
|
+
}
|
|
258
|
+
let entries;
|
|
259
|
+
try {
|
|
260
|
+
entries = readdirSync(dir, { withFileTypes: true, encoding: 'utf-8' });
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
return { components, diagnostics };
|
|
264
|
+
}
|
|
265
|
+
for (const entry of entries) {
|
|
266
|
+
if (entry.name.startsWith('.') || entry.name === 'node_modules') {
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
const fullPath = join(dir, entry.name);
|
|
270
|
+
let isDir = entry.isDirectory();
|
|
271
|
+
let isFile = entry.isFile();
|
|
272
|
+
if (entry.isSymbolicLink()) {
|
|
273
|
+
try {
|
|
274
|
+
const stats = statSync(fullPath);
|
|
275
|
+
isDir = stats.isDirectory();
|
|
276
|
+
isFile = stats.isFile();
|
|
277
|
+
}
|
|
278
|
+
catch {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
if (isDir) {
|
|
283
|
+
const result = loadComponentFromDir(fullPath, source);
|
|
284
|
+
if (result.component) {
|
|
285
|
+
if (!kind || result.component.kind === kind) {
|
|
286
|
+
components.push(result.component);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
diagnostics.push(...result.diagnostics);
|
|
290
|
+
}
|
|
291
|
+
else if (isFile && entry.name.endsWith('.md')) {
|
|
292
|
+
// Root-level .md files — could be legacy skills or agents
|
|
293
|
+
// Peek at frontmatter to determine type
|
|
294
|
+
const result = loadFromFile(fullPath, source);
|
|
295
|
+
if (result.component) {
|
|
296
|
+
if (!kind || result.component.kind === kind) {
|
|
297
|
+
components.push(result.component);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
diagnostics.push(...result.diagnostics);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return { components, diagnostics };
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Scan a directory specifically for agent .md files (legacy agent format).
|
|
307
|
+
*/
|
|
308
|
+
export function scanAgentDir(dir, source) {
|
|
309
|
+
const components = [];
|
|
310
|
+
const diagnostics = [];
|
|
311
|
+
if (!existsSync(dir)) {
|
|
312
|
+
return { components, diagnostics };
|
|
313
|
+
}
|
|
314
|
+
let entries;
|
|
315
|
+
try {
|
|
316
|
+
entries = readdirSync(dir, { withFileTypes: true, encoding: 'utf-8' });
|
|
317
|
+
}
|
|
318
|
+
catch {
|
|
319
|
+
return { components, diagnostics };
|
|
320
|
+
}
|
|
321
|
+
for (const entry of entries) {
|
|
322
|
+
const fullPath = join(dir, entry.name);
|
|
323
|
+
let isDir = entry.isDirectory();
|
|
324
|
+
let isFile = entry.isFile();
|
|
325
|
+
if (entry.isSymbolicLink()) {
|
|
326
|
+
try {
|
|
327
|
+
const stats = statSync(fullPath);
|
|
328
|
+
isDir = stats.isDirectory();
|
|
329
|
+
isFile = stats.isFile();
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
if (isDir) {
|
|
336
|
+
const result = loadComponentFromDir(fullPath, source);
|
|
337
|
+
if (result.component?.kind === 'agent') {
|
|
338
|
+
components.push(result.component);
|
|
339
|
+
}
|
|
340
|
+
diagnostics.push(...result.diagnostics);
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
if (!entry.name.endsWith('.md'))
|
|
344
|
+
continue;
|
|
345
|
+
if (!isFile)
|
|
346
|
+
continue;
|
|
347
|
+
// Check if there's a component.yaml in a same-named directory
|
|
348
|
+
const nameWithoutExt = entry.name.replace(/\.md$/, '');
|
|
349
|
+
const componentDir = join(dir, nameWithoutExt);
|
|
350
|
+
if (existsSync(join(componentDir, 'component.yaml'))) {
|
|
351
|
+
// New format takes precedence and is loaded by the directory branch.
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
const result = loadComponentFromAgentFile(fullPath, source);
|
|
355
|
+
if (result.component) {
|
|
356
|
+
components.push(result.component);
|
|
357
|
+
}
|
|
358
|
+
diagnostics.push(...result.diagnostics);
|
|
359
|
+
}
|
|
360
|
+
return { components, diagnostics };
|
|
361
|
+
}
|
|
362
|
+
// ============================================================================
|
|
363
|
+
// Helpers
|
|
364
|
+
// ============================================================================
|
|
365
|
+
/**
|
|
366
|
+
* Load a single file, detecting whether it's a skill or agent by frontmatter.
|
|
367
|
+
*/
|
|
368
|
+
function loadFromFile(filePath, source) {
|
|
369
|
+
const diagnostics = [];
|
|
370
|
+
let raw;
|
|
371
|
+
try {
|
|
372
|
+
raw = readFileSync(filePath, 'utf-8');
|
|
373
|
+
}
|
|
374
|
+
catch (error) {
|
|
375
|
+
const msg = error instanceof Error ? error.message : 'failed to read file';
|
|
376
|
+
diagnostics.push({ type: 'warning', message: msg, path: filePath });
|
|
377
|
+
return { component: null, diagnostics };
|
|
378
|
+
}
|
|
379
|
+
const { frontmatter } = parseFrontmatter(raw);
|
|
380
|
+
// If it has 'tools' field, treat as agent
|
|
381
|
+
if (frontmatter.tools !== undefined) {
|
|
382
|
+
return loadFromLegacyAgent(filePath, source);
|
|
383
|
+
}
|
|
384
|
+
// Otherwise treat as a legacy skill (root-level .md)
|
|
385
|
+
const dir = dirname(filePath);
|
|
386
|
+
const name = frontmatter.name || basename(filePath, '.md');
|
|
387
|
+
const description = frontmatter.description;
|
|
388
|
+
if (!description || description.trim() === '') {
|
|
389
|
+
return { component: null, diagnostics };
|
|
390
|
+
}
|
|
391
|
+
const spec = {
|
|
392
|
+
prompt: basename(filePath),
|
|
393
|
+
disableModelInvocation: frontmatter['disable-model-invocation'] === true,
|
|
394
|
+
};
|
|
395
|
+
const id = computeComponentId(name);
|
|
396
|
+
const component = {
|
|
397
|
+
id,
|
|
398
|
+
kind: 'skill',
|
|
399
|
+
metadata: { name, description },
|
|
400
|
+
spec,
|
|
401
|
+
dirPath: dir,
|
|
402
|
+
filePath,
|
|
403
|
+
source,
|
|
404
|
+
format: 'skill-md',
|
|
405
|
+
enabled: true,
|
|
406
|
+
};
|
|
407
|
+
return { component, diagnostics };
|
|
408
|
+
}
|
|
409
|
+
function validateEntryFile(kind, spec, dir, yamlPath) {
|
|
410
|
+
const relativePath = kind === 'skill'
|
|
411
|
+
? spec.prompt
|
|
412
|
+
: spec.systemPrompt;
|
|
413
|
+
const field = kind === 'skill' ? 'spec.prompt' : 'spec.systemPrompt';
|
|
414
|
+
if (!relativePath || typeof relativePath !== 'string') {
|
|
415
|
+
return {
|
|
416
|
+
type: 'error',
|
|
417
|
+
message: `missing ${field}`,
|
|
418
|
+
path: yamlPath,
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
const entryPath = join(dir, relativePath);
|
|
422
|
+
if (!existsSync(entryPath)) {
|
|
423
|
+
return {
|
|
424
|
+
type: 'error',
|
|
425
|
+
message: `missing referenced file for ${field}: ${relativePath}`,
|
|
426
|
+
path: entryPath,
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
try {
|
|
430
|
+
if (!statSync(entryPath).isFile()) {
|
|
431
|
+
return {
|
|
432
|
+
type: 'error',
|
|
433
|
+
message: `referenced ${field} is not a file: ${relativePath}`,
|
|
434
|
+
path: entryPath,
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
catch (error) {
|
|
439
|
+
const msg = error instanceof Error ? error.message : 'failed to inspect referenced file';
|
|
440
|
+
return {
|
|
441
|
+
type: 'error',
|
|
442
|
+
message: `${msg}: ${relativePath}`,
|
|
443
|
+
path: entryPath,
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Component Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Shared metadata for installable/discoverable skills and agents.
|
|
5
|
+
*
|
|
6
|
+
* Replaces the separate type systems in:
|
|
7
|
+
* - packages/pi-coding-agent/src/core/skills.ts (SkillFrontmatter, Skill)
|
|
8
|
+
* - src/resources/extensions/subagent/agents.ts (AgentConfig)
|
|
9
|
+
*
|
|
10
|
+
* Legacy skill and agent formats are supported via backward-compatible loading.
|
|
11
|
+
*/
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// Validation
|
|
14
|
+
// ============================================================================
|
|
15
|
+
/** Max name length per spec */
|
|
16
|
+
export const MAX_NAME_LENGTH = 64;
|
|
17
|
+
/** Max description length per spec */
|
|
18
|
+
export const MAX_DESCRIPTION_LENGTH = 1024;
|
|
19
|
+
/** Valid name pattern: lowercase a-z, 0-9, hyphens, no leading/trailing/consecutive hyphens */
|
|
20
|
+
export const NAME_PATTERN = /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/;
|
|
21
|
+
/**
|
|
22
|
+
* Validate a component name.
|
|
23
|
+
* @returns Array of error messages (empty if valid).
|
|
24
|
+
*/
|
|
25
|
+
export function validateComponentName(name) {
|
|
26
|
+
const errors = [];
|
|
27
|
+
if (!name || name.trim() === '') {
|
|
28
|
+
errors.push('name is required');
|
|
29
|
+
return errors;
|
|
30
|
+
}
|
|
31
|
+
if (name.length > MAX_NAME_LENGTH) {
|
|
32
|
+
errors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);
|
|
33
|
+
}
|
|
34
|
+
if (name.includes('--')) {
|
|
35
|
+
errors.push('name must not contain consecutive hyphens');
|
|
36
|
+
}
|
|
37
|
+
if (!NAME_PATTERN.test(name)) {
|
|
38
|
+
if (/[A-Z]/.test(name)) {
|
|
39
|
+
errors.push('name must be lowercase');
|
|
40
|
+
}
|
|
41
|
+
else if (name.startsWith('-') || name.endsWith('-')) {
|
|
42
|
+
errors.push('name must not start or end with a hyphen');
|
|
43
|
+
}
|
|
44
|
+
else if (!name.includes('--')) {
|
|
45
|
+
errors.push('name must contain only lowercase a-z, 0-9, and hyphens');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return errors;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Validate a component description.
|
|
52
|
+
* @returns Array of error messages (empty if valid).
|
|
53
|
+
*/
|
|
54
|
+
export function validateComponentDescription(description) {
|
|
55
|
+
const errors = [];
|
|
56
|
+
if (!description || description.trim() === '') {
|
|
57
|
+
errors.push('description is required');
|
|
58
|
+
}
|
|
59
|
+
else if (description.length > MAX_DESCRIPTION_LENGTH) {
|
|
60
|
+
errors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);
|
|
61
|
+
}
|
|
62
|
+
return errors;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Compute the canonical ID for a component.
|
|
66
|
+
*/
|
|
67
|
+
export function computeComponentId(name, namespace) {
|
|
68
|
+
return namespace ? `${namespace}:${name}` : name;
|
|
69
|
+
}
|
|
@@ -180,7 +180,13 @@ export function queryProject() {
|
|
|
180
180
|
// ─── Knowledge Query ───────────────────────────────────────────────────────
|
|
181
181
|
/**
|
|
182
182
|
* Filter KNOWLEDGE.md sections by keyword matching.
|
|
183
|
-
*
|
|
183
|
+
*
|
|
184
|
+
* Structure-adaptive (issue #4719): files that organise entries as H3 items
|
|
185
|
+
* under one or more H2 topics are filtered at H3 granularity. Files with only
|
|
186
|
+
* H2 topic headers (no H3) fall back to H2-level filtering for backwards
|
|
187
|
+
* compatibility.
|
|
188
|
+
*
|
|
189
|
+
* Matches keywords case-insensitively against:
|
|
184
190
|
* 1. Section header text
|
|
185
191
|
* 2. First paragraph of section content (up to first blank line or next heading)
|
|
186
192
|
*
|
|
@@ -189,28 +195,38 @@ export function queryProject() {
|
|
|
189
195
|
*
|
|
190
196
|
* @param content - Full KNOWLEDGE.md content
|
|
191
197
|
* @param keywords - Keywords to match (case-insensitive)
|
|
192
|
-
* @returns Concatenated matching sections with
|
|
198
|
+
* @returns Concatenated matching sections with their original heading prefix, or empty string
|
|
193
199
|
*/
|
|
194
200
|
export async function queryKnowledge(content, keywords) {
|
|
195
201
|
if (!content || keywords.length === 0)
|
|
196
202
|
return '';
|
|
197
203
|
// Lazy import to avoid circular dependency
|
|
198
204
|
const { extractAllSections } = await import('./files.js');
|
|
199
|
-
|
|
205
|
+
// Prefer H3 granularity when available; fall back to H2 for H2-only files.
|
|
206
|
+
// This prevents single-H2-with-many-H3 layouts from returning the entire
|
|
207
|
+
// file on a keyword match against the H2 header or its first paragraph.
|
|
208
|
+
const h3Sections = extractAllSections(content, 3);
|
|
209
|
+
const useH3 = h3Sections.size > 0;
|
|
210
|
+
const sections = useH3 ? h3Sections : extractAllSections(content, 2);
|
|
200
211
|
if (sections.size === 0)
|
|
201
212
|
return '';
|
|
202
|
-
|
|
203
|
-
|
|
213
|
+
const prefix = useH3 ? '###' : '##';
|
|
214
|
+
// Trim, lowercase, drop empties, and de-dupe so callers can pass raw
|
|
215
|
+
// user-provided strings without risking empty-string / whitespace matches.
|
|
216
|
+
const normalizedKeywords = [...new Set(keywords
|
|
217
|
+
.map(k => k.trim().toLowerCase())
|
|
218
|
+
.filter(k => k.length > 0))];
|
|
219
|
+
if (normalizedKeywords.length === 0)
|
|
220
|
+
return '';
|
|
204
221
|
const matchingSections = [];
|
|
205
222
|
for (const [header, body] of sections) {
|
|
206
223
|
// Extract first paragraph: everything up to first blank line or next heading
|
|
207
224
|
const firstParagraph = body.split(/\n\s*\n|\n#/)[0] || '';
|
|
208
|
-
// Check if any keyword matches header or first paragraph
|
|
209
225
|
const headerLower = header.toLowerCase();
|
|
210
226
|
const paragraphLower = firstParagraph.toLowerCase();
|
|
211
227
|
const matches = normalizedKeywords.some(kw => headerLower.includes(kw) || paragraphLower.includes(kw));
|
|
212
228
|
if (matches) {
|
|
213
|
-
matchingSections.push(
|
|
229
|
+
matchingSections.push(`${prefix} ${header}\n\n${body}`);
|
|
214
230
|
}
|
|
215
231
|
}
|
|
216
232
|
return matchingSections.join('\n\n');
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* flow to show when entering a project directory.
|
|
7
7
|
*/
|
|
8
8
|
import { existsSync, openSync, readSync, closeSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
9
|
-
import { join } from "node:path";
|
|
9
|
+
import { dirname, join, parse as parsePath } from "node:path";
|
|
10
10
|
import { homedir } from "node:os";
|
|
11
11
|
import { gsdRoot } from "./paths.js";
|
|
12
12
|
const gsdHome = process.env.GSD_HOME || join(homedir(), ".gsd");
|
|
@@ -951,6 +951,54 @@ function resolveVersionCatalogAccessors(basePath, versionCatalogFiles, settingsF
|
|
|
951
951
|
}
|
|
952
952
|
return accessors;
|
|
953
953
|
}
|
|
954
|
+
/**
|
|
955
|
+
* Walk ancestor directories of `startDir` looking for any file in
|
|
956
|
+
* `PROJECT_FILES`. Stops at the filesystem root or at a `.git` boundary
|
|
957
|
+
* (so ancestors above a git repo root — e.g. `$HOME` or `/usr/local` —
|
|
958
|
+
* can't trigger false positives). Returns true if an ancestor contains
|
|
959
|
+
* one of the project markers.
|
|
960
|
+
*
|
|
961
|
+
* Used by the worktree health check (#2347) to avoid warning about
|
|
962
|
+
* monorepos where package.json / Cargo.toml / etc. live in a parent
|
|
963
|
+
* directory rather than in the worktree's own checkout.
|
|
964
|
+
*
|
|
965
|
+
* `existsFn` is injectable so this remains deterministically testable
|
|
966
|
+
* without touching the real filesystem; defaults to `fs.existsSync`.
|
|
967
|
+
*/
|
|
968
|
+
export function hasProjectFileInAncestor(startDir, existsFn = existsSync) {
|
|
969
|
+
let checkDir = dirname(startDir);
|
|
970
|
+
const { root } = parsePath(checkDir);
|
|
971
|
+
while (checkDir !== root) {
|
|
972
|
+
if (PROJECT_FILES.some((f) => existsFn(join(checkDir, f)))) {
|
|
973
|
+
return true;
|
|
974
|
+
}
|
|
975
|
+
// Stop at git repository boundary — ancestors above the repo root
|
|
976
|
+
// may contain unrelated project files. Check AFTER project-file scan
|
|
977
|
+
// so a repo root containing both .git and a marker is still recognized.
|
|
978
|
+
if (existsFn(join(checkDir, ".git")))
|
|
979
|
+
return false;
|
|
980
|
+
checkDir = dirname(checkDir);
|
|
981
|
+
}
|
|
982
|
+
return false;
|
|
983
|
+
}
|
|
984
|
+
/**
|
|
985
|
+
* Check whether a project's `.gsd/` directory contains the bootstrap artifacts
|
|
986
|
+
* (`PREFERENCES.md` or `milestones/`) that indicate a completed init run.
|
|
987
|
+
*
|
|
988
|
+
* A zombie `.gsd/` state — symlink exists but neither artifact is present —
|
|
989
|
+
* must be treated as "needs init wizard". The previous guard checked only
|
|
990
|
+
* `existsSync(gsdRoot(basePath))`, which accepted zombie states and skipped
|
|
991
|
+
* the wizard (#2942).
|
|
992
|
+
*
|
|
993
|
+
* `existsFn` is injectable so tests can run deterministically; defaults to
|
|
994
|
+
* `fs.existsSync`.
|
|
995
|
+
*/
|
|
996
|
+
export function hasGsdBootstrapArtifacts(gsdPath, existsFn = existsSync) {
|
|
997
|
+
return (existsFn(gsdPath) &&
|
|
998
|
+
(existsFn(join(gsdPath, "PREFERENCES.md")) ||
|
|
999
|
+
existsFn(join(gsdPath, "preferences.md")) ||
|
|
1000
|
+
existsFn(join(gsdPath, "milestones"))));
|
|
1001
|
+
}
|
|
954
1002
|
export function scanProjectFiles(basePath) {
|
|
955
1003
|
const files = [];
|
|
956
1004
|
const queue = [{ path: basePath, depth: 0 }];
|
|
@@ -5,23 +5,8 @@ import { parseUnitId } from "./unit-id.js";
|
|
|
5
5
|
import { isDbAvailable, getMilestoneSlices, getMilestone } from "./gsd-db.js";
|
|
6
6
|
import { parseRoadmap } from "./parsers-legacy.js";
|
|
7
7
|
import { isClosedStatus } from "./status-guards.js";
|
|
8
|
+
import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
|
|
8
9
|
import { readFileSync } from "node:fs";
|
|
9
|
-
/**
|
|
10
|
-
* Detect failure-path milestone SUMMARY content (#4663 sibling to #4658).
|
|
11
|
-
* A failure SUMMARY must not let the dispatch guard treat an active
|
|
12
|
-
* milestone as complete. The markers mirror those produced by
|
|
13
|
-
* writeBlockerPlaceholder and the "verification FAILED" retry path.
|
|
14
|
-
*
|
|
15
|
-
* This is intentionally a minimal local detector so this fix does not
|
|
16
|
-
* depend on PR #4660's `classifyMilestoneSummaryContent`. It can migrate
|
|
17
|
-
* to the shared classifier once that lands.
|
|
18
|
-
*/
|
|
19
|
-
function isFailureMilestoneSummary(content) {
|
|
20
|
-
return (/(?:^|\n)\s*#\s*BLOCKER\b/i.test(content) ||
|
|
21
|
-
/auto-mode recovery failed/i.test(content) ||
|
|
22
|
-
/verification\s+failed/i.test(content) ||
|
|
23
|
-
/\bnot complete\b/i.test(content));
|
|
24
|
-
}
|
|
25
10
|
const SLICE_DISPATCH_TYPES = new Set([
|
|
26
11
|
"research-slice",
|
|
27
12
|
"plan-slice",
|
|
@@ -78,7 +63,7 @@ export function getPriorSliceCompletionBlocker(base, _mainBranch, unitType, unit
|
|
|
78
63
|
summaryContent = readFileSync(summaryPath, "utf-8");
|
|
79
64
|
}
|
|
80
65
|
catch { /* ignore */ }
|
|
81
|
-
if (!summaryContent ||
|
|
66
|
+
if (!summaryContent || classifyMilestoneSummaryContent(summaryContent) !== "failure") {
|
|
82
67
|
continue;
|
|
83
68
|
}
|
|
84
69
|
}
|
|
@@ -159,7 +159,7 @@ Setting `prefer_skills: []` does **not** disable skill discovery — it just mea
|
|
|
159
159
|
|
|
160
160
|
- `phases`: fine-grained control over which phases run. Usually set by `token_profile`, but can be overridden. Keys:
|
|
161
161
|
- `skip_research`: boolean — skip milestone-level research. Default: `false`.
|
|
162
|
-
- `reassess_after_slice`: boolean — run roadmap
|
|
162
|
+
- `reassess_after_slice`: boolean — run a dedicated roadmap-reassessment unit after each completed slice. Default: `false` (per ADR-003 §4). The plan-slice agent for the next slice performs JIT reassessment via a prompt preamble at zero additional token cost; a dedicated reassess session is opt-in. Set to `true` (e.g. via the `burn-max` profile) if you want the explicit session.
|
|
163
163
|
- `skip_reassess`: boolean — force-disable roadmap reassessment even if `reassess_after_slice` is enabled. Default: `false`.
|
|
164
164
|
- `skip_slice_research`: boolean — skip per-slice research. Default: `false`.
|
|
165
165
|
|