gsd-pi 2.77.0-dev.58d3d4d6c → 2.77.0-dev.cfd69e714
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/claude-cli-check.js +5 -1
- package/dist/headless.js +49 -4
- package/dist/resource-loader.d.ts +40 -0
- package/dist/resource-loader.js +32 -13
- package/dist/resources/extensions/browser-tools/capture.js +9 -0
- package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/dist/resources/extensions/browser-tools/tools/forms.js +5 -1
- package/dist/resources/extensions/browser-tools/tools/intent.js +5 -1
- package/dist/resources/extensions/claude-code-cli/readiness.js +5 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +481 -17
- package/dist/resources/extensions/gsd/auto/loop.js +43 -0
- package/dist/resources/extensions/gsd/auto/phases.js +15 -21
- package/dist/resources/extensions/gsd/auto/session.js +0 -2
- package/dist/resources/extensions/gsd/auto-dispatch.js +102 -24
- package/dist/resources/extensions/gsd/auto-model-selection.js +124 -4
- package/dist/resources/extensions/gsd/auto-post-unit.js +71 -64
- package/dist/resources/extensions/gsd/auto-prompts.js +329 -102
- package/dist/resources/extensions/gsd/auto-recovery.js +195 -23
- package/dist/resources/extensions/gsd/auto-start.js +34 -24
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +47 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +122 -26
- package/dist/resources/extensions/gsd/auto.js +31 -20
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +9 -1
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +209 -0
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +3 -6
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -3
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +127 -9
- package/dist/resources/extensions/gsd/component-loader.js +447 -0
- package/dist/resources/extensions/gsd/component-types.js +69 -0
- package/dist/resources/extensions/gsd/detection.js +49 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/dist/resources/extensions/gsd/gate-registry.js +2 -2
- package/dist/resources/extensions/gsd/git-constants.js +28 -1
- package/dist/resources/extensions/gsd/git-self-heal.js +27 -0
- package/dist/resources/extensions/gsd/git-service.js +126 -2
- package/dist/resources/extensions/gsd/gsd-db.js +6 -3
- package/dist/resources/extensions/gsd/guided-flow.js +17 -5
- package/dist/resources/extensions/gsd/memory-extractor.js +7 -1
- package/dist/resources/extensions/gsd/milestone-scope-classifier.js +299 -0
- package/dist/resources/extensions/gsd/model-cost-table.js +3 -0
- package/dist/resources/extensions/gsd/model-router.js +6 -0
- package/dist/resources/extensions/gsd/native-git-bridge.js +34 -4
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/dist/resources/extensions/gsd/safety/git-checkpoint.js +11 -0
- package/dist/resources/extensions/gsd/service-tier.js +5 -2
- package/dist/resources/extensions/gsd/session-lock.js +19 -10
- package/dist/resources/extensions/gsd/skill-manifest.js +168 -0
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +278 -8
- package/dist/resources/extensions/gsd/state.js +44 -33
- package/dist/resources/extensions/gsd/sync-lock.js +98 -42
- package/dist/resources/extensions/gsd/unit-context-composer.js +147 -0
- package/dist/resources/extensions/gsd/unit-context-manifest.js +370 -0
- package/dist/resources/extensions/gsd/uok/gate-runner.js +53 -5
- package/dist/resources/extensions/gsd/workflow-mcp.js +6 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +34 -8
- package/dist/resources/extensions/mcp-client/index.js +3 -1
- package/dist/resources/extensions/ollama/index.js +5 -1
- package/dist/resources/extensions/remote-questions/manager.js +11 -5
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
- package/dist/web/standalone/.next/server/chunks/1926.js +1 -1
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/package.json +2 -3
- package/packages/daemon/src/logger.ts +4 -3
- package/packages/mcp-server/dist/server.d.ts +24 -0
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +88 -87
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/src/mcp-server.test.ts +25 -3
- package/packages/mcp-server/src/readers/graph.test.ts +87 -15
- package/packages/mcp-server/src/secure-env-collect.test.ts +232 -237
- package/packages/mcp-server/src/server.ts +131 -105
- package/packages/mcp-server/src/workflow-tools.test.ts +80 -39
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/native/package.json +1 -1
- package/packages/native/src/__tests__/_test-coverage-guard.test.mjs +98 -0
- package/packages/native/src/__tests__/module-compat.test.mjs +59 -27
- package/packages/native/src/__tests__/ps.test.mjs +14 -8
- package/packages/native/src/__tests__/stream-process.test.mjs +23 -2
- package/packages/native/src/__tests__/truncate.test.mjs +17 -2
- package/packages/pi-agent-core/src/agent-loop.test.ts +5 -15
- package/packages/pi-agent-core/src/agent.test.ts +96 -102
- package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-ai/dist/models/capability-patches.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/capability-patches.js +9 -2
- package/packages/pi-ai/dist/models/capability-patches.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/index.d.ts +34 -0
- package/packages/pi-ai/dist/models/generated/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai-codex.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai-codex.js.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.d.ts +17 -0
- package/packages/pi-ai/dist/models/generated/openai.d.ts.map +1 -1
- package/packages/pi-ai/dist/models/generated/openai.js +17 -0
- package/packages/pi-ai/dist/models/generated/openai.js.map +1 -1
- package/packages/pi-ai/dist/models.generated.test.js +43 -70
- package/packages/pi-ai/dist/models.generated.test.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +36 -11
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/scripts/generate-models.ts +44 -0
- package/packages/pi-ai/src/models/capability-patches.ts +10 -2
- package/packages/pi-ai/src/models/generated/openai-codex.ts +17 -0
- package/packages/pi-ai/src/models/generated/openai.ts +17 -0
- package/packages/pi-ai/src/models.generated.test.ts +46 -73
- package/packages/pi-ai/src/models.test.ts +48 -11
- package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +96 -32
- package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js +75 -12
- package/packages/pi-coding-agent/dist/core/agent-session-model-switch.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +99 -31
- package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +5 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/loader.js +61 -0
- package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js +30 -4
- package/packages/pi-coding-agent/dist/core/lsp/lsp-integration.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +17 -0
- package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js +76 -18
- package/packages/pi-coding-agent/dist/core/resource-loader-cache-reset.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +2 -6
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +5 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js +18 -0
- package/packages/pi-coding-agent/dist/core/retryable-error-regex.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +20 -0
- package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/system-prompt.js +16 -2
- package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js +20 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/dynamic-border.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +18 -3
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +125 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +105 -13
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js +130 -0
- package/packages/pi-coding-agent/dist/tests/system-prompt-skill-filter.test.js.map +1 -0
- package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +113 -37
- package/packages/pi-coding-agent/src/core/agent-session-model-switch.test.ts +89 -17
- package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +112 -43
- package/packages/pi-coding-agent/src/core/extensions/loader.ts +58 -0
- package/packages/pi-coding-agent/src/core/lsp/lsp-integration.test.ts +35 -4
- package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +20 -0
- package/packages/pi-coding-agent/src/core/resource-loader-cache-reset.test.ts +93 -28
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +5 -1
- package/packages/pi-coding-agent/src/core/retry-handler.ts +2 -8
- package/packages/pi-coding-agent/src/core/retryable-error-regex.ts +18 -0
- package/packages/pi-coding-agent/src/core/system-prompt.ts +35 -1
- package/packages/pi-coding-agent/src/index.ts +1 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/dynamic-border.test.ts +26 -20
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +146 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +20 -3
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +2 -0
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +119 -13
- package/packages/pi-coding-agent/src/tests/system-prompt-skill-filter.test.ts +157 -0
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js +18 -8
- package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +128 -17
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +36 -12
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
- package/packages/pi-tui/dist/__tests__/tui.test.js +18 -30
- package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/input.test.js +10 -3
- package/packages/pi-tui/dist/components/__tests__/input.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/loader.test.js +53 -9
- package/packages/pi-tui/dist/components/__tests__/loader.test.js.map +1 -1
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js +6 -2
- package/packages/pi-tui/dist/components/__tests__/markdown-maxlines.test.js.map +1 -1
- package/packages/pi-tui/dist/components/editor.d.ts +14 -0
- package/packages/pi-tui/dist/components/editor.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/editor.js +19 -0
- package/packages/pi-tui/dist/components/editor.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.js +6 -5
- package/packages/pi-tui/dist/components/image.test.js.map +1 -1
- package/packages/pi-tui/dist/editor-component.d.ts +2 -0
- package/packages/pi-tui/dist/editor-component.d.ts.map +1 -1
- package/packages/pi-tui/dist/editor-component.js.map +1 -1
- package/packages/pi-tui/src/__tests__/autocomplete.test.ts +24 -8
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +140 -17
- package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +41 -12
- package/packages/pi-tui/src/__tests__/tui.test.ts +18 -37
- package/packages/pi-tui/src/components/__tests__/input.test.ts +19 -3
- package/packages/pi-tui/src/components/__tests__/loader.test.ts +112 -35
- package/packages/pi-tui/src/components/__tests__/markdown-maxlines.test.ts +9 -2
- package/packages/pi-tui/src/components/editor.ts +22 -0
- package/packages/pi-tui/src/components/image.test.ts +10 -5
- package/packages/pi-tui/src/editor-component.ts +3 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/dist/rpc-client.test.js +101 -51
- package/packages/rpc-client/dist/rpc-client.test.js.map +1 -1
- package/packages/rpc-client/src/rpc-client.test.ts +109 -52
- package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
- package/scripts/install.js +15 -1
- package/src/resources/extensions/browser-tools/capture.ts +12 -0
- package/src/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +8 -59
- package/src/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +36 -24
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +69 -71
- package/src/resources/extensions/browser-tools/tools/forms.ts +5 -1
- package/src/resources/extensions/browser-tools/tools/intent.ts +5 -1
- package/src/resources/extensions/claude-code-cli/readiness.ts +5 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +518 -19
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +919 -75
- package/src/resources/extensions/github-sync/tests/cli.test.ts +76 -7
- package/src/resources/extensions/github-sync/tests/templates.test.ts +33 -1
- package/src/resources/extensions/gsd/auto/loop.ts +47 -0
- package/src/resources/extensions/gsd/auto/phases.ts +16 -20
- package/src/resources/extensions/gsd/auto/session.ts +0 -2
- package/src/resources/extensions/gsd/auto-dispatch.ts +113 -24
- package/src/resources/extensions/gsd/auto-model-selection.ts +131 -4
- package/src/resources/extensions/gsd/auto-post-unit.ts +82 -73
- package/src/resources/extensions/gsd/auto-prompts.ts +330 -90
- package/src/resources/extensions/gsd/auto-recovery.ts +225 -24
- package/src/resources/extensions/gsd/auto-start.ts +54 -6
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +51 -7
- package/src/resources/extensions/gsd/auto-worktree.ts +130 -26
- package/src/resources/extensions/gsd/auto.ts +43 -22
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +9 -1
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +221 -0
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +3 -7
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -3
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +158 -9
- package/src/resources/extensions/gsd/component-loader.ts +598 -0
- package/src/resources/extensions/gsd/component-types.ts +362 -0
- package/src/resources/extensions/gsd/detection.ts +58 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -1
- package/src/resources/extensions/gsd/gate-registry.ts +2 -2
- package/src/resources/extensions/gsd/git-constants.ts +30 -1
- package/src/resources/extensions/gsd/git-self-heal.ts +31 -0
- package/src/resources/extensions/gsd/git-service.ts +133 -2
- package/src/resources/extensions/gsd/gsd-db.ts +6 -3
- package/src/resources/extensions/gsd/guided-flow.ts +20 -5
- package/src/resources/extensions/gsd/memory-extractor.ts +11 -3
- package/src/resources/extensions/gsd/milestone-scope-classifier.ts +366 -0
- package/src/resources/extensions/gsd/model-cost-table.ts +3 -0
- package/src/resources/extensions/gsd/model-router.ts +6 -0
- package/src/resources/extensions/gsd/native-git-bridge.ts +34 -4
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +6 -2
- package/src/resources/extensions/gsd/prompts/plan-slice.md +15 -2
- package/src/resources/extensions/gsd/safety/git-checkpoint.ts +15 -0
- package/src/resources/extensions/gsd/service-tier.ts +5 -2
- package/src/resources/extensions/gsd/session-lock.ts +20 -10
- package/src/resources/extensions/gsd/skill-manifest.ts +175 -0
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +309 -8
- package/src/resources/extensions/gsd/state.ts +49 -44
- package/src/resources/extensions/gsd/sync-lock.ts +97 -39
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +270 -0
- package/src/resources/extensions/gsd/tests/auto-deterministic-error-classification-4973.test.ts +341 -0
- package/src/resources/extensions/gsd/tests/auto-discuss-milestone-deadlock-4973.test.ts +264 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +94 -289
- package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +742 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +78 -0
- package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +61 -0
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +93 -0
- package/src/resources/extensions/gsd/tests/auto-retry-mcp-churn-fixes.test.ts +8 -197
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +15 -58
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +263 -0
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +192 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +16 -8
- package/src/resources/extensions/gsd/tests/component-loader.test.ts +589 -0
- package/src/resources/extensions/gsd/tests/component-types.test.ts +127 -0
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +50 -1
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +91 -3
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +139 -129
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +9 -105
- package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +102 -0
- package/src/resources/extensions/gsd/tests/gate-storage.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/hook-key-parsing.test.ts +4 -55
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +7 -57
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/integration/doctor-proactive.test.ts +18 -2
- package/src/resources/extensions/gsd/tests/integration/queue-completed-milestone-perf.test.ts +10 -4
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +144 -7
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/integration/state-machine-runtime-failures.test.ts +2 -16
- package/src/resources/extensions/gsd/tests/interrupted-session-ui.test.ts +6 -9
- package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +8 -37
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +5 -15
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +227 -62
- package/src/resources/extensions/gsd/tests/milestone-scope-classifier.test.ts +187 -0
- package/src/resources/extensions/gsd/tests/model-cost-table.test.ts +9 -1
- package/src/resources/extensions/gsd/tests/model-router.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +6 -49
- package/src/resources/extensions/gsd/tests/notification-widget.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +273 -133
- package/src/resources/extensions/gsd/tests/pipeline-variant-dispatch.test.ts +301 -0
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +32 -1
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +23 -24
- package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +32 -0
- package/src/resources/extensions/gsd/tests/ready-phrase-no-files-4573.test.ts +75 -2
- package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +132 -0
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +8 -40
- package/src/resources/extensions/gsd/tests/regex-hardening.test.ts +136 -256
- package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +148 -0
- package/src/resources/extensions/gsd/tests/service-tier.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/silent-catch-diagnostics.test.ts +55 -95
- package/src/resources/extensions/gsd/tests/single-writer-v3-tool-surface.test.ts +158 -0
- package/src/resources/extensions/gsd/tests/skill-activation.test.ts +120 -1
- package/src/resources/extensions/gsd/tests/skill-manifest.test.ts +112 -0
- package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +164 -1
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +5 -5
- package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +11 -92
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +102 -101
- package/src/resources/extensions/gsd/tests/sync-lock.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/test-helpers.test.ts +12 -61
- package/src/resources/extensions/gsd/tests/test-helpers.ts +21 -8
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +61 -1
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +8 -1
- package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +355 -0
- package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +258 -0
- package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +75 -0
- package/src/resources/extensions/gsd/tests/uok-gitops-wiring.test.ts +49 -26
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +144 -81
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -54
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +342 -277
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +37 -29
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +226 -266
- package/src/resources/extensions/gsd/tests/worktree-health-monorepo.test.ts +103 -67
- package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +92 -90
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +238 -59
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +113 -161
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +262 -0
- package/src/resources/extensions/gsd/tests/write-gate-predicates.test.ts +186 -0
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +7 -5
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +80 -96
- package/src/resources/extensions/gsd/types.ts +3 -3
- package/src/resources/extensions/gsd/unit-context-composer.ts +218 -0
- package/src/resources/extensions/gsd/unit-context-manifest.ts +574 -0
- package/src/resources/extensions/gsd/uok/gate-runner.ts +65 -5
- package/src/resources/extensions/gsd/workflow-mcp.ts +6 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +55 -7
- package/src/resources/extensions/mcp-client/index.ts +3 -1
- package/src/resources/extensions/mcp-client/tests/server-name-spaces.test.ts +70 -36
- package/src/resources/extensions/ollama/index.ts +5 -1
- package/src/resources/extensions/ollama/ollama-auth-mode.test.ts +123 -15
- package/src/resources/extensions/ollama/ollama-status-indicator.test.ts +206 -19
- package/src/resources/extensions/remote-questions/manager.ts +36 -4
- package/src/resources/extensions/remote-questions/tests/command-polling.test.ts +200 -190
- package/src/resources/extensions/shared/tests/interview-preview.test.ts +11 -3
- package/src/resources/extensions/voice/tests/linux-ready.test.ts +129 -113
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts +0 -2
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.d.ts.map +0 -1
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js +0 -289
- package/packages/pi-ai/dist/utils/oauth/oauth-providers.test.js.map +0 -1
- package/packages/pi-ai/src/utils/oauth/oauth-providers.test.ts +0 -363
- package/src/resources/extensions/gsd/tests/auto-start-model-capture.test.ts +0 -144
- package/src/resources/extensions/gsd/tests/complete-milestone-false-merge.test.ts +0 -157
- package/src/resources/extensions/gsd/tests/dashboard-model-label-ordering.test.ts +0 -107
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +0 -48
- package/src/resources/extensions/gsd/tests/forensics-context-persist.test.ts +0 -159
- package/src/resources/extensions/gsd/tests/forensics-db-completion.test.ts +0 -96
- package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +0 -79
- package/src/resources/extensions/gsd/tests/forensics-hook-key-parse.test.ts +0 -75
- package/src/resources/extensions/gsd/tests/forensics-journal.test.ts +0 -162
- package/src/resources/extensions/gsd/tests/forensics-worktree-telemetry.test.ts +0 -145
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +0 -38
- package/src/resources/extensions/gsd/tests/gsd-no-project-error.test.ts +0 -73
- package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +0 -130
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +0 -43
- /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{Cev5xrAYA3ZGTRLyjR2fX → SvCJDZPQW104bR1KnBQg1}/_ssgManifest.js +0 -0
|
@@ -17,6 +17,7 @@ import { isDbAvailable, getTask, getSlice, getSliceTasks, getPendingGates, updat
|
|
|
17
17
|
import { isValidationTerminal } from "./state.js";
|
|
18
18
|
import { getErrorMessage } from "./error-utils.js";
|
|
19
19
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
20
|
+
import { readIntegrationBranch } from "./git-service.js";
|
|
20
21
|
import { isClosedStatus } from "./status-guards.js";
|
|
21
22
|
import {
|
|
22
23
|
nativeConflictFiles,
|
|
@@ -24,6 +25,7 @@ import {
|
|
|
24
25
|
nativeCheckoutTheirs,
|
|
25
26
|
nativeAddPaths,
|
|
26
27
|
nativeMergeAbort,
|
|
28
|
+
nativeRebaseAbort,
|
|
27
29
|
nativeResetHard,
|
|
28
30
|
} from "./native-git-bridge.js";
|
|
29
31
|
import {
|
|
@@ -63,14 +65,16 @@ export {
|
|
|
63
65
|
// ─── Artifact Resolution & Verification ───────────────────────────────────────
|
|
64
66
|
|
|
65
67
|
/**
|
|
66
|
-
* Check whether a milestone produced implementation artifacts (non-`.gsd/`
|
|
67
|
-
* in
|
|
68
|
-
*
|
|
68
|
+
* Check whether a milestone produced implementation artifacts (non-`.gsd/`
|
|
69
|
+
* files) in git history. The primary signal is the branch diff against the
|
|
70
|
+
* integration branch. When a retry is already on the integration branch, that
|
|
71
|
+
* diff is a self-diff; if a milestone ID is available, fall back to recent
|
|
72
|
+
* GSD-tagged commits for that milestone.
|
|
69
73
|
*
|
|
70
74
|
* Returns "present" if implementation files found, "absent" if only .gsd/ files,
|
|
71
75
|
* "unknown" if git is unavailable or check failed (callers decide how to handle).
|
|
72
76
|
*/
|
|
73
|
-
export function hasImplementationArtifacts(basePath: string): "present" | "absent" | "unknown" {
|
|
77
|
+
export function hasImplementationArtifacts(basePath: string, milestoneId?: string): "present" | "absent" | "unknown" {
|
|
74
78
|
try {
|
|
75
79
|
// Verify we're in a git repo
|
|
76
80
|
try {
|
|
@@ -86,20 +90,29 @@ export function hasImplementationArtifacts(basePath: string): "present" | "absen
|
|
|
86
90
|
|
|
87
91
|
// Strategy: check `git diff --name-only` against the merge-base with the
|
|
88
92
|
// main branch. This captures ALL files changed during the milestone's
|
|
89
|
-
// lifetime
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
//
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
|
|
102
|
-
|
|
93
|
+
// lifetime while running on a milestone branch.
|
|
94
|
+
const integrationBranch = milestoneId
|
|
95
|
+
? readIntegrationBranch(basePath, milestoneId) ?? detectMainBranch(basePath)
|
|
96
|
+
: detectMainBranch(basePath);
|
|
97
|
+
const currentBranch = getCurrentBranch(basePath);
|
|
98
|
+
const branchDiff = getChangedFilesSinceBranch(basePath, integrationBranch);
|
|
99
|
+
if (!branchDiff.ok) return "unknown";
|
|
100
|
+
const changedFiles = branchDiff.files;
|
|
101
|
+
|
|
102
|
+
// No branch-diff files can mean the unit retried on main after milestone
|
|
103
|
+
// commits already landed there. In that topology, inspect GSD-tagged
|
|
104
|
+
// milestone commits instead of treating the self-diff as proof of no work.
|
|
105
|
+
if (changedFiles.length === 0) {
|
|
106
|
+
if (milestoneId && currentBranch === integrationBranch) {
|
|
107
|
+
const tagged = getChangedFilesFromMilestoneTaggedCommits(basePath, milestoneId);
|
|
108
|
+
if (!tagged.ok) return "unknown";
|
|
109
|
+
if (tagged.matched) return classifyImplementationFiles(tagged.files);
|
|
110
|
+
}
|
|
111
|
+
if (currentBranch && currentBranch !== "HEAD") return "absent";
|
|
112
|
+
return "unknown";
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return classifyImplementationFiles(changedFiles);
|
|
103
116
|
} catch (e) {
|
|
104
117
|
// Non-fatal — if git operations fail, return unknown so callers can decide
|
|
105
118
|
logWarning("recovery", `implementation artifact check failed: ${(e as Error).message}`);
|
|
@@ -107,6 +120,28 @@ export function hasImplementationArtifacts(basePath: string): "present" | "absen
|
|
|
107
120
|
}
|
|
108
121
|
}
|
|
109
122
|
|
|
123
|
+
function getCurrentBranch(basePath: string): string | null {
|
|
124
|
+
try {
|
|
125
|
+
const branch = execFileSync("git", ["rev-parse", "--abbrev-ref", "HEAD"], {
|
|
126
|
+
cwd: basePath,
|
|
127
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
128
|
+
encoding: "utf-8",
|
|
129
|
+
}).trim();
|
|
130
|
+
return branch || null;
|
|
131
|
+
} catch {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function classifyImplementationFiles(files: readonly string[]): "present" | "absent" {
|
|
137
|
+
const implFiles = files.filter(isImplementationPath);
|
|
138
|
+
return implFiles.length > 0 ? "present" : "absent";
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function isImplementationPath(file: string): boolean {
|
|
142
|
+
return !file.startsWith(".gsd/") && !file.startsWith(".gsd\\");
|
|
143
|
+
}
|
|
144
|
+
|
|
110
145
|
/**
|
|
111
146
|
* Detect the main/master branch name.
|
|
112
147
|
*/
|
|
@@ -142,7 +177,7 @@ function detectMainBranch(basePath: string): string {
|
|
|
142
177
|
* Get files changed since the branch diverged from the target branch.
|
|
143
178
|
* Falls back to checking HEAD~20 if merge-base detection fails.
|
|
144
179
|
*/
|
|
145
|
-
function getChangedFilesSinceBranch(basePath: string, targetBranch: string): string[] {
|
|
180
|
+
function getChangedFilesSinceBranch(basePath: string, targetBranch: string): { ok: boolean; files: string[] } {
|
|
146
181
|
try {
|
|
147
182
|
// Try merge-base approach first
|
|
148
183
|
const mergeBase = execFileSync(
|
|
@@ -155,7 +190,7 @@ function getChangedFilesSinceBranch(basePath: string, targetBranch: string): str
|
|
|
155
190
|
"git", ["diff", "--name-only", mergeBase, "HEAD"],
|
|
156
191
|
{ cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
|
|
157
192
|
).trim();
|
|
158
|
-
return result ? result.split("\n").filter(Boolean) : [];
|
|
193
|
+
return { ok: true, files: result ? result.split("\n").filter(Boolean) : [] };
|
|
159
194
|
}
|
|
160
195
|
} catch (err) {
|
|
161
196
|
// merge-base failed — fall back
|
|
@@ -168,11 +203,94 @@ function getChangedFilesSinceBranch(basePath: string, targetBranch: string): str
|
|
|
168
203
|
"git", ["log", "--name-only", "--pretty=format:", "-20", "HEAD"],
|
|
169
204
|
{ cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
|
|
170
205
|
).trim();
|
|
171
|
-
return result ? [...new Set(result.split("\n").filter(Boolean))] : [];
|
|
206
|
+
return { ok: true, files: result ? [...new Set(result.split("\n").filter(Boolean))] : [] };
|
|
172
207
|
} catch (e) {
|
|
173
208
|
logWarning("recovery", `git log fallback failed: ${(e as Error).message}`);
|
|
174
|
-
return [];
|
|
209
|
+
return { ok: false, files: [] };
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
function getChangedFilesFromMilestoneTaggedCommits(
|
|
214
|
+
basePath: string,
|
|
215
|
+
milestoneId: string,
|
|
216
|
+
): { ok: boolean; matched: boolean; files: string[] } {
|
|
217
|
+
try {
|
|
218
|
+
const logOutput = execFileSync(
|
|
219
|
+
"git",
|
|
220
|
+
["log", "--format=%H%x1f%B%x1e", "HEAD", "--", `.gsd/milestones/${milestoneId}`],
|
|
221
|
+
{ cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
|
|
222
|
+
);
|
|
223
|
+
const records = logOutput
|
|
224
|
+
.split("\x1e")
|
|
225
|
+
.map((record) => record.trim())
|
|
226
|
+
.filter(Boolean)
|
|
227
|
+
.flatMap((record) => {
|
|
228
|
+
const sep = record.indexOf("\x1f");
|
|
229
|
+
if (sep === -1) return [];
|
|
230
|
+
const hash = record.slice(0, sep).trim();
|
|
231
|
+
const message = record.slice(sep + 1);
|
|
232
|
+
return [{ hash, message }];
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
const files = new Set<string>();
|
|
236
|
+
let matched = false;
|
|
237
|
+
for (const { hash, message } of records) {
|
|
238
|
+
if (!commitMessageHasGsdTrailer(message)) continue;
|
|
239
|
+
|
|
240
|
+
const commitFiles = getChangedFilesForCommit(basePath, hash);
|
|
241
|
+
if (!commitMatchesMilestone(message, milestoneId, commitFiles)) continue;
|
|
242
|
+
|
|
243
|
+
matched = true;
|
|
244
|
+
for (const file of commitFiles) {
|
|
245
|
+
files.add(file);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
return { ok: true, matched, files: [...files] };
|
|
250
|
+
} catch (e) {
|
|
251
|
+
logWarning("recovery", `milestone-tagged commit scan failed: ${(e as Error).message}`);
|
|
252
|
+
return { ok: false, matched: false, files: [] };
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function getChangedFilesForCommit(basePath: string, hash: string): string[] {
|
|
257
|
+
const fileOutput = execFileSync(
|
|
258
|
+
"git",
|
|
259
|
+
["diff-tree", "--root", "--no-commit-id", "-r", "--name-only", hash],
|
|
260
|
+
{ cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" },
|
|
261
|
+
).trim();
|
|
262
|
+
return fileOutput.split("\n").map((f) => f.trim()).filter(Boolean);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function commitMessageHasGsdTrailer(message: string): boolean {
|
|
266
|
+
return /^GSD-(?:Task|Unit):\s*\S+/m.test(message);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function commitMatchesMilestone(message: string, milestoneId: string, files: readonly string[]): boolean {
|
|
270
|
+
if (commitTrailerStartsWithMilestone(message, milestoneId)) return true;
|
|
271
|
+
|
|
272
|
+
// Meaningful execute-task commits currently store task scope as Sxx/Tyy
|
|
273
|
+
// rather than Mxx/Sxx/Tyy. Bind those commits back to the milestone only
|
|
274
|
+
// when the commit also touched this milestone's artifacts.
|
|
275
|
+
if (/^GSD-Task:\s*S[^/\s]+\/T\S+/m.test(message)) {
|
|
276
|
+
return files.some((file) => isMilestoneArtifactPath(file, milestoneId));
|
|
175
277
|
}
|
|
278
|
+
|
|
279
|
+
return false;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function commitTrailerStartsWithMilestone(message: string, milestoneId: string): boolean {
|
|
283
|
+
const escapedMilestone = milestoneId.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
284
|
+
const trailerPattern = new RegExp(
|
|
285
|
+
`^GSD-(?:Task|Unit):\\s*${escapedMilestone}(?:$|[\\s/])`,
|
|
286
|
+
"m",
|
|
287
|
+
);
|
|
288
|
+
return trailerPattern.test(message);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function isMilestoneArtifactPath(file: string, milestoneId: string): boolean {
|
|
292
|
+
return file.startsWith(`.gsd/milestones/${milestoneId}/`)
|
|
293
|
+
|| file.startsWith(`.gsd\\milestones\\${milestoneId}\\`);
|
|
176
294
|
}
|
|
177
295
|
|
|
178
296
|
/**
|
|
@@ -491,7 +609,7 @@ export function verifyExpectedArtifact(
|
|
|
491
609
|
if (!dbMilestone) return false;
|
|
492
610
|
if (!isClosedStatus(dbMilestone.status) && summaryOutcome !== "success") return false;
|
|
493
611
|
}
|
|
494
|
-
if (hasImplementationArtifacts(base) === "absent") return false;
|
|
612
|
+
if (hasImplementationArtifacts(base, mid) === "absent") return false;
|
|
495
613
|
}
|
|
496
614
|
|
|
497
615
|
return true;
|
|
@@ -612,6 +730,79 @@ function abortAndResetMerge(
|
|
|
612
730
|
|
|
613
731
|
export type MergeReconcileResult = "clean" | "reconciled" | "blocked";
|
|
614
732
|
|
|
733
|
+
/**
|
|
734
|
+
* Detect and abort other in-progress git operations left behind by a SIGKILL'd
|
|
735
|
+
* worker (rebase, cherry-pick, revert). Without this, a killed worker mid-rebase
|
|
736
|
+
* leaves `.git/rebase-merge/` or `.git/CHERRY_PICK_HEAD` and the worktree is
|
|
737
|
+
* wedged until the user manually runs the matching `--abort`.
|
|
738
|
+
*
|
|
739
|
+
* Called before merge-state reconciliation because these states block any
|
|
740
|
+
* subsequent merge/commit operation. (Issue #4980 HIGH-7)
|
|
741
|
+
*/
|
|
742
|
+
function reconcileOtherInProgressGitOps(
|
|
743
|
+
basePath: string,
|
|
744
|
+
ctx: ExtensionContext,
|
|
745
|
+
): "clean" | "reconciled" | "blocked" {
|
|
746
|
+
const gitDir = join(basePath, ".git");
|
|
747
|
+
const states: Array<{
|
|
748
|
+
label: string;
|
|
749
|
+
indicators: string[];
|
|
750
|
+
abort: () => void;
|
|
751
|
+
}> = [
|
|
752
|
+
{
|
|
753
|
+
label: "rebase",
|
|
754
|
+
indicators: [join(gitDir, "rebase-merge"), join(gitDir, "rebase-apply")],
|
|
755
|
+
abort: () => nativeRebaseAbort(basePath),
|
|
756
|
+
},
|
|
757
|
+
{
|
|
758
|
+
label: "cherry-pick",
|
|
759
|
+
indicators: [join(gitDir, "CHERRY_PICK_HEAD")],
|
|
760
|
+
abort: () => {
|
|
761
|
+
// No native helper; fall back to git CLI.
|
|
762
|
+
try {
|
|
763
|
+
execFileSync("git", ["cherry-pick", "--abort"], {
|
|
764
|
+
cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8",
|
|
765
|
+
});
|
|
766
|
+
} catch (err) { logWarning("recovery", `cherry-pick --abort failed: ${getErrorMessage(err)}`); }
|
|
767
|
+
},
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
label: "revert",
|
|
771
|
+
indicators: [join(gitDir, "REVERT_HEAD")],
|
|
772
|
+
abort: () => {
|
|
773
|
+
try {
|
|
774
|
+
execFileSync("git", ["revert", "--abort"], {
|
|
775
|
+
cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8",
|
|
776
|
+
});
|
|
777
|
+
} catch (err) { logWarning("recovery", `revert --abort failed: ${getErrorMessage(err)}`); }
|
|
778
|
+
},
|
|
779
|
+
},
|
|
780
|
+
];
|
|
781
|
+
|
|
782
|
+
let reconciled = false;
|
|
783
|
+
for (const s of states) {
|
|
784
|
+
const present = s.indicators.some((p) => existsSync(p));
|
|
785
|
+
if (!present) continue;
|
|
786
|
+
try {
|
|
787
|
+
s.abort();
|
|
788
|
+
ctx.ui.notify(
|
|
789
|
+
`Detected leftover ${s.label} state from prior session — aborted.`,
|
|
790
|
+
"warning",
|
|
791
|
+
);
|
|
792
|
+
reconciled = true;
|
|
793
|
+
} catch (err) {
|
|
794
|
+
logError("recovery", `${s.label} abort failed: ${getErrorMessage(err)}`);
|
|
795
|
+
ctx.ui.notify(
|
|
796
|
+
`Detected leftover ${s.label} state but auto-abort failed. ` +
|
|
797
|
+
`Run \`git ${s.label} --abort\` manually before retrying.`,
|
|
798
|
+
"error",
|
|
799
|
+
);
|
|
800
|
+
return "blocked";
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
return reconciled ? "reconciled" : "clean";
|
|
804
|
+
}
|
|
805
|
+
|
|
615
806
|
/**
|
|
616
807
|
* Detect leftover merge state from a prior session and reconcile it.
|
|
617
808
|
* If MERGE_HEAD or SQUASH_MSG exists, check whether conflicts are resolved.
|
|
@@ -622,11 +813,21 @@ export function reconcileMergeState(
|
|
|
622
813
|
basePath: string,
|
|
623
814
|
ctx: ExtensionContext,
|
|
624
815
|
): MergeReconcileResult {
|
|
816
|
+
// First, abort any rebase/cherry-pick/revert left over from a SIGKILL'd
|
|
817
|
+
// worker. Doing this before the merge-state check unblocks any merge that
|
|
818
|
+
// would otherwise refuse with "you have unfinished operation". (HIGH-7)
|
|
819
|
+
const otherOpsResult = reconcileOtherInProgressGitOps(basePath, ctx);
|
|
820
|
+
if (otherOpsResult === "blocked") return "blocked";
|
|
821
|
+
|
|
625
822
|
const mergeHeadPath = join(basePath, ".git", "MERGE_HEAD");
|
|
626
823
|
const squashMsgPath = join(basePath, ".git", "SQUASH_MSG");
|
|
627
824
|
const hasMergeHead = existsSync(mergeHeadPath);
|
|
628
825
|
const hasSquashMsg = existsSync(squashMsgPath);
|
|
629
|
-
if (!hasMergeHead && !hasSquashMsg)
|
|
826
|
+
if (!hasMergeHead && !hasSquashMsg) {
|
|
827
|
+
// If we cleaned up another op type, return "reconciled" so the caller
|
|
828
|
+
// re-derives state from a known-good baseline.
|
|
829
|
+
return otherOpsResult === "reconciled" ? "reconciled" : "clean";
|
|
830
|
+
}
|
|
630
831
|
|
|
631
832
|
const conflictedFiles = nativeConflictFiles(basePath);
|
|
632
833
|
if (conflictedFiles.length === 0) {
|
|
@@ -146,6 +146,35 @@ export async function openProjectDbIfPresent(basePath: string): Promise<void> {
|
|
|
146
146
|
*
|
|
147
147
|
* Returns a summary of actions taken for the caller to surface via notify.
|
|
148
148
|
*/
|
|
149
|
+
/**
|
|
150
|
+
* Decide which survivor-branch recovery action bootstrapAutoSession must
|
|
151
|
+
* run for the current (hasSurvivorBranch, phase) combination. Extracted
|
|
152
|
+
* from the inline chain at `bootstrapAutoSession` (around line 604) so
|
|
153
|
+
* the decision table is testable without constructing a full session.
|
|
154
|
+
*
|
|
155
|
+
* - `none` — no survivor, or phase doesn't call for recovery. Fall
|
|
156
|
+
* through to normal bootstrap flow.
|
|
157
|
+
* - `discuss` — survivor + phase=needs-discussion (#1726). Route to
|
|
158
|
+
* showSmartEntry.
|
|
159
|
+
* - `finalize` — survivor + phase=complete (#2358). Run mergeAndExit to
|
|
160
|
+
* merge the milestone branch and clear the worktree.
|
|
161
|
+
*
|
|
162
|
+
* Any other phase with a survivor (pre-planning, planning, executing…)
|
|
163
|
+
* returns `none` — the caller continues its normal flow and the
|
|
164
|
+
* survivor branch participates in whatever auto-mode happens next.
|
|
165
|
+
*/
|
|
166
|
+
export type SurvivorAction = "none" | "discuss" | "finalize";
|
|
167
|
+
|
|
168
|
+
export function decideSurvivorAction(
|
|
169
|
+
hasSurvivorBranch: boolean,
|
|
170
|
+
phase: string | null | undefined,
|
|
171
|
+
): SurvivorAction {
|
|
172
|
+
if (!hasSurvivorBranch) return "none";
|
|
173
|
+
if (phase === "needs-discussion") return "discuss";
|
|
174
|
+
if (phase === "complete") return "finalize";
|
|
175
|
+
return "none";
|
|
176
|
+
}
|
|
177
|
+
|
|
149
178
|
export function auditOrphanedMilestoneBranches(
|
|
150
179
|
basePath: string,
|
|
151
180
|
isolationMode: "worktree" | "branch" | "none",
|
|
@@ -575,7 +604,7 @@ export async function bootstrapAutoSession(
|
|
|
575
604
|
// The worktree/branch was created but the milestone only has CONTEXT-DRAFT.md.
|
|
576
605
|
// Route to the interactive discussion handler instead of falling through to
|
|
577
606
|
// auto-mode, which would immediately stop with "needs discussion".
|
|
578
|
-
if (hasSurvivorBranch
|
|
607
|
+
if (decideSurvivorAction(hasSurvivorBranch, state.phase) === "discuss") {
|
|
579
608
|
const { showSmartEntry } = await import("./guided-flow.js");
|
|
580
609
|
await showSmartEntry(ctx, pi, base, { step: requestedStepMode });
|
|
581
610
|
|
|
@@ -601,7 +630,9 @@ export async function bootstrapAutoSession(
|
|
|
601
630
|
// The milestone artifacts were written but finalization (merge, worktree
|
|
602
631
|
// cleanup) never ran. Run mergeAndExit to finalize, then re-derive state
|
|
603
632
|
// so the normal "all milestones complete" or "next milestone" path runs.
|
|
604
|
-
|
|
633
|
+
// Re-evaluate via the helper — the discuss branch above may have cleared
|
|
634
|
+
// hasSurvivorBranch after a successful promotion.
|
|
635
|
+
if (decideSurvivorAction(hasSurvivorBranch, state.phase) === "finalize") {
|
|
605
636
|
const mid = state.activeMilestone!.id;
|
|
606
637
|
ctx.ui.notify(
|
|
607
638
|
`Milestone ${mid} is complete but branch/worktree was not finalized. Running merge now.`,
|
|
@@ -971,17 +1002,34 @@ export async function bootstrapAutoSession(
|
|
|
971
1002
|
);
|
|
972
1003
|
}
|
|
973
1004
|
|
|
974
|
-
// Self-heal: remove stale .git/index.lock
|
|
1005
|
+
// Self-heal: remove stale .git/index.lock.
|
|
1006
|
+
//
|
|
1007
|
+
// Threshold raised from 60s → 5min because a 60s-old lock is not
|
|
1008
|
+
// definitively stale: `git gc --auto` triggered by a heavy commit, NFS
|
|
1009
|
+
// delays, or concurrent worktree writes can hold .git/index.lock for
|
|
1010
|
+
// minutes on large repos. Force-removing a live lock causes the holder
|
|
1011
|
+
// to encounter `fatal: Unable to create '.git/index.lock'` on its next
|
|
1012
|
+
// write, or worse, operate on a partially-written index → corruption
|
|
1013
|
+
// requiring `git fsck`/`git reset` to recover.
|
|
1014
|
+
// (Issue #4980 CRIT-3)
|
|
975
1015
|
try {
|
|
976
1016
|
const gitLockFile = join(base, ".git", "index.lock");
|
|
977
1017
|
if (existsSync(gitLockFile)) {
|
|
978
1018
|
const lockAge = Date.now() - statSync(gitLockFile).mtimeMs;
|
|
979
|
-
|
|
1019
|
+
const STALE_GIT_LOCK_THRESHOLD_MS = 5 * 60_000;
|
|
1020
|
+
if (lockAge > STALE_GIT_LOCK_THRESHOLD_MS) {
|
|
980
1021
|
unlinkSync(gitLockFile);
|
|
981
1022
|
ctx.ui.notify(
|
|
982
|
-
|
|
983
|
-
"
|
|
1023
|
+
`Removed stale .git/index.lock (age ${Math.round(lockAge / 1000)}s, > 5min threshold).`,
|
|
1024
|
+
"warning",
|
|
984
1025
|
);
|
|
1026
|
+
} else {
|
|
1027
|
+
// Lock present but not yet stale — surface so the user knows why
|
|
1028
|
+
// git ops may be queueing instead of silently waiting.
|
|
1029
|
+
debugLog("git-lock-present-not-stale", {
|
|
1030
|
+
ageMs: lockAge,
|
|
1031
|
+
thresholdMs: STALE_GIT_LOCK_THRESHOLD_MS,
|
|
1032
|
+
});
|
|
985
1033
|
}
|
|
986
1034
|
}
|
|
987
1035
|
} catch (e) {
|
|
@@ -87,20 +87,21 @@ export function clearInFlightTools(): void {
|
|
|
87
87
|
// ─── Tool invocation error classification (#2883) ────────────────────────
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
-
* Patterns that indicate a tool invocation failed
|
|
91
|
-
*
|
|
92
|
-
* handler. When these errors occur, retrying the same unit will
|
|
93
|
-
* failure, so the retry loop must be broken.
|
|
90
|
+
* Patterns that indicate a tool invocation failed deterministically before
|
|
91
|
+
* useful work could be completed — as opposed to a normal business-logic error
|
|
92
|
+
* from the tool handler. When these errors occur, retrying the same unit will
|
|
93
|
+
* produce the same failure, so the retry loop must be broken.
|
|
94
94
|
*/
|
|
95
95
|
const TOOL_INVOCATION_ERROR_RE = /Validation failed for tool|Expected ',' or '\}'(?: after property value)?(?: in JSON)?|Unexpected end of JSON|Unexpected token.*in JSON/i;
|
|
96
|
+
const DETERMINISTIC_POLICY_ERROR_RE = /(?:^|\b)(?:HARD BLOCK:|Blocked: \/gsd queue is a planning tool|Direct writes to \.gsd\/STATE\.md and \.gsd\/gsd\.db are blocked|This is a mechanical gate)/i;
|
|
96
97
|
|
|
97
98
|
/**
|
|
98
|
-
* Returns true if the error message indicates a
|
|
99
|
-
*
|
|
99
|
+
* Returns true if the error message indicates a deterministic invocation or
|
|
100
|
+
* policy failure (as opposed to a normal tool execution error).
|
|
100
101
|
*/
|
|
101
102
|
export function isToolInvocationError(errorMsg: string): boolean {
|
|
102
103
|
if (!errorMsg) return false;
|
|
103
|
-
return TOOL_INVOCATION_ERROR_RE.test(errorMsg);
|
|
104
|
+
return TOOL_INVOCATION_ERROR_RE.test(errorMsg) || isDeterministicPolicyError(errorMsg);
|
|
104
105
|
}
|
|
105
106
|
|
|
106
107
|
/**
|
|
@@ -112,3 +113,46 @@ export function isQueuedUserMessageSkip(errorMsg: string): boolean {
|
|
|
112
113
|
if (!errorMsg) return false;
|
|
113
114
|
return /^Skipped due to queued user message\.?$/i.test(errorMsg.trim());
|
|
114
115
|
}
|
|
116
|
+
|
|
117
|
+
// ─── Deterministic policy error classification (#4973, #4974) ──────────────
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Known deterministic policy error substrings. Each entry is a stable string
|
|
121
|
+
* that will appear in the tool error text content when the corresponding
|
|
122
|
+
* policy gate fires. Retrying these errors will always produce the same outcome.
|
|
123
|
+
*
|
|
124
|
+
* Add new entries here as new deterministic gates are introduced. Do NOT use
|
|
125
|
+
* regex — explicit substrings keep the list auditable.
|
|
126
|
+
*/
|
|
127
|
+
export const DETERMINISTIC_POLICY_ERROR_STRINGS = [
|
|
128
|
+
// gsd_summary_save write-gate: CONTEXT artifact blocked pending depth verification (#4973).
|
|
129
|
+
// Matches the fallback text in workflow-tool-executors.ts and the verbose reason
|
|
130
|
+
// from shouldBlockContextArtifactSaveInSnapshot at write-gate.ts:432-442.
|
|
131
|
+
"context write blocked",
|
|
132
|
+
"CONTEXT without depth verification",
|
|
133
|
+
// Raw write tool gate (#4973): shouldBlockContextWrite at write-gate.ts:390-399 emits
|
|
134
|
+
// "Cannot write to milestone CONTEXT.md without depth verification." for direct
|
|
135
|
+
// write tool calls to *-CONTEXT.md paths (different code path than gsd_summary_save).
|
|
136
|
+
"CONTEXT.md without depth verification",
|
|
137
|
+
] as const;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Returns true if the error message indicates a deterministic policy gate
|
|
141
|
+
* blocked the tool call before execution. Retrying the same unit without
|
|
142
|
+
* changing behavior will hit the same gate, so auto-mode should pause instead
|
|
143
|
+
* of re-dispatching.
|
|
144
|
+
*
|
|
145
|
+
* Combines the regex-based gate set from #4974 (HARD BLOCK / queue planning /
|
|
146
|
+
* STATE.md / mechanical gate) and the substring-based set from #4973 (context
|
|
147
|
+
* write block / CONTEXT depth verification). Both branches landed on main
|
|
148
|
+
* independently and their parallel `isDeterministicPolicyError` declarations
|
|
149
|
+
* were not deduplicated at merge — this consolidated form preserves both
|
|
150
|
+
* matchers under a single export.
|
|
151
|
+
*/
|
|
152
|
+
export function isDeterministicPolicyError(errorMsg: string): boolean {
|
|
153
|
+
if (!errorMsg) return false;
|
|
154
|
+
return (
|
|
155
|
+
DETERMINISTIC_POLICY_ERROR_RE.test(errorMsg) ||
|
|
156
|
+
DETERMINISTIC_POLICY_ERROR_STRINGS.some(s => errorMsg.includes(s))
|
|
157
|
+
);
|
|
158
|
+
}
|