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
|
@@ -35,11 +35,12 @@ import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
|
35
35
|
import { loadEffectiveGSDPreferences, loadGlobalGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
|
36
36
|
import { showNextAction } from "../shared/tui.js";
|
|
37
37
|
import { ensurePreferencesFile, serializePreferencesToFrontmatter } from "./commands-prefs-wizard.js";
|
|
38
|
+
import { summarizeWorktreeTelemetry, percentile, type WorktreeTelemetrySummary } from "./worktree-telemetry.js";
|
|
38
39
|
|
|
39
40
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
40
41
|
|
|
41
42
|
export interface ForensicAnomaly {
|
|
42
|
-
type: "stuck-loop" | "cost-spike" | "timeout" | "missing-artifact" | "crash" | "doctor-issue" | "error-trace" | "journal-stuck" | "journal-guard-block" | "journal-rapid-iterations" | "journal-worktree-failure";
|
|
43
|
+
type: "stuck-loop" | "cost-spike" | "timeout" | "missing-artifact" | "crash" | "doctor-issue" | "error-trace" | "journal-stuck" | "journal-guard-block" | "journal-rapid-iterations" | "journal-worktree-failure" | "worktree-orphan" | "worktree-unmerged-exit";
|
|
43
44
|
severity: "info" | "warning" | "error";
|
|
44
45
|
unitType?: string;
|
|
45
46
|
unitId?: string;
|
|
@@ -113,6 +114,8 @@ interface ForensicReport {
|
|
|
113
114
|
recentUnits: { type: string; id: string; cost: number; duration: number; model: string; finishedAt: number }[];
|
|
114
115
|
journalSummary: JournalSummary | null;
|
|
115
116
|
activityLogMeta: ActivityLogMeta | null;
|
|
117
|
+
/** #4764 — worktree lifespan / divergence telemetry aggregates. */
|
|
118
|
+
worktreeTelemetry: WorktreeTelemetrySummary | null;
|
|
116
119
|
}
|
|
117
120
|
|
|
118
121
|
// ─── Duplicate Detection ──────────────────────────────────────────────────────
|
|
@@ -337,6 +340,16 @@ export async function buildForensicReport(basePath: string): Promise<ForensicRep
|
|
|
337
340
|
detectCrash(crashLock, anomalies);
|
|
338
341
|
detectDoctorIssues(doctorIssues, anomalies);
|
|
339
342
|
detectErrorTraces(unitTraces, anomalies);
|
|
343
|
+
|
|
344
|
+
// 11b. #4764 — worktree lifecycle telemetry
|
|
345
|
+
let worktreeTelemetry: WorktreeTelemetrySummary | null = null;
|
|
346
|
+
try {
|
|
347
|
+
worktreeTelemetry = summarizeWorktreeTelemetry(basePath);
|
|
348
|
+
detectWorktreeOrphans(worktreeTelemetry, anomalies);
|
|
349
|
+
} catch {
|
|
350
|
+
// Telemetry is best-effort — do not let an aggregator failure block the
|
|
351
|
+
// rest of the forensic report.
|
|
352
|
+
}
|
|
340
353
|
detectJournalAnomalies(journalSummary, anomalies);
|
|
341
354
|
|
|
342
355
|
return {
|
|
@@ -356,6 +369,7 @@ export async function buildForensicReport(basePath: string): Promise<ForensicRep
|
|
|
356
369
|
recentUnits,
|
|
357
370
|
journalSummary,
|
|
358
371
|
activityLogMeta,
|
|
372
|
+
worktreeTelemetry,
|
|
359
373
|
};
|
|
360
374
|
}
|
|
361
375
|
|
|
@@ -783,6 +797,51 @@ function detectMissingArtifacts(completedKeys: string[], basePath: string, activ
|
|
|
783
797
|
}
|
|
784
798
|
}
|
|
785
799
|
|
|
800
|
+
/**
|
|
801
|
+
* #4764 — surface worktree lifecycle and orphan signals in the forensic report.
|
|
802
|
+
*
|
|
803
|
+
* Consumes only the aggregated summary (not raw journal events) to respect
|
|
804
|
+
* the forensics memory-bloat guard in forensics-journal.test.ts — per-event
|
|
805
|
+
* detail stays in the journal itself where the LLM can query it on demand.
|
|
806
|
+
*/
|
|
807
|
+
function detectWorktreeOrphans(
|
|
808
|
+
summary: WorktreeTelemetrySummary,
|
|
809
|
+
anomalies: ForensicAnomaly[],
|
|
810
|
+
): void {
|
|
811
|
+
// 1. Orphan aggregate — severity depends on reason. In-progress orphans are
|
|
812
|
+
// the #4761 consumer-side signal (live work sitting on an unmerged branch).
|
|
813
|
+
for (const [reason, count] of Object.entries(summary.orphansByReason)) {
|
|
814
|
+
if (count <= 0) continue;
|
|
815
|
+
const severity: ForensicAnomaly["severity"] =
|
|
816
|
+
reason === "in-progress-unmerged" ? "warning" : "info";
|
|
817
|
+
anomalies.push({
|
|
818
|
+
type: "worktree-orphan",
|
|
819
|
+
severity,
|
|
820
|
+
summary: `${count} worktree orphan(s) detected (${reason})`,
|
|
821
|
+
details:
|
|
822
|
+
reason === "in-progress-unmerged"
|
|
823
|
+
? "Auto-mode exited without completing a milestone; live work sits on an unmerged milestone branch. Run `/gsd auto` to resume, or merge manually."
|
|
824
|
+
: reason === "complete-unmerged"
|
|
825
|
+
? "A completed milestone's branch was never merged back to main. Run `/gsd health --fix` to resolve."
|
|
826
|
+
: `Reason: ${reason}.`,
|
|
827
|
+
});
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
// 2. Auto-exit producer signal — #4761's upstream cause.
|
|
831
|
+
if (summary.exitsWithUnmergedWork > 0) {
|
|
832
|
+
const reasonBreakdown = Object.entries(summary.exitsByReason)
|
|
833
|
+
.filter(([, n]) => n > 0)
|
|
834
|
+
.map(([r, n]) => `${r}=${n}`)
|
|
835
|
+
.join(", ");
|
|
836
|
+
anomalies.push({
|
|
837
|
+
type: "worktree-unmerged-exit",
|
|
838
|
+
severity: "warning",
|
|
839
|
+
summary: `${summary.exitsWithUnmergedWork} auto-exit(s) left milestone work unmerged`,
|
|
840
|
+
details: `Exit reasons: ${reasonBreakdown || "(none)"} · Producer-side signal for #4761-class orphans. Inspect .gsd/journal/*.jsonl with eventType:"auto-exit" for per-exit detail.`,
|
|
841
|
+
});
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
786
845
|
function detectCrash(crashLock: LockData | null, anomalies: ForensicAnomaly[]): void {
|
|
787
846
|
if (!crashLock) return;
|
|
788
847
|
if (isLockProcessAlive(crashLock)) return; // Process still running, not a crash
|
|
@@ -972,6 +1031,40 @@ function saveForensicReport(basePath: string, report: ForensicReport, problemDes
|
|
|
972
1031
|
sections.push(``);
|
|
973
1032
|
}
|
|
974
1033
|
|
|
1034
|
+
// #4764 — Worktree telemetry summary
|
|
1035
|
+
if (report.worktreeTelemetry) {
|
|
1036
|
+
const t = report.worktreeTelemetry;
|
|
1037
|
+
const p50 = percentile(t.mergeDurationsMs, 0.5);
|
|
1038
|
+
const p95 = percentile(t.mergeDurationsMs, 0.95);
|
|
1039
|
+
sections.push(`## Worktree Telemetry`, ``);
|
|
1040
|
+
sections.push(`- Worktrees created: ${t.worktreesCreated}`);
|
|
1041
|
+
sections.push(`- Worktrees merged: ${t.worktreesMerged}`);
|
|
1042
|
+
sections.push(`- Orphans detected: ${t.orphansDetected}`);
|
|
1043
|
+
if (t.orphansDetected > 0) {
|
|
1044
|
+
const breakdown = Object.entries(t.orphansByReason)
|
|
1045
|
+
.map(([r, n]) => `${r}=${n}`).join(", ");
|
|
1046
|
+
sections.push(` - By reason: ${breakdown}`);
|
|
1047
|
+
}
|
|
1048
|
+
sections.push(`- Merge conflicts: ${t.mergeConflicts}`);
|
|
1049
|
+
if (t.mergeDurationsMs.length > 0) {
|
|
1050
|
+
sections.push(`- Merge duration p50 / p95: ${p50 ?? "-"} / ${p95 ?? "-"} ms (n=${t.mergeDurationsMs.length})`);
|
|
1051
|
+
}
|
|
1052
|
+
sections.push(`- Auto-exits leaving unmerged work: ${t.exitsWithUnmergedWork}`);
|
|
1053
|
+
if (Object.keys(t.exitsByReason).length > 0) {
|
|
1054
|
+
const breakdown = Object.entries(t.exitsByReason)
|
|
1055
|
+
.sort((a, b) => b[1] - a[1])
|
|
1056
|
+
.map(([r, n]) => `${r}=${n}`).join(", ");
|
|
1057
|
+
sections.push(` - Exit reasons: ${breakdown}`);
|
|
1058
|
+
}
|
|
1059
|
+
sections.push(`- Canonical-root redirects (#4761 fix fired): ${t.canonicalRedirects}`);
|
|
1060
|
+
// #4765 slice-cadence counters
|
|
1061
|
+
if (t.slicesMerged + t.sliceMergeConflicts + t.milestoneResquashes > 0) {
|
|
1062
|
+
sections.push(`- Slices merged: ${t.slicesMerged} · Slice merge conflicts: ${t.sliceMergeConflicts}`);
|
|
1063
|
+
sections.push(`- Milestone re-squashes: ${t.milestoneResquashes}`);
|
|
1064
|
+
}
|
|
1065
|
+
sections.push(``);
|
|
1066
|
+
}
|
|
1067
|
+
|
|
975
1068
|
// Journal summary
|
|
976
1069
|
if (report.journalSummary) {
|
|
977
1070
|
const js = report.journalSummary;
|
|
@@ -1117,6 +1210,30 @@ function formatReportForPrompt(report: ForensicReport): string {
|
|
|
1117
1210
|
sections.push("");
|
|
1118
1211
|
}
|
|
1119
1212
|
|
|
1213
|
+
// #4764 — worktree telemetry (compact prompt form)
|
|
1214
|
+
if (report.worktreeTelemetry) {
|
|
1215
|
+
const t = report.worktreeTelemetry;
|
|
1216
|
+
const hasSignal =
|
|
1217
|
+
t.worktreesCreated + t.worktreesMerged + t.orphansDetected +
|
|
1218
|
+
t.exitsWithUnmergedWork + t.canonicalRedirects +
|
|
1219
|
+
t.slicesMerged + t.milestoneResquashes > 0;
|
|
1220
|
+
if (hasSignal) {
|
|
1221
|
+
sections.push("### Worktree Telemetry");
|
|
1222
|
+
sections.push(`- Created: ${t.worktreesCreated} · Merged: ${t.worktreesMerged} · Conflicts: ${t.mergeConflicts}`);
|
|
1223
|
+
sections.push(`- Orphans: ${t.orphansDetected} · Unmerged exits: ${t.exitsWithUnmergedWork} · Redirects (#4761): ${t.canonicalRedirects}`);
|
|
1224
|
+
if (t.orphansDetected > 0) {
|
|
1225
|
+
const breakdown = Object.entries(t.orphansByReason)
|
|
1226
|
+
.map(([r, n]) => `${r}=${n}`).join(", ");
|
|
1227
|
+
sections.push(`- Orphan reasons: ${breakdown}`);
|
|
1228
|
+
}
|
|
1229
|
+
// #4765 — slice-cadence counters (only shown when the feature was exercised)
|
|
1230
|
+
if (t.slicesMerged + t.sliceMergeConflicts + t.milestoneResquashes > 0) {
|
|
1231
|
+
sections.push(`- Slices merged: ${t.slicesMerged} · Slice conflicts: ${t.sliceMergeConflicts} · Re-squashes: ${t.milestoneResquashes}`);
|
|
1232
|
+
}
|
|
1233
|
+
sections.push("");
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1120
1237
|
// Activity log metadata
|
|
1121
1238
|
if (report.activityLogMeta) {
|
|
1122
1239
|
const meta = report.activityLogMeta;
|
|
@@ -60,9 +60,9 @@ export const GATE_REGISTRY = {
|
|
|
60
60
|
id: "Q4",
|
|
61
61
|
scope: "slice",
|
|
62
62
|
ownerTurn: "gate-evaluate",
|
|
63
|
-
question: "
|
|
63
|
+
question: "Which existing requirements (R-IDs) does this slice touch, and which must be re-tested?",
|
|
64
64
|
guidance: [
|
|
65
|
-
"List
|
|
65
|
+
"List the R-IDs (e.g. R001, R003) touched by this slice; see the milestone requirements artifact at .gsd/milestones/<id>/REQUIREMENTS.md.",
|
|
66
66
|
"Identify what must be re-tested after shipping.",
|
|
67
67
|
"Flag decisions that should be revisited given the new scope.",
|
|
68
68
|
"If no existing requirements are affected, return verdict 'omitted'.",
|
|
@@ -2,9 +2,38 @@
|
|
|
2
2
|
* Shared git constants used across git-service and native-git-bridge.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Parent process env vars that, if leaked into a git child process, can
|
|
7
|
+
* silently redirect every operation to a different repo or index.
|
|
8
|
+
*
|
|
9
|
+
* Stripped from GIT_NO_PROMPT_ENV so a GSD invoked from inside a git hook,
|
|
10
|
+
* a different worktree's terminal, or any context that pre-set these vars
|
|
11
|
+
* cannot redirect GSD's git operations to the wrong target.
|
|
12
|
+
* (Issue #4980 NEW-1)
|
|
13
|
+
*/
|
|
14
|
+
const LEAKING_GIT_ENV_VARS = [
|
|
15
|
+
"GIT_DIR",
|
|
16
|
+
"GIT_WORK_TREE",
|
|
17
|
+
"GIT_INDEX_FILE",
|
|
18
|
+
"GIT_OBJECT_DIRECTORY",
|
|
19
|
+
"GIT_ALTERNATE_OBJECT_DIRECTORIES",
|
|
20
|
+
"GIT_COMMON_DIR",
|
|
21
|
+
"GIT_NAMESPACE",
|
|
22
|
+
] as const;
|
|
23
|
+
|
|
24
|
+
function buildSafeParentEnv(): NodeJS.ProcessEnv {
|
|
25
|
+
const safe: NodeJS.ProcessEnv = {};
|
|
26
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
27
|
+
if (!LEAKING_GIT_ENV_VARS.includes(k as (typeof LEAKING_GIT_ENV_VARS)[number])) {
|
|
28
|
+
safe[k] = v;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return safe;
|
|
32
|
+
}
|
|
33
|
+
|
|
5
34
|
/** Env overlay that suppresses interactive git credential prompts and git-svn noise. */
|
|
6
35
|
export const GIT_NO_PROMPT_ENV = {
|
|
7
|
-
...
|
|
36
|
+
...buildSafeParentEnv(),
|
|
8
37
|
GIT_TERMINAL_PROMPT: "0",
|
|
9
38
|
GIT_ASKPASS: "",
|
|
10
39
|
GIT_SVN_ID: "",
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
* user-friendly messages suggesting `/gsd doctor`.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import { execFileSync } from "node:child_process";
|
|
13
14
|
import { existsSync, unlinkSync } from "node:fs";
|
|
14
15
|
import { join } from "node:path";
|
|
15
16
|
import { MergeConflictError } from "./git-service.js";
|
|
@@ -24,6 +25,18 @@ export interface AbortAndResetResult {
|
|
|
24
25
|
cleaned: string[];
|
|
25
26
|
}
|
|
26
27
|
|
|
28
|
+
function hasWorkingTreeChanges(cwd: string): boolean {
|
|
29
|
+
try {
|
|
30
|
+
return execFileSync("git", ["status", "--porcelain"], {
|
|
31
|
+
cwd,
|
|
32
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
33
|
+
encoding: "utf-8",
|
|
34
|
+
}).trim().length > 0;
|
|
35
|
+
} catch {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
27
40
|
/**
|
|
28
41
|
* Detect and clean up leftover merge/rebase state, then hard-reset.
|
|
29
42
|
*
|
|
@@ -70,6 +83,24 @@ export function abortAndReset(cwd: string): AbortAndResetResult {
|
|
|
70
83
|
}
|
|
71
84
|
}
|
|
72
85
|
|
|
86
|
+
// Preserve any staged or untracked user work before the hard reset.
|
|
87
|
+
// Reset --hard discards staged changes (reflog only covers committed
|
|
88
|
+
// state), so a labeled stash gives the user a recovery handle if their
|
|
89
|
+
// in-flight inspection work would otherwise be silently lost.
|
|
90
|
+
// (Issue #4980 HIGH-5)
|
|
91
|
+
if (hasWorkingTreeChanges(cwd)) {
|
|
92
|
+
try {
|
|
93
|
+
execFileSync(
|
|
94
|
+
"git",
|
|
95
|
+
["stash", "push", "--include-untracked", "-m", `gsd: pre-self-heal-reset ${new Date().toISOString()}`],
|
|
96
|
+
{ cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
|
|
97
|
+
);
|
|
98
|
+
cleaned.push("stashed working tree before reset");
|
|
99
|
+
} catch {
|
|
100
|
+
/* nothing to stash, or stash refused (e.g. unresolved conflicts) — proceed */
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
73
104
|
// Always hard-reset to HEAD
|
|
74
105
|
try {
|
|
75
106
|
nativeResetHard(cwd);
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* paths, commit type inference, and the runGit shell helper.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { execFileSync
|
|
11
|
+
import { execFileSync } from "node:child_process";
|
|
12
12
|
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
13
13
|
import { join } from "node:path";
|
|
14
14
|
import { gsdRoot } from "./paths.js";
|
|
@@ -85,6 +85,22 @@ export interface GitPreferences {
|
|
|
85
85
|
* for forensic inspection.
|
|
86
86
|
*/
|
|
87
87
|
absorb_snapshot_commits?: boolean;
|
|
88
|
+
/** #4765 — when to collapse worktree commits back to main.
|
|
89
|
+
* - "milestone" (default): existing behavior — squash-merge happens once
|
|
90
|
+
* at milestone completion or transition.
|
|
91
|
+
* - "slice": squash-merge each slice's commits to main as soon as the
|
|
92
|
+
* slice passes validation. Shrinks the orphan window from
|
|
93
|
+
* milestone-size to slice-size and surfaces merge conflicts per slice
|
|
94
|
+
* rather than all at once at milestone end.
|
|
95
|
+
*/
|
|
96
|
+
collapse_cadence?: "milestone" | "slice";
|
|
97
|
+
/** #4765 — when `collapse_cadence: "slice"`, optionally re-squash the per-
|
|
98
|
+
* slice commits on main into one milestone commit at milestone completion.
|
|
99
|
+
* Preserves the "one commit per milestone in main" history shape that
|
|
100
|
+
* `collapse_cadence: "milestone"` produces today.
|
|
101
|
+
* Default: true when collapse_cadence is "slice", ignored otherwise.
|
|
102
|
+
*/
|
|
103
|
+
milestone_resquash?: boolean;
|
|
88
104
|
}
|
|
89
105
|
|
|
90
106
|
export const VALID_BRANCH_NAME = /^[a-zA-Z0-9_\-\/.]+$/;
|
|
@@ -393,6 +409,111 @@ export function resolveMilestoneIntegrationBranch(
|
|
|
393
409
|
};
|
|
394
410
|
}
|
|
395
411
|
|
|
412
|
+
// ─── Pre-Merge Command Tokenizer ──────────────────────────────────────────
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Tokenize a user-supplied pre-merge command string into argv form, with
|
|
416
|
+
* minimal support for double- and single-quoted strings. Designed to be
|
|
417
|
+
* sufficient for typical commands ("npm test", `npm run lint:ci`,
|
|
418
|
+
* `pnpm run tsc --noEmit`) without spawning a shell.
|
|
419
|
+
*
|
|
420
|
+
* Returns [] when the input is empty or whitespace-only.
|
|
421
|
+
* Throws when quoting is malformed.
|
|
422
|
+
*
|
|
423
|
+
* Used by GitServiceImpl.runPreMergeCheck to eliminate the shell-injection
|
|
424
|
+
* surface that running an arbitrary user string through a shell would create.
|
|
425
|
+
* (Issue #4980 HIGH-2)
|
|
426
|
+
*/
|
|
427
|
+
export function tokenizePreMergeCommand(input: string): string[] {
|
|
428
|
+
const tokens: string[] = [];
|
|
429
|
+
let current = "";
|
|
430
|
+
let i = 0;
|
|
431
|
+
let quote: "" | "'" | '"' = "";
|
|
432
|
+
let hasContent = false;
|
|
433
|
+
|
|
434
|
+
while (i < input.length) {
|
|
435
|
+
const ch = input[i]!;
|
|
436
|
+
if (quote) {
|
|
437
|
+
if (ch === quote) {
|
|
438
|
+
quote = "";
|
|
439
|
+
} else if (ch === "\\" && quote === '"' && i + 1 < input.length) {
|
|
440
|
+
current += input[i + 1];
|
|
441
|
+
i += 2;
|
|
442
|
+
continue;
|
|
443
|
+
} else {
|
|
444
|
+
current += ch;
|
|
445
|
+
}
|
|
446
|
+
i++;
|
|
447
|
+
continue;
|
|
448
|
+
}
|
|
449
|
+
if (ch === '"' || ch === "'") {
|
|
450
|
+
quote = ch;
|
|
451
|
+
hasContent = true;
|
|
452
|
+
i++;
|
|
453
|
+
continue;
|
|
454
|
+
}
|
|
455
|
+
if (ch === " " || ch === "\t") {
|
|
456
|
+
if (hasContent) {
|
|
457
|
+
tokens.push(current);
|
|
458
|
+
current = "";
|
|
459
|
+
hasContent = false;
|
|
460
|
+
}
|
|
461
|
+
i++;
|
|
462
|
+
continue;
|
|
463
|
+
}
|
|
464
|
+
if (ch === "\\" && i + 1 < input.length) {
|
|
465
|
+
current += input[i + 1];
|
|
466
|
+
i += 2;
|
|
467
|
+
hasContent = true;
|
|
468
|
+
continue;
|
|
469
|
+
}
|
|
470
|
+
current += ch;
|
|
471
|
+
hasContent = true;
|
|
472
|
+
i++;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
if (quote) {
|
|
476
|
+
throw new Error(`Unterminated ${quote === '"' ? "double" : "single"} quote in pre-merge command`);
|
|
477
|
+
}
|
|
478
|
+
if (hasContent) tokens.push(current);
|
|
479
|
+
return tokens;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function containsUnquotedShellControl(input: string): boolean {
|
|
483
|
+
let i = 0;
|
|
484
|
+
let quote: "" | "'" | '"' = "";
|
|
485
|
+
|
|
486
|
+
while (i < input.length) {
|
|
487
|
+
const ch = input[i]!;
|
|
488
|
+
if (quote) {
|
|
489
|
+
if (ch === quote) {
|
|
490
|
+
quote = "";
|
|
491
|
+
} else if (ch === "\\" && quote === '"' && i + 1 < input.length) {
|
|
492
|
+
i += 2;
|
|
493
|
+
continue;
|
|
494
|
+
}
|
|
495
|
+
i++;
|
|
496
|
+
continue;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
if (ch === '"' || ch === "'") {
|
|
500
|
+
quote = ch;
|
|
501
|
+
i++;
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
if (ch === "\\" && i + 1 < input.length) {
|
|
505
|
+
i += 2;
|
|
506
|
+
continue;
|
|
507
|
+
}
|
|
508
|
+
if (ch === ";" || ch === "&" || ch === "|" || ch === "`" || ch === "$" || ch === "<" || ch === ">") {
|
|
509
|
+
return true;
|
|
510
|
+
}
|
|
511
|
+
i++;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
return false;
|
|
515
|
+
}
|
|
516
|
+
|
|
396
517
|
// ─── Git Helper ────────────────────────────────────────────────────────────
|
|
397
518
|
|
|
398
519
|
|
|
@@ -786,8 +907,34 @@ export class GitServiceImpl {
|
|
|
786
907
|
}
|
|
787
908
|
}
|
|
788
909
|
|
|
910
|
+
// Tokenize and run via execFileSync (no shell). Shell metacharacters in
|
|
911
|
+
// user-supplied prefs.pre_merge_check would otherwise be interpreted as
|
|
912
|
+
// chaining/redirection (e.g. `;`, `&&`, `|`, backticks) — a privesc
|
|
913
|
+
// surface in repos with a checked-in `.gsd/PREFERENCES.md`.
|
|
914
|
+
// (Issue #4980 HIGH-2)
|
|
915
|
+
if (containsUnquotedShellControl(command)) {
|
|
916
|
+
return {
|
|
917
|
+
passed: false,
|
|
918
|
+
skipped: false,
|
|
919
|
+
command,
|
|
920
|
+
error:
|
|
921
|
+
"pre_merge_check contains shell metacharacters (;, &&, |, $, backticks, redirects). " +
|
|
922
|
+
"Put complex commands in a script file (e.g. './scripts/pre-merge.sh') and reference the script path instead.",
|
|
923
|
+
};
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
const tokens = tokenizePreMergeCommand(command);
|
|
927
|
+
if (tokens.length === 0) {
|
|
928
|
+
return { passed: true, skipped: true };
|
|
929
|
+
}
|
|
930
|
+
|
|
789
931
|
try {
|
|
790
|
-
|
|
932
|
+
execFileSync(tokens[0]!, tokens.slice(1), {
|
|
933
|
+
cwd: this.basePath,
|
|
934
|
+
stdio: "pipe",
|
|
935
|
+
encoding: "utf-8",
|
|
936
|
+
env: GIT_NO_PROMPT_ENV,
|
|
937
|
+
});
|
|
791
938
|
return { passed: true, skipped: false, command };
|
|
792
939
|
} catch (err) {
|
|
793
940
|
const msg = getErrorMessage(err);
|
|
@@ -180,7 +180,7 @@ function openRawDb(path: string): unknown {
|
|
|
180
180
|
return new Database(path);
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
const SCHEMA_VERSION = 22;
|
|
183
|
+
export const SCHEMA_VERSION = 22;
|
|
184
184
|
|
|
185
185
|
function indexExists(db: DbAdapter, name: string): boolean {
|
|
186
186
|
return !!db.prepare(
|
|
@@ -2946,6 +2946,9 @@ export function insertAssessment(entry: {
|
|
|
2946
2946
|
fullContent: string;
|
|
2947
2947
|
}): void {
|
|
2948
2948
|
if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
2949
|
+
// Idempotent: PRIMARY KEY is `path`, which is deterministic given (milestone_id, scope) per
|
|
2950
|
+
// the artifact-path resolver. Retrying the same reassess-roadmap silently overwrites the row
|
|
2951
|
+
// instead of accumulating duplicates.
|
|
2949
2952
|
currentDb.prepare(
|
|
2950
2953
|
`INSERT OR REPLACE INTO assessments (path, milestone_id, slice_id, task_id, status, scope, full_content, created_at)
|
|
2951
2954
|
VALUES (:path, :milestone_id, :slice_id, :task_id, :status, :scope, :full_content, :created_at)`,
|
|
@@ -3100,7 +3103,7 @@ function rowToGate(row: Record<string, unknown>): GateRow {
|
|
|
3100
3103
|
scope: row["scope"] as GateScope,
|
|
3101
3104
|
task_id: (row["task_id"] as string) ?? "",
|
|
3102
3105
|
status: row["status"] as GateStatus,
|
|
3103
|
-
verdict: (row["verdict"] as GateVerdict)
|
|
3106
|
+
verdict: row["status"] === "pending" ? null : (row["verdict"] as GateVerdict),
|
|
3104
3107
|
rationale: (row["rationale"] as string) || "",
|
|
3105
3108
|
findings: (row["findings"] as string) || "",
|
|
3106
3109
|
evaluated_at: (row["evaluated_at"] as string) ?? null,
|
|
@@ -3204,7 +3207,7 @@ export function getGateResults(milestoneId: string, sliceId: string, scope?: Gat
|
|
|
3204
3207
|
export function markAllGatesOmitted(milestoneId: string, sliceId: string): void {
|
|
3205
3208
|
if (!currentDb) return;
|
|
3206
3209
|
currentDb.prepare(
|
|
3207
|
-
`UPDATE quality_gates SET status = '
|
|
3210
|
+
`UPDATE quality_gates SET status = 'complete', verdict = 'omitted', evaluated_at = :now
|
|
3208
3211
|
WHERE milestone_id = :mid AND slice_id = :sid AND status = 'pending'`,
|
|
3209
3212
|
).run({
|
|
3210
3213
|
":mid": milestoneId,
|
|
@@ -13,7 +13,7 @@ import { loadFile, saveFile } from "./files.js";
|
|
|
13
13
|
import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
|
|
14
14
|
import { parseRoadmapSlices } from "./roadmap-slices.js";
|
|
15
15
|
import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
|
|
16
|
-
import { buildSkillActivationBlock } from "./auto-prompts.js";
|
|
16
|
+
import { buildDiscussMilestonePrompt, buildSkillActivationBlock } from "./auto-prompts.js";
|
|
17
17
|
import { deriveState } from "./state.js";
|
|
18
18
|
import { invalidateAllCaches } from "./cache.js";
|
|
19
19
|
import { startAutoDetached } from "./auto.js";
|
|
@@ -38,8 +38,8 @@ import { isInheritedRepo } from "./repo-identity.js";
|
|
|
38
38
|
import { ensureGitignore, ensurePreferences, untrackRuntimeFiles } from "./gitignore.js";
|
|
39
39
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
40
40
|
import { resolveUokFlags } from "./uok/flags.js";
|
|
41
|
-
import { ensurePlanV2Graph } from "./uok/plan-v2.js";
|
|
42
|
-
import { detectProjectState } from "./detection.js";
|
|
41
|
+
import { ensurePlanV2Graph, isMissingFinalizedContextResult } from "./uok/plan-v2.js";
|
|
42
|
+
import { detectProjectState, hasGsdBootstrapArtifacts } from "./detection.js";
|
|
43
43
|
import { showProjectInit, offerMigration } from "./init-wizard.js";
|
|
44
44
|
import { validateDirectory } from "./validate-directory.js";
|
|
45
45
|
import { showConfirm } from "../shared/tui.js";
|
|
@@ -93,24 +93,29 @@ function needsPlanV2Gate(state: GSDState): boolean {
|
|
|
93
93
|
|| state.phase === "completing-milestone";
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
type PlanV2GateDecision = "pass" | "recover-missing-context" | "block";
|
|
97
|
+
|
|
96
98
|
function runPlanV2Gate(
|
|
97
99
|
ctx: ExtensionContext,
|
|
98
100
|
basePath: string,
|
|
99
101
|
state: GSDState,
|
|
100
|
-
):
|
|
102
|
+
): PlanV2GateDecision {
|
|
101
103
|
const prefs = loadEffectiveGSDPreferences()?.preferences;
|
|
102
104
|
const uokFlags = resolveUokFlags(prefs);
|
|
103
|
-
if (!uokFlags.planV2 || !needsPlanV2Gate(state)) return
|
|
105
|
+
if (!uokFlags.planV2 || !needsPlanV2Gate(state)) return "pass";
|
|
104
106
|
const compiled = ensurePlanV2Graph(basePath, state);
|
|
105
107
|
if (!compiled.ok) {
|
|
108
|
+
if (isMissingFinalizedContextResult(compiled)) {
|
|
109
|
+
return "recover-missing-context";
|
|
110
|
+
}
|
|
106
111
|
const reason = compiled.reason ?? "plan-v2 compilation failed";
|
|
107
112
|
ctx.ui.notify(
|
|
108
113
|
`Plan gate failed-closed: ${reason}. Complete plan/discuss artifacts before execution.\n\nIf this keeps happening, try: /gsd doctor heal`,
|
|
109
114
|
"error",
|
|
110
115
|
);
|
|
111
|
-
return
|
|
116
|
+
return "block";
|
|
112
117
|
}
|
|
113
|
-
return
|
|
118
|
+
return "pass";
|
|
114
119
|
}
|
|
115
120
|
|
|
116
121
|
// ─── Commit Instruction Helpers ──────────────────────────────────────────────
|
|
@@ -310,12 +315,29 @@ function extractAssistantText(msg: any): string {
|
|
|
310
315
|
|
|
311
316
|
/**
|
|
312
317
|
* Return true if the assistant message contains any tool-use block.
|
|
318
|
+
*
|
|
319
|
+
* The canonical pi-ai `AssistantMessage.content` (see packages/pi-ai/src/types.ts)
|
|
320
|
+
* uses `type: "toolCall"` and `type: "serverToolUse"` for tool invocations —
|
|
321
|
+
* every provider (anthropic-direct, claude-code-cli, openai, etc.) normalizes
|
|
322
|
+
* incoming tool blocks into these two shapes before they reach guided-flow.
|
|
323
|
+
*
|
|
324
|
+
* The Anthropic API wire shape `"tool_use"` / `"server_tool_use"` does NOT appear
|
|
325
|
+
* in the internal AssistantMessage — those literals are only used when sending
|
|
326
|
+
* messages back out to the Anthropic API. Matching them here was a latent bug:
|
|
327
|
+
* `hasToolUse` returned `false` for every real tool call, which let the
|
|
328
|
+
* empty-turn nudge fire and pre-empt MCP tools that block on the user
|
|
329
|
+
* (e.g. `ask_user_questions`). See investigation in PR for #4658.
|
|
313
330
|
*/
|
|
314
331
|
function hasToolUse(msg: any): boolean {
|
|
315
332
|
if (!msg) return false;
|
|
316
333
|
const content = msg.content;
|
|
317
334
|
if (!Array.isArray(content)) return false;
|
|
318
|
-
return content.some(
|
|
335
|
+
return content.some(
|
|
336
|
+
(b: any) =>
|
|
337
|
+
b &&
|
|
338
|
+
typeof b === "object" &&
|
|
339
|
+
(b.type === "toolCall" || b.type === "serverToolUse"),
|
|
340
|
+
);
|
|
319
341
|
}
|
|
320
342
|
|
|
321
343
|
/**
|
|
@@ -825,8 +847,13 @@ export async function showHeadlessMilestoneCreation(
|
|
|
825
847
|
// Set pending auto start (auto-mode triggers on "Milestone X ready." via checkAutoStartAfterDiscuss)
|
|
826
848
|
pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId: nextId, createdAt: Date.now() });
|
|
827
849
|
|
|
828
|
-
// Dispatch
|
|
829
|
-
|
|
850
|
+
// Dispatch as discuss-milestone. The LLM writes PROJECT.md, REQUIREMENTS.md,
|
|
851
|
+
// and CONTEXT.md, then calls gsd_plan_milestone — this is semantically the
|
|
852
|
+
// discuss path, just non-interactive. Using "plan-milestone" here caused
|
|
853
|
+
// model/tool routing to skip discuss-flow tool scoping and
|
|
854
|
+
// `checkAutoStartAfterDiscuss` guardrails that rely on the
|
|
855
|
+
// "discuss-"-prefixed unitType.
|
|
856
|
+
await dispatchWorkflow(pi, prompt, "gsd-run", ctx, "discuss-milestone");
|
|
830
857
|
}
|
|
831
858
|
|
|
832
859
|
|
|
@@ -1481,9 +1508,7 @@ export async function showSmartEntry(
|
|
|
1481
1508
|
// A zombie .gsd/ state (symlink exists but missing PREFERENCES.md and
|
|
1482
1509
|
// milestones/) must trigger the init wizard, not skip it (#2942).
|
|
1483
1510
|
const gsdPath = gsdRoot(basePath);
|
|
1484
|
-
const hasBootstrapArtifacts =
|
|
1485
|
-
&& (existsSync(join(gsdPath, "PREFERENCES.md"))
|
|
1486
|
-
|| existsSync(join(gsdPath, "milestones")));
|
|
1511
|
+
const hasBootstrapArtifacts = hasGsdBootstrapArtifacts(gsdPath);
|
|
1487
1512
|
|
|
1488
1513
|
if (!hasBootstrapArtifacts) {
|
|
1489
1514
|
const detection = detectProjectState(basePath);
|
|
@@ -1573,7 +1598,8 @@ export async function showSmartEntry(
|
|
|
1573
1598
|
logWarning("guided", `STATE.md rebuild failed: ${(err as Error).message}`);
|
|
1574
1599
|
}
|
|
1575
1600
|
|
|
1576
|
-
|
|
1601
|
+
const planV2GateDecision = runPlanV2Gate(ctx, basePath, state);
|
|
1602
|
+
if (planV2GateDecision === "block") return;
|
|
1577
1603
|
|
|
1578
1604
|
if (!state.activeMilestone?.id) {
|
|
1579
1605
|
// Guard: if a discuss session is already in flight, don't re-inject the prompt.
|
|
@@ -1661,6 +1687,23 @@ export async function showSmartEntry(
|
|
|
1661
1687
|
const milestoneId = state.activeMilestone.id;
|
|
1662
1688
|
const milestoneTitle = state.activeMilestone.title;
|
|
1663
1689
|
|
|
1690
|
+
if (planV2GateDecision === "recover-missing-context") {
|
|
1691
|
+
pendingAutoStartMap.set(basePath, { ctx, pi, basePath, milestoneId, step: stepMode, createdAt: Date.now() });
|
|
1692
|
+
await dispatchWorkflow(
|
|
1693
|
+
pi,
|
|
1694
|
+
await buildDiscussMilestonePrompt(
|
|
1695
|
+
milestoneId,
|
|
1696
|
+
milestoneTitle,
|
|
1697
|
+
basePath,
|
|
1698
|
+
getStructuredQuestionsAvailability(pi, ctx),
|
|
1699
|
+
),
|
|
1700
|
+
"gsd-discuss",
|
|
1701
|
+
ctx,
|
|
1702
|
+
"discuss-milestone",
|
|
1703
|
+
);
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1664
1707
|
// ── All milestones complete → New milestone ──────────────────────────
|
|
1665
1708
|
if (state.phase === "complete") {
|
|
1666
1709
|
const choice = await showNextAction(ctx, {
|
|
@@ -50,7 +50,17 @@ export type JournalEventType =
|
|
|
50
50
|
| "worktree-skip"
|
|
51
51
|
| "worktree-merge-start"
|
|
52
52
|
| "worktree-merge-failed"
|
|
53
|
-
| "artifact-verification-retry"
|
|
53
|
+
| "artifact-verification-retry"
|
|
54
|
+
// #4764 — worktree lifespan / divergence telemetry
|
|
55
|
+
| "worktree-created"
|
|
56
|
+
| "worktree-merged"
|
|
57
|
+
| "worktree-orphaned"
|
|
58
|
+
| "auto-exit"
|
|
59
|
+
| "worktree-sync"
|
|
60
|
+
| "canonical-root-redirect"
|
|
61
|
+
// #4765 — slice-cadence collapse
|
|
62
|
+
| "slice-merged"
|
|
63
|
+
| "milestone-resquash";
|
|
54
64
|
|
|
55
65
|
/** A single structured event in the journal. */
|
|
56
66
|
export interface JournalEntry {
|