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
|
@@ -29,6 +29,7 @@ import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
|
29
29
|
import { loadEffectiveGSDPreferences, loadGlobalGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
30
30
|
import { showNextAction } from "../shared/tui.js";
|
|
31
31
|
import { ensurePreferencesFile, serializePreferencesToFrontmatter } from "./commands-prefs-wizard.js";
|
|
32
|
+
import { summarizeWorktreeTelemetry, percentile } from "./worktree-telemetry.js";
|
|
32
33
|
// ─── Duplicate Detection ──────────────────────────────────────────────────────
|
|
33
34
|
const DEDUP_PROMPT_SECTION = `
|
|
34
35
|
## Pre-Investigation: Duplicate Check (REQUIRED)
|
|
@@ -214,6 +215,16 @@ export async function buildForensicReport(basePath) {
|
|
|
214
215
|
detectCrash(crashLock, anomalies);
|
|
215
216
|
detectDoctorIssues(doctorIssues, anomalies);
|
|
216
217
|
detectErrorTraces(unitTraces, anomalies);
|
|
218
|
+
// 11b. #4764 — worktree lifecycle telemetry
|
|
219
|
+
let worktreeTelemetry = null;
|
|
220
|
+
try {
|
|
221
|
+
worktreeTelemetry = summarizeWorktreeTelemetry(basePath);
|
|
222
|
+
detectWorktreeOrphans(worktreeTelemetry, anomalies);
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// Telemetry is best-effort — do not let an aggregator failure block the
|
|
226
|
+
// rest of the forensic report.
|
|
227
|
+
}
|
|
217
228
|
detectJournalAnomalies(journalSummary, anomalies);
|
|
218
229
|
return {
|
|
219
230
|
gsdVersion,
|
|
@@ -232,6 +243,7 @@ export async function buildForensicReport(basePath) {
|
|
|
232
243
|
recentUnits,
|
|
233
244
|
journalSummary,
|
|
234
245
|
activityLogMeta,
|
|
246
|
+
worktreeTelemetry,
|
|
235
247
|
};
|
|
236
248
|
}
|
|
237
249
|
// ─── Activity Log Scanner ─────────────────────────────────────────────────────
|
|
@@ -630,6 +642,45 @@ function detectMissingArtifacts(completedKeys, basePath, activeMilestone, anomal
|
|
|
630
642
|
}
|
|
631
643
|
}
|
|
632
644
|
}
|
|
645
|
+
/**
|
|
646
|
+
* #4764 — surface worktree lifecycle and orphan signals in the forensic report.
|
|
647
|
+
*
|
|
648
|
+
* Consumes only the aggregated summary (not raw journal events) to respect
|
|
649
|
+
* the forensics memory-bloat guard in forensics-journal.test.ts — per-event
|
|
650
|
+
* detail stays in the journal itself where the LLM can query it on demand.
|
|
651
|
+
*/
|
|
652
|
+
function detectWorktreeOrphans(summary, anomalies) {
|
|
653
|
+
// 1. Orphan aggregate — severity depends on reason. In-progress orphans are
|
|
654
|
+
// the #4761 consumer-side signal (live work sitting on an unmerged branch).
|
|
655
|
+
for (const [reason, count] of Object.entries(summary.orphansByReason)) {
|
|
656
|
+
if (count <= 0)
|
|
657
|
+
continue;
|
|
658
|
+
const severity = reason === "in-progress-unmerged" ? "warning" : "info";
|
|
659
|
+
anomalies.push({
|
|
660
|
+
type: "worktree-orphan",
|
|
661
|
+
severity,
|
|
662
|
+
summary: `${count} worktree orphan(s) detected (${reason})`,
|
|
663
|
+
details: reason === "in-progress-unmerged"
|
|
664
|
+
? "Auto-mode exited without completing a milestone; live work sits on an unmerged milestone branch. Run `/gsd auto` to resume, or merge manually."
|
|
665
|
+
: reason === "complete-unmerged"
|
|
666
|
+
? "A completed milestone's branch was never merged back to main. Run `/gsd health --fix` to resolve."
|
|
667
|
+
: `Reason: ${reason}.`,
|
|
668
|
+
});
|
|
669
|
+
}
|
|
670
|
+
// 2. Auto-exit producer signal — #4761's upstream cause.
|
|
671
|
+
if (summary.exitsWithUnmergedWork > 0) {
|
|
672
|
+
const reasonBreakdown = Object.entries(summary.exitsByReason)
|
|
673
|
+
.filter(([, n]) => n > 0)
|
|
674
|
+
.map(([r, n]) => `${r}=${n}`)
|
|
675
|
+
.join(", ");
|
|
676
|
+
anomalies.push({
|
|
677
|
+
type: "worktree-unmerged-exit",
|
|
678
|
+
severity: "warning",
|
|
679
|
+
summary: `${summary.exitsWithUnmergedWork} auto-exit(s) left milestone work unmerged`,
|
|
680
|
+
details: `Exit reasons: ${reasonBreakdown || "(none)"} · Producer-side signal for #4761-class orphans. Inspect .gsd/journal/*.jsonl with eventType:"auto-exit" for per-exit detail.`,
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
}
|
|
633
684
|
function detectCrash(crashLock, anomalies) {
|
|
634
685
|
if (!crashLock)
|
|
635
686
|
return;
|
|
@@ -808,6 +859,39 @@ function saveForensicReport(basePath, report, problemDescription) {
|
|
|
808
859
|
sections.push(`- Newest: ${meta.newestFile}`);
|
|
809
860
|
sections.push(``);
|
|
810
861
|
}
|
|
862
|
+
// #4764 — Worktree telemetry summary
|
|
863
|
+
if (report.worktreeTelemetry) {
|
|
864
|
+
const t = report.worktreeTelemetry;
|
|
865
|
+
const p50 = percentile(t.mergeDurationsMs, 0.5);
|
|
866
|
+
const p95 = percentile(t.mergeDurationsMs, 0.95);
|
|
867
|
+
sections.push(`## Worktree Telemetry`, ``);
|
|
868
|
+
sections.push(`- Worktrees created: ${t.worktreesCreated}`);
|
|
869
|
+
sections.push(`- Worktrees merged: ${t.worktreesMerged}`);
|
|
870
|
+
sections.push(`- Orphans detected: ${t.orphansDetected}`);
|
|
871
|
+
if (t.orphansDetected > 0) {
|
|
872
|
+
const breakdown = Object.entries(t.orphansByReason)
|
|
873
|
+
.map(([r, n]) => `${r}=${n}`).join(", ");
|
|
874
|
+
sections.push(` - By reason: ${breakdown}`);
|
|
875
|
+
}
|
|
876
|
+
sections.push(`- Merge conflicts: ${t.mergeConflicts}`);
|
|
877
|
+
if (t.mergeDurationsMs.length > 0) {
|
|
878
|
+
sections.push(`- Merge duration p50 / p95: ${p50 ?? "-"} / ${p95 ?? "-"} ms (n=${t.mergeDurationsMs.length})`);
|
|
879
|
+
}
|
|
880
|
+
sections.push(`- Auto-exits leaving unmerged work: ${t.exitsWithUnmergedWork}`);
|
|
881
|
+
if (Object.keys(t.exitsByReason).length > 0) {
|
|
882
|
+
const breakdown = Object.entries(t.exitsByReason)
|
|
883
|
+
.sort((a, b) => b[1] - a[1])
|
|
884
|
+
.map(([r, n]) => `${r}=${n}`).join(", ");
|
|
885
|
+
sections.push(` - Exit reasons: ${breakdown}`);
|
|
886
|
+
}
|
|
887
|
+
sections.push(`- Canonical-root redirects (#4761 fix fired): ${t.canonicalRedirects}`);
|
|
888
|
+
// #4765 slice-cadence counters
|
|
889
|
+
if (t.slicesMerged + t.sliceMergeConflicts + t.milestoneResquashes > 0) {
|
|
890
|
+
sections.push(`- Slices merged: ${t.slicesMerged} · Slice merge conflicts: ${t.sliceMergeConflicts}`);
|
|
891
|
+
sections.push(`- Milestone re-squashes: ${t.milestoneResquashes}`);
|
|
892
|
+
}
|
|
893
|
+
sections.push(``);
|
|
894
|
+
}
|
|
811
895
|
// Journal summary
|
|
812
896
|
if (report.journalSummary) {
|
|
813
897
|
const js = report.journalSummary;
|
|
@@ -940,6 +1024,28 @@ function formatReportForPrompt(report) {
|
|
|
940
1024
|
sections.push(`- Total duration: ${formatDuration(totals.duration)}`);
|
|
941
1025
|
sections.push("");
|
|
942
1026
|
}
|
|
1027
|
+
// #4764 — worktree telemetry (compact prompt form)
|
|
1028
|
+
if (report.worktreeTelemetry) {
|
|
1029
|
+
const t = report.worktreeTelemetry;
|
|
1030
|
+
const hasSignal = t.worktreesCreated + t.worktreesMerged + t.orphansDetected +
|
|
1031
|
+
t.exitsWithUnmergedWork + t.canonicalRedirects +
|
|
1032
|
+
t.slicesMerged + t.milestoneResquashes > 0;
|
|
1033
|
+
if (hasSignal) {
|
|
1034
|
+
sections.push("### Worktree Telemetry");
|
|
1035
|
+
sections.push(`- Created: ${t.worktreesCreated} · Merged: ${t.worktreesMerged} · Conflicts: ${t.mergeConflicts}`);
|
|
1036
|
+
sections.push(`- Orphans: ${t.orphansDetected} · Unmerged exits: ${t.exitsWithUnmergedWork} · Redirects (#4761): ${t.canonicalRedirects}`);
|
|
1037
|
+
if (t.orphansDetected > 0) {
|
|
1038
|
+
const breakdown = Object.entries(t.orphansByReason)
|
|
1039
|
+
.map(([r, n]) => `${r}=${n}`).join(", ");
|
|
1040
|
+
sections.push(`- Orphan reasons: ${breakdown}`);
|
|
1041
|
+
}
|
|
1042
|
+
// #4765 — slice-cadence counters (only shown when the feature was exercised)
|
|
1043
|
+
if (t.slicesMerged + t.sliceMergeConflicts + t.milestoneResquashes > 0) {
|
|
1044
|
+
sections.push(`- Slices merged: ${t.slicesMerged} · Slice conflicts: ${t.sliceMergeConflicts} · Re-squashes: ${t.milestoneResquashes}`);
|
|
1045
|
+
}
|
|
1046
|
+
sections.push("");
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
943
1049
|
// Activity log metadata
|
|
944
1050
|
if (report.activityLogMeta) {
|
|
945
1051
|
const meta = report.activityLogMeta;
|
|
@@ -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,
|
|
@@ -10,7 +10,7 @@ import { loadFile, saveFile } from "./files.js";
|
|
|
10
10
|
import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
|
|
11
11
|
import { parseRoadmapSlices } from "./roadmap-slices.js";
|
|
12
12
|
import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
13
|
-
import { buildSkillActivationBlock } from "./auto-prompts.js";
|
|
13
|
+
import { buildDiscussMilestonePrompt, buildSkillActivationBlock } from "./auto-prompts.js";
|
|
14
14
|
import { deriveState } from "./state.js";
|
|
15
15
|
import { invalidateAllCaches } from "./cache.js";
|
|
16
16
|
import { startAutoDetached } from "./auto.js";
|
|
@@ -27,8 +27,8 @@ import { isInheritedRepo } from "./repo-identity.js";
|
|
|
27
27
|
import { ensureGitignore, ensurePreferences, untrackRuntimeFiles } from "./gitignore.js";
|
|
28
28
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
29
29
|
import { resolveUokFlags } from "./uok/flags.js";
|
|
30
|
-
import { ensurePlanV2Graph } from "./uok/plan-v2.js";
|
|
31
|
-
import { detectProjectState } from "./detection.js";
|
|
30
|
+
import { ensurePlanV2Graph, isMissingFinalizedContextResult } from "./uok/plan-v2.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";
|
|
@@ -65,14 +65,17 @@ function runPlanV2Gate(ctx, basePath, state) {
|
|
|
65
65
|
const prefs = loadEffectiveGSDPreferences()?.preferences;
|
|
66
66
|
const uokFlags = resolveUokFlags(prefs);
|
|
67
67
|
if (!uokFlags.planV2 || !needsPlanV2Gate(state))
|
|
68
|
-
return
|
|
68
|
+
return "pass";
|
|
69
69
|
const compiled = ensurePlanV2Graph(basePath, state);
|
|
70
70
|
if (!compiled.ok) {
|
|
71
|
+
if (isMissingFinalizedContextResult(compiled)) {
|
|
72
|
+
return "recover-missing-context";
|
|
73
|
+
}
|
|
71
74
|
const reason = compiled.reason ?? "plan-v2 compilation failed";
|
|
72
75
|
ctx.ui.notify(`Plan gate failed-closed: ${reason}. Complete plan/discuss artifacts before execution.\n\nIf this keeps happening, try: /gsd doctor heal`, "error");
|
|
73
|
-
return
|
|
76
|
+
return "block";
|
|
74
77
|
}
|
|
75
|
-
return
|
|
78
|
+
return "pass";
|
|
76
79
|
}
|
|
77
80
|
// ─── Commit Instruction Helpers ──────────────────────────────────────────────
|
|
78
81
|
/** Build commit instruction for planning prompts. .gsd/ is managed externally and always gitignored. */
|
|
@@ -255,6 +258,18 @@ function extractAssistantText(msg) {
|
|
|
255
258
|
}
|
|
256
259
|
/**
|
|
257
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.
|
|
258
273
|
*/
|
|
259
274
|
function hasToolUse(msg) {
|
|
260
275
|
if (!msg)
|
|
@@ -262,7 +277,9 @@ function hasToolUse(msg) {
|
|
|
262
277
|
const content = msg.content;
|
|
263
278
|
if (!Array.isArray(content))
|
|
264
279
|
return false;
|
|
265
|
-
return content.some((b) => b &&
|
|
280
|
+
return content.some((b) => b &&
|
|
281
|
+
typeof b === "object" &&
|
|
282
|
+
(b.type === "toolCall" || b.type === "serverToolUse"));
|
|
266
283
|
}
|
|
267
284
|
/**
|
|
268
285
|
* #4573 — Detect and recover from the "ready phrase without files" failure mode.
|
|
@@ -669,8 +686,13 @@ export async function showHeadlessMilestoneCreation(ctx, pi, basePath, seedConte
|
|
|
669
686
|
const prompt = buildHeadlessDiscussPrompt(nextId, seedContext, basePath);
|
|
670
687
|
// Set pending auto start (auto-mode triggers on "Milestone X ready." via checkAutoStartAfterDiscuss)
|
|
671
688
|
pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, createdAt: Date.now() });
|
|
672
|
-
// Dispatch
|
|
673
|
-
|
|
689
|
+
// Dispatch as discuss-milestone. The LLM writes PROJECT.md, REQUIREMENTS.md,
|
|
690
|
+
// and CONTEXT.md, then calls gsd_plan_milestone — this is semantically the
|
|
691
|
+
// discuss path, just non-interactive. Using "plan-milestone" here caused
|
|
692
|
+
// model/tool routing to skip discuss-flow tool scoping and
|
|
693
|
+
// `checkAutoStartAfterDiscuss` guardrails that rely on the
|
|
694
|
+
// "discuss-"-prefixed unitType.
|
|
695
|
+
await dispatchWorkflow(pi, prompt, "gsd-run", ctx, "discuss-milestone");
|
|
674
696
|
}
|
|
675
697
|
// ─── Discuss Flow ─────────────────────────────────────────────────────────────
|
|
676
698
|
/**
|
|
@@ -1236,9 +1258,7 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1236
1258
|
// A zombie .gsd/ state (symlink exists but missing PREFERENCES.md and
|
|
1237
1259
|
// milestones/) must trigger the init wizard, not skip it (#2942).
|
|
1238
1260
|
const gsdPath = gsdRoot(basePath);
|
|
1239
|
-
const hasBootstrapArtifacts =
|
|
1240
|
-
&& (existsSync(join(gsdPath, "PREFERENCES.md"))
|
|
1241
|
-
|| existsSync(join(gsdPath, "milestones")));
|
|
1261
|
+
const hasBootstrapArtifacts = hasGsdBootstrapArtifacts(gsdPath);
|
|
1242
1262
|
if (!hasBootstrapArtifacts) {
|
|
1243
1263
|
const detection = detectProjectState(basePath);
|
|
1244
1264
|
// v1 .planning/ detected — offer migration before anything else
|
|
@@ -1322,7 +1342,8 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1322
1342
|
catch (err) {
|
|
1323
1343
|
logWarning("guided", `STATE.md rebuild failed: ${err.message}`);
|
|
1324
1344
|
}
|
|
1325
|
-
|
|
1345
|
+
const planV2GateDecision = runPlanV2Gate(ctx, basePath, state);
|
|
1346
|
+
if (planV2GateDecision === "block")
|
|
1326
1347
|
return;
|
|
1327
1348
|
if (!state.activeMilestone?.id) {
|
|
1328
1349
|
// Guard: if a discuss session is already in flight, don't re-inject the prompt.
|
|
@@ -1397,6 +1418,11 @@ export async function showSmartEntry(ctx, pi, basePath, options) {
|
|
|
1397
1418
|
}
|
|
1398
1419
|
const milestoneId = state.activeMilestone.id;
|
|
1399
1420
|
const milestoneTitle = state.activeMilestone.title;
|
|
1421
|
+
if (planV2GateDecision === "recover-missing-context") {
|
|
1422
|
+
pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId, step: stepMode, createdAt: Date.now() });
|
|
1423
|
+
await dispatchWorkflow(pi, await buildDiscussMilestonePrompt(milestoneId, milestoneTitle, basePath, getStructuredQuestionsAvailability(pi, ctx)), "gsd-discuss", ctx, "discuss-milestone");
|
|
1424
|
+
return;
|
|
1425
|
+
}
|
|
1400
1426
|
// ── All milestones complete → New milestone ──────────────────────────
|
|
1401
1427
|
if (state.phase === "complete") {
|
|
1402
1428
|
const choice = await showNextAction(ctx, {
|
|
@@ -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;
|