gsd-pi 2.77.0-dev.58d3d4d6c → 2.77.0-dev.cfd69e714
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 +1 -1
- package/dist/claude-cli-check.js +5 -1
- 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 +5 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
- package/dist/resources/extensions/gsd/auto/loop.js +43 -0
- package/dist/resources/extensions/gsd/auto/phases.js +15 -21
- package/dist/resources/extensions/gsd/auto/session.js +0 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +102 -24
- package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
- package/dist/resources/extensions/gsd/auto-post-unit.js +71 -64
- package/dist/resources/extensions/gsd/auto-prompts.js +329 -102
- package/dist/resources/extensions/gsd/auto-recovery.js +195 -23
- package/dist/resources/extensions/gsd/auto-start.js +34 -24
- 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 +31 -20
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -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/detection.js +49 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- 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 +17 -5
- 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/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/prompts/complete-milestone.md +6 -2
- 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-parallel-orchestrator.js +278 -8
- package/dist/resources/extensions/gsd/state.js +44 -33
- package/dist/resources/extensions/gsd/sync-lock.js +98 -42
- 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/gate-runner.js +53 -5
- package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +34 -8
- 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 +5 -5
- 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 +5 -5
- 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/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/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 +80 -39
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- 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/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/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/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/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/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/dynamic-border.test.ts +26 -20
- 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 +36 -12
- 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/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 +41 -12
- 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/src/rpc-client.test.ts +109 -52
- package/packages/rpc-client/tsconfig.tsbuildinfo +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 +5 -1
- 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/tests/cli.test.ts +76 -7
- package/src/resources/extensions/github-sync/tests/templates.test.ts +33 -1
- package/src/resources/extensions/gsd/auto/loop.ts +47 -0
- package/src/resources/extensions/gsd/auto/phases.ts +16 -20
- package/src/resources/extensions/gsd/auto/session.ts +0 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +113 -24
- package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
- package/src/resources/extensions/gsd/auto-post-unit.ts +82 -73
- package/src/resources/extensions/gsd/auto-prompts.ts +330 -90
- package/src/resources/extensions/gsd/auto-recovery.ts +225 -24
- package/src/resources/extensions/gsd/auto-start.ts +54 -6
- 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 +43 -22
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -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/detection.ts +58 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -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 +133 -2
- package/src/resources/extensions/gsd/gsd-db.ts +6 -3
- package/src/resources/extensions/gsd/guided-flow.ts +20 -5
- 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/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/prompts/complete-milestone.md +6 -2
- 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-parallel-orchestrator.ts +309 -8
- package/src/resources/extensions/gsd/state.ts +49 -44
- 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/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 +94 -289
- 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-retry-mcp-churn-fixes.test.ts +8 -197
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
- 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-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/crash-recovery.test.ts +50 -1
- 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 -3
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +9 -105
- 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/hook-key-parsing.test.ts +4 -55
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -57
- 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/interrupted-session-ui.test.ts +6 -9
- 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 -62
- package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -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 -49
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -133
- 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/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/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/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/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-parallel-orchestrator.test.ts +164 -1
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
- 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/test-helpers.test.ts +12 -61
- package/src/resources/extensions/gsd/tests/test-helpers.ts +21 -8
- 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-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/validate-milestone.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -81
- 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/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/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/gate-runner.ts +65 -5
- package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +55 -7
- 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 -144
- 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 -75
- package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/forensics-worktree-telemetry.test.ts +0 -145
- 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 -130
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -43
- /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_ssgManifest.js +0 -0
|
@@ -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
|
+
}
|
|
@@ -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 }];
|
|
@@ -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
|
|
|
@@ -37,9 +37,9 @@ export const GATE_REGISTRY = {
|
|
|
37
37
|
id: "Q4",
|
|
38
38
|
scope: "slice",
|
|
39
39
|
ownerTurn: "gate-evaluate",
|
|
40
|
-
question: "
|
|
40
|
+
question: "Which existing requirements (R-IDs) does this slice touch, and which must be re-tested?",
|
|
41
41
|
guidance: [
|
|
42
|
-
"List
|
|
42
|
+
"List the R-IDs (e.g. R001, R003) touched by this slice; see the milestone requirements artifact at .gsd/milestones/<id>/REQUIREMENTS.md.",
|
|
43
43
|
"Identify what must be re-tested after shipping.",
|
|
44
44
|
"Flag decisions that should be revisited given the new scope.",
|
|
45
45
|
"If no existing requirements are affected, return verdict 'omitted'.",
|
|
@@ -1,9 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Shared git constants used across git-service and native-git-bridge.
|
|
3
3
|
*/
|
|
4
|
+
/**
|
|
5
|
+
* Parent process env vars that, if leaked into a git child process, can
|
|
6
|
+
* silently redirect every operation to a different repo or index.
|
|
7
|
+
*
|
|
8
|
+
* Stripped from GIT_NO_PROMPT_ENV so a GSD invoked from inside a git hook,
|
|
9
|
+
* a different worktree's terminal, or any context that pre-set these vars
|
|
10
|
+
* cannot redirect GSD's git operations to the wrong target.
|
|
11
|
+
* (Issue #4980 NEW-1)
|
|
12
|
+
*/
|
|
13
|
+
const LEAKING_GIT_ENV_VARS = [
|
|
14
|
+
"GIT_DIR",
|
|
15
|
+
"GIT_WORK_TREE",
|
|
16
|
+
"GIT_INDEX_FILE",
|
|
17
|
+
"GIT_OBJECT_DIRECTORY",
|
|
18
|
+
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
19
|
+
"GIT_COMMON_DIR",
|
|
20
|
+
"GIT_NAMESPACE",
|
|
21
|
+
];
|
|
22
|
+
function buildSafeParentEnv() {
|
|
23
|
+
const safe = {};
|
|
24
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
25
|
+
if (!LEAKING_GIT_ENV_VARS.includes(k)) {
|
|
26
|
+
safe[k] = v;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return safe;
|
|
30
|
+
}
|
|
4
31
|
/** Env overlay that suppresses interactive git credential prompts and git-svn noise. */
|
|
5
32
|
export const GIT_NO_PROMPT_ENV = {
|
|
6
|
-
...
|
|
33
|
+
...buildSafeParentEnv(),
|
|
7
34
|
GIT_TERMINAL_PROMPT: "0",
|
|
8
35
|
GIT_ASKPASS: "",
|
|
9
36
|
GIT_SVN_ID: "",
|
|
@@ -9,12 +9,25 @@
|
|
|
9
9
|
* what actions were taken. `formatGitError` maps raw git errors to
|
|
10
10
|
* user-friendly messages suggesting `/gsd doctor`.
|
|
11
11
|
*/
|
|
12
|
+
import { execFileSync } from "node:child_process";
|
|
12
13
|
import { existsSync, unlinkSync } from "node:fs";
|
|
13
14
|
import { join } from "node:path";
|
|
14
15
|
import { MergeConflictError } from "./git-service.js";
|
|
15
16
|
import { nativeMergeAbort, nativeRebaseAbort, nativeResetHard } from "./native-git-bridge.js";
|
|
16
17
|
// Re-export for consumers
|
|
17
18
|
export { MergeConflictError };
|
|
19
|
+
function hasWorkingTreeChanges(cwd) {
|
|
20
|
+
try {
|
|
21
|
+
return execFileSync("git", ["status", "--porcelain"], {
|
|
22
|
+
cwd,
|
|
23
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
24
|
+
encoding: "utf-8",
|
|
25
|
+
}).trim().length > 0;
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
18
31
|
/**
|
|
19
32
|
* Detect and clean up leftover merge/rebase state, then hard-reset.
|
|
20
33
|
*
|
|
@@ -60,6 +73,20 @@ export function abortAndReset(cwd) {
|
|
|
60
73
|
cleaned.push("rebase abort attempted (may have failed)");
|
|
61
74
|
}
|
|
62
75
|
}
|
|
76
|
+
// Preserve any staged or untracked user work before the hard reset.
|
|
77
|
+
// Reset --hard discards staged changes (reflog only covers committed
|
|
78
|
+
// state), so a labeled stash gives the user a recovery handle if their
|
|
79
|
+
// in-flight inspection work would otherwise be silently lost.
|
|
80
|
+
// (Issue #4980 HIGH-5)
|
|
81
|
+
if (hasWorkingTreeChanges(cwd)) {
|
|
82
|
+
try {
|
|
83
|
+
execFileSync("git", ["stash", "push", "--include-untracked", "-m", `gsd: pre-self-heal-reset ${new Date().toISOString()}`], { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" });
|
|
84
|
+
cleaned.push("stashed working tree before reset");
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
/* nothing to stash, or stash refused (e.g. unresolved conflicts) — proceed */
|
|
88
|
+
}
|
|
89
|
+
}
|
|
63
90
|
// Always hard-reset to HEAD
|
|
64
91
|
try {
|
|
65
92
|
nativeResetHard(cwd);
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* This module centralizes the GitPreferences interface, runtime exclusion
|
|
8
8
|
* paths, commit type inference, and the runGit shell helper.
|
|
9
9
|
*/
|
|
10
|
-
import { execFileSync
|
|
10
|
+
import { execFileSync } from "node:child_process";
|
|
11
11
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
12
12
|
import { join } from "node:path";
|
|
13
13
|
import { gsdRoot } from "./paths.js";
|
|
@@ -243,6 +243,107 @@ export function resolveMilestoneIntegrationBranch(basePath, milestoneId, prefs =
|
|
|
243
243
|
reason: `Recorded integration branch "${recordedBranch}" for milestone ${milestoneId} no longer exists, and no safe fallback branch could be determined.`,
|
|
244
244
|
};
|
|
245
245
|
}
|
|
246
|
+
// ─── Pre-Merge Command Tokenizer ──────────────────────────────────────────
|
|
247
|
+
/**
|
|
248
|
+
* Tokenize a user-supplied pre-merge command string into argv form, with
|
|
249
|
+
* minimal support for double- and single-quoted strings. Designed to be
|
|
250
|
+
* sufficient for typical commands ("npm test", `npm run lint:ci`,
|
|
251
|
+
* `pnpm run tsc --noEmit`) without spawning a shell.
|
|
252
|
+
*
|
|
253
|
+
* Returns [] when the input is empty or whitespace-only.
|
|
254
|
+
* Throws when quoting is malformed.
|
|
255
|
+
*
|
|
256
|
+
* Used by GitServiceImpl.runPreMergeCheck to eliminate the shell-injection
|
|
257
|
+
* surface that running an arbitrary user string through a shell would create.
|
|
258
|
+
* (Issue #4980 HIGH-2)
|
|
259
|
+
*/
|
|
260
|
+
export function tokenizePreMergeCommand(input) {
|
|
261
|
+
const tokens = [];
|
|
262
|
+
let current = "";
|
|
263
|
+
let i = 0;
|
|
264
|
+
let quote = "";
|
|
265
|
+
let hasContent = false;
|
|
266
|
+
while (i < input.length) {
|
|
267
|
+
const ch = input[i];
|
|
268
|
+
if (quote) {
|
|
269
|
+
if (ch === quote) {
|
|
270
|
+
quote = "";
|
|
271
|
+
}
|
|
272
|
+
else if (ch === "\\" && quote === '"' && i + 1 < input.length) {
|
|
273
|
+
current += input[i + 1];
|
|
274
|
+
i += 2;
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
else {
|
|
278
|
+
current += ch;
|
|
279
|
+
}
|
|
280
|
+
i++;
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (ch === '"' || ch === "'") {
|
|
284
|
+
quote = ch;
|
|
285
|
+
hasContent = true;
|
|
286
|
+
i++;
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
if (ch === " " || ch === "\t") {
|
|
290
|
+
if (hasContent) {
|
|
291
|
+
tokens.push(current);
|
|
292
|
+
current = "";
|
|
293
|
+
hasContent = false;
|
|
294
|
+
}
|
|
295
|
+
i++;
|
|
296
|
+
continue;
|
|
297
|
+
}
|
|
298
|
+
if (ch === "\\" && i + 1 < input.length) {
|
|
299
|
+
current += input[i + 1];
|
|
300
|
+
i += 2;
|
|
301
|
+
hasContent = true;
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
current += ch;
|
|
305
|
+
hasContent = true;
|
|
306
|
+
i++;
|
|
307
|
+
}
|
|
308
|
+
if (quote) {
|
|
309
|
+
throw new Error(`Unterminated ${quote === '"' ? "double" : "single"} quote in pre-merge command`);
|
|
310
|
+
}
|
|
311
|
+
if (hasContent)
|
|
312
|
+
tokens.push(current);
|
|
313
|
+
return tokens;
|
|
314
|
+
}
|
|
315
|
+
function containsUnquotedShellControl(input) {
|
|
316
|
+
let i = 0;
|
|
317
|
+
let quote = "";
|
|
318
|
+
while (i < input.length) {
|
|
319
|
+
const ch = input[i];
|
|
320
|
+
if (quote) {
|
|
321
|
+
if (ch === quote) {
|
|
322
|
+
quote = "";
|
|
323
|
+
}
|
|
324
|
+
else if (ch === "\\" && quote === '"' && i + 1 < input.length) {
|
|
325
|
+
i += 2;
|
|
326
|
+
continue;
|
|
327
|
+
}
|
|
328
|
+
i++;
|
|
329
|
+
continue;
|
|
330
|
+
}
|
|
331
|
+
if (ch === '"' || ch === "'") {
|
|
332
|
+
quote = ch;
|
|
333
|
+
i++;
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
if (ch === "\\" && i + 1 < input.length) {
|
|
337
|
+
i += 2;
|
|
338
|
+
continue;
|
|
339
|
+
}
|
|
340
|
+
if (ch === ";" || ch === "&" || ch === "|" || ch === "`" || ch === "$" || ch === "<" || ch === ">") {
|
|
341
|
+
return true;
|
|
342
|
+
}
|
|
343
|
+
i++;
|
|
344
|
+
}
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
246
347
|
// ─── Git Helper ────────────────────────────────────────────────────────────
|
|
247
348
|
/**
|
|
248
349
|
* Strip git-svn noise from error messages.
|
|
@@ -601,8 +702,31 @@ export class GitServiceImpl {
|
|
|
601
702
|
return { passed: true, skipped: true };
|
|
602
703
|
}
|
|
603
704
|
}
|
|
705
|
+
// Tokenize and run via execFileSync (no shell). Shell metacharacters in
|
|
706
|
+
// user-supplied prefs.pre_merge_check would otherwise be interpreted as
|
|
707
|
+
// chaining/redirection (e.g. `;`, `&&`, `|`, backticks) — a privesc
|
|
708
|
+
// surface in repos with a checked-in `.gsd/PREFERENCES.md`.
|
|
709
|
+
// (Issue #4980 HIGH-2)
|
|
710
|
+
if (containsUnquotedShellControl(command)) {
|
|
711
|
+
return {
|
|
712
|
+
passed: false,
|
|
713
|
+
skipped: false,
|
|
714
|
+
command,
|
|
715
|
+
error: "pre_merge_check contains shell metacharacters (;, &&, |, $, backticks, redirects). " +
|
|
716
|
+
"Put complex commands in a script file (e.g. './scripts/pre-merge.sh') and reference the script path instead.",
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
const tokens = tokenizePreMergeCommand(command);
|
|
720
|
+
if (tokens.length === 0) {
|
|
721
|
+
return { passed: true, skipped: true };
|
|
722
|
+
}
|
|
604
723
|
try {
|
|
605
|
-
|
|
724
|
+
execFileSync(tokens[0], tokens.slice(1), {
|
|
725
|
+
cwd: this.basePath,
|
|
726
|
+
stdio: "pipe",
|
|
727
|
+
encoding: "utf-8",
|
|
728
|
+
env: GIT_NO_PROMPT_ENV,
|
|
729
|
+
});
|
|
606
730
|
return { passed: true, skipped: false, command };
|
|
607
731
|
}
|
|
608
732
|
catch (err) {
|
|
@@ -135,7 +135,7 @@ function openRawDb(path) {
|
|
|
135
135
|
const Database = providerModule;
|
|
136
136
|
return new Database(path);
|
|
137
137
|
}
|
|
138
|
-
const SCHEMA_VERSION = 22;
|
|
138
|
+
export const SCHEMA_VERSION = 22;
|
|
139
139
|
function indexExists(db, name) {
|
|
140
140
|
return !!db.prepare("SELECT 1 as present FROM sqlite_master WHERE type = 'index' AND name = ?").get(name);
|
|
141
141
|
}
|
|
@@ -2556,6 +2556,9 @@ export function insertReplanHistory(entry) {
|
|
|
2556
2556
|
export function insertAssessment(entry) {
|
|
2557
2557
|
if (!currentDb)
|
|
2558
2558
|
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
2559
|
+
// Idempotent: PRIMARY KEY is `path`, which is deterministic given (milestone_id, scope) per
|
|
2560
|
+
// the artifact-path resolver. Retrying the same reassess-roadmap silently overwrites the row
|
|
2561
|
+
// instead of accumulating duplicates.
|
|
2559
2562
|
currentDb.prepare(`INSERT OR REPLACE INTO assessments (path, milestone_id, slice_id, task_id, status, scope, full_content, created_at)
|
|
2560
2563
|
VALUES (:path, :milestone_id, :slice_id, :task_id, :status, :scope, :full_content, :created_at)`).run({
|
|
2561
2564
|
":path": entry.path,
|
|
@@ -2655,7 +2658,7 @@ function rowToGate(row) {
|
|
|
2655
2658
|
scope: row["scope"],
|
|
2656
2659
|
task_id: row["task_id"] ?? "",
|
|
2657
2660
|
status: row["status"],
|
|
2658
|
-
verdict: row["
|
|
2661
|
+
verdict: row["status"] === "pending" ? null : row["verdict"],
|
|
2659
2662
|
rationale: row["rationale"] || "",
|
|
2660
2663
|
findings: row["findings"] || "",
|
|
2661
2664
|
evaluated_at: row["evaluated_at"] ?? null,
|
|
@@ -2739,7 +2742,7 @@ export function getGateResults(milestoneId, sliceId, scope) {
|
|
|
2739
2742
|
export function markAllGatesOmitted(milestoneId, sliceId) {
|
|
2740
2743
|
if (!currentDb)
|
|
2741
2744
|
return;
|
|
2742
|
-
currentDb.prepare(`UPDATE quality_gates SET status = '
|
|
2745
|
+
currentDb.prepare(`UPDATE quality_gates SET status = 'complete', verdict = 'omitted', evaluated_at = :now
|
|
2743
2746
|
WHERE milestone_id = :mid AND slice_id = :sid AND status = 'pending'`).run({
|
|
2744
2747
|
":mid": milestoneId,
|
|
2745
2748
|
":sid": sliceId,
|
|
@@ -28,7 +28,7 @@ import { ensureGitignore, ensurePreferences, untrackRuntimeFiles } from "./gitig
|
|
|
28
28
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
29
29
|
import { resolveUokFlags } from "./uok/flags.js";
|
|
30
30
|
import { ensurePlanV2Graph, isMissingFinalizedContextResult } from "./uok/plan-v2.js";
|
|
31
|
-
import { detectProjectState } from "./detection.js";
|
|
31
|
+
import { detectProjectState, hasGsdBootstrapArtifacts } from "./detection.js";
|
|
32
32
|
import { showProjectInit, offerMigration } from "./init-wizard.js";
|
|
33
33
|
import { validateDirectory } from "./validate-directory.js";
|
|
34
34
|
import { showConfirm } from "../shared/tui.js";
|
|
@@ -258,6 +258,18 @@ function extractAssistantText(msg) {
|
|
|
258
258
|
}
|
|
259
259
|
/**
|
|
260
260
|
* Return true if the assistant message contains any tool-use block.
|
|
261
|
+
*
|
|
262
|
+
* The canonical pi-ai `AssistantMessage.content` (see packages/pi-ai/src/types.ts)
|
|
263
|
+
* uses `type: "toolCall"` and `type: "serverToolUse"` for tool invocations —
|
|
264
|
+
* every provider (anthropic-direct, claude-code-cli, openai, etc.) normalizes
|
|
265
|
+
* incoming tool blocks into these two shapes before they reach guided-flow.
|
|
266
|
+
*
|
|
267
|
+
* The Anthropic API wire shape `"tool_use"` / `"server_tool_use"` does NOT appear
|
|
268
|
+
* in the internal AssistantMessage — those literals are only used when sending
|
|
269
|
+
* messages back out to the Anthropic API. Matching them here was a latent bug:
|
|
270
|
+
* `hasToolUse` returned `false` for every real tool call, which let the
|
|
271
|
+
* empty-turn nudge fire and pre-empt MCP tools that block on the user
|
|
272
|
+
* (e.g. `ask_user_questions`). See investigation in PR for #4658.
|
|
261
273
|
*/
|
|
262
274
|
function hasToolUse(msg) {
|
|
263
275
|
if (!msg)
|
|
@@ -265,7 +277,9 @@ function hasToolUse(msg) {
|
|
|
265
277
|
const content = msg.content;
|
|
266
278
|
if (!Array.isArray(content))
|
|
267
279
|
return false;
|
|
268
|
-
return content.some((b) => b &&
|
|
280
|
+
return content.some((b) => b &&
|
|
281
|
+
typeof b === "object" &&
|
|
282
|
+
(b.type === "toolCall" || b.type === "serverToolUse"));
|
|
269
283
|
}
|
|
270
284
|
/**
|
|
271
285
|
* #4573 — Detect and recover from the "ready phrase without files" failure mode.
|
|
@@ -1244,9 +1258,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1244
1258
|
// A zombie .gsd/ state (symlink exists but missing PREFERENCES.md and
|
|
1245
1259
|
// milestones/) must trigger the init wizard, not skip it (#2942).
|
|
1246
1260
|
const gsdPath = gsdRoot(basePath);
|
|
1247
|
-
const hasBootstrapArtifacts =
|
|
1248
|
-
&& (existsSync(join(gsdPath, "PREFERENCES.md"))
|
|
1249
|
-
|| existsSync(join(gsdPath, "milestones")));
|
|
1261
|
+
const hasBootstrapArtifacts = hasGsdBootstrapArtifacts(gsdPath);
|
|
1250
1262
|
if (!hasBootstrapArtifacts) {
|
|
1251
1263
|
const detection = detectProjectState(basePath);
|
|
1252
1264
|
// v1 .planning/ detected — offer migration before anything else
|
|
@@ -62,7 +62,9 @@ export function buildMemoryLLMCall(ctx) {
|
|
|
62
62
|
// which returns undefined for OAuth users (Claude Max / Claude Pro).
|
|
63
63
|
// See: https://github.com/gsd-build/gsd-2/issues/2959
|
|
64
64
|
const resolvedKeyPromise = ctx.modelRegistry.getApiKey(selectedModel).catch(() => undefined);
|
|
65
|
-
|
|
65
|
+
// Expose on the returned fn so tests can await resolution deterministically
|
|
66
|
+
// (avoids arbitrary setTimeout polling for an internal microtask).
|
|
67
|
+
const llmCall = async (system, user) => {
|
|
66
68
|
const { completeSimple } = await import('@gsd/pi-ai');
|
|
67
69
|
const resolvedApiKey = await resolvedKeyPromise;
|
|
68
70
|
const result = await completeSimple(selectedModel, {
|
|
@@ -79,6 +81,10 @@ export function buildMemoryLLMCall(ctx) {
|
|
|
79
81
|
.map(c => c.text);
|
|
80
82
|
return textParts.join('');
|
|
81
83
|
};
|
|
84
|
+
// Attach the in-flight API-key resolution so tests (and callers) can
|
|
85
|
+
// `await llmCall.apiKeyReady` rather than relying on setTimeout polling.
|
|
86
|
+
llmCall.apiKeyReady = resolvedKeyPromise;
|
|
87
|
+
return llmCall;
|
|
82
88
|
}
|
|
83
89
|
catch {
|
|
84
90
|
return null;
|