gsd-pi 2.81.0 → 2.82.0
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 +36 -24
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/loop.js +111 -8
- package/dist/resources/extensions/gsd/auto/phases.js +190 -97
- package/dist/resources/extensions/gsd/auto/run-unit.js +66 -3
- package/dist/resources/extensions/gsd/auto/session.js +9 -0
- package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +182 -178
- package/dist/resources/extensions/gsd/auto-dispatch.js +14 -11
- package/dist/resources/extensions/gsd/auto-post-unit.js +7 -1
- package/dist/resources/extensions/gsd/auto-recovery.js +6 -181
- package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
- package/dist/resources/extensions/gsd/auto-start.js +20 -23
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
- package/dist/resources/extensions/gsd/auto-verification.js +12 -6
- package/dist/resources/extensions/gsd/auto-worktree.js +8 -0
- package/dist/resources/extensions/gsd/auto.js +265 -76
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +13 -6
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +8 -2
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
- package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +9 -0
- package/dist/resources/extensions/gsd/git-service.js +2 -1
- package/dist/resources/extensions/gsd/gsd-db.js +7 -23
- package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
- package/dist/resources/extensions/gsd/health-widget.js +4 -10
- package/dist/resources/extensions/gsd/markdown-renderer.js +0 -95
- package/dist/resources/extensions/gsd/native-git-bridge.js +14 -14
- package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
- package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
- package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
- package/dist/resources/extensions/gsd/recovery-classification.js +15 -1
- package/dist/resources/extensions/gsd/session-lock.js +40 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +131 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +247 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +50 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +87 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +50 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +124 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +32 -0
- package/dist/resources/extensions/gsd/state-reconciliation/errors.js +41 -0
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +99 -0
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +24 -0
- package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +43 -0
- package/dist/resources/extensions/gsd/state-reconciliation/types.js +3 -0
- package/dist/resources/extensions/gsd/state-reconciliation.js +5 -26
- package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
- package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
- package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +722 -316
- package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
- 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 +9 -9
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- 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/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 +9 -9
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/welcome-screen.d.ts +0 -7
- package/dist/welcome-screen.js +60 -69
- package/package.json +1 -1
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/package.json +2 -2
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
- 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/__tests__/user-message-design.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -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 +86 -82
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
- package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.js +9 -6
- package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
- package/packages/pi-tui/src/overlay-layout.ts +10 -7
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +105 -1
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +27 -26
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
- package/src/resources/extensions/gsd/auto/loop.ts +113 -9
- package/src/resources/extensions/gsd/auto/phases.ts +144 -19
- package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
- package/src/resources/extensions/gsd/auto/session.ts +10 -0
- package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +230 -183
- package/src/resources/extensions/gsd/auto-dispatch.ts +15 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +7 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +7 -209
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +22 -22
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
- package/src/resources/extensions/gsd/auto-verification.ts +12 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +8 -0
- package/src/resources/extensions/gsd/auto.ts +295 -75
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -6
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -2
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
- package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
- package/src/resources/extensions/gsd/git-service.ts +2 -0
- package/src/resources/extensions/gsd/gsd-db.ts +7 -23
- package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
- package/src/resources/extensions/gsd/health-widget.ts +6 -10
- package/src/resources/extensions/gsd/journal.ts +2 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +4 -95
- package/src/resources/extensions/gsd/native-git-bridge.ts +14 -13
- package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
- package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
- package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
- package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
- package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
- package/src/resources/extensions/gsd/session-lock.ts +41 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +337 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +69 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +109 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
- package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
- package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
- package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +654 -176
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +291 -4
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +20 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
- package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -58
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +952 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +158 -58
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +572 -118
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
- package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
- package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
- package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +1151 -524
- package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
- /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → S44UQTFCUdA44dkjfYt6S}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → S44UQTFCUdA44dkjfYt6S}/_ssgManifest.js +0 -0
|
@@ -83,6 +83,7 @@ import {
|
|
|
83
83
|
finalizeProjectResearchTimeout,
|
|
84
84
|
} from "./project-research-policy.js";
|
|
85
85
|
import { validateArtifact } from "./schemas/validate.js";
|
|
86
|
+
import { verificationRetryKey } from "./auto/verification-retry-policy.js";
|
|
86
87
|
|
|
87
88
|
// ─── Path Comparison Helper ───────────────────────────────────────────────
|
|
88
89
|
/** Compare two paths for physical identity, tolerating trailing slashes and symlinks. */
|
|
@@ -1016,6 +1017,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
1016
1017
|
);
|
|
1017
1018
|
s.pendingVerificationRetry = null;
|
|
1018
1019
|
s.verificationRetryCount.delete(retryKey);
|
|
1020
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
1019
1021
|
triggerArtifactVerified = verifyExpectedArtifact(s.currentUnit.type, s.currentUnit.id, s.basePath);
|
|
1020
1022
|
if (triggerArtifactVerified) {
|
|
1021
1023
|
invalidateAllCaches();
|
|
@@ -1074,6 +1076,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
1074
1076
|
s.lastToolInvocationError = null;
|
|
1075
1077
|
s.pendingVerificationRetry = null;
|
|
1076
1078
|
s.verificationRetryCount.delete(retryKey);
|
|
1079
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
1077
1080
|
writeBlockerPlaceholder(s.currentUnit.type, s.currentUnit.id, s.basePath, reason);
|
|
1078
1081
|
ctx.ui.notify(
|
|
1079
1082
|
`${s.currentUnit.type} ${s.currentUnit.id} — deterministic policy rejection, wrote blocker placeholder (no retries) (#4973)`,
|
|
@@ -1111,6 +1114,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
1111
1114
|
);
|
|
1112
1115
|
if (attempt > MAX_ARTIFACT_VERIFICATION_RETRIES) {
|
|
1113
1116
|
s.verificationRetryCount.delete(retryKey);
|
|
1117
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
1114
1118
|
debugLog("postUnit", { phase: "artifact-verify-exhausted", unitType: s.currentUnit.type, unitId: s.currentUnit.id, attempt });
|
|
1115
1119
|
ctx.ui.notify(
|
|
1116
1120
|
`${failureDetails} Pausing auto-mode after ${MAX_ARTIFACT_VERIFICATION_RETRIES} retries.`,
|
|
@@ -1137,7 +1141,9 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|
|
1137
1141
|
// Verification succeeded — clear the retry counter so a future failure
|
|
1138
1142
|
// of the same unit gets a full retry budget instead of the stale count.
|
|
1139
1143
|
if (triggerArtifactVerified) {
|
|
1140
|
-
|
|
1144
|
+
const retryKey = verificationRetryKey(s.currentUnit.type, s.currentUnit.id);
|
|
1145
|
+
s.verificationRetryCount.delete(retryKey);
|
|
1146
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
1141
1147
|
}
|
|
1142
1148
|
} else {
|
|
1143
1149
|
// Hook unit completed — no additional processing needed
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
* globals or AutoContext dependency.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import type { ExtensionContext } from "@gsd/pi-coding-agent";
|
|
11
10
|
import { parseUnitId } from "./unit-id.js";
|
|
12
11
|
import { MILESTONE_ID_RE } from "./milestone-ids.js";
|
|
13
12
|
import { appendEvent } from "./workflow-events.js";
|
|
@@ -20,15 +19,6 @@ import { getErrorMessage } from "./error-utils.js";
|
|
|
20
19
|
import { logWarning, logError } from "./workflow-logger.js";
|
|
21
20
|
import { readIntegrationBranch } from "./git-service.js";
|
|
22
21
|
import { isClosedStatus } from "./status-guards.js";
|
|
23
|
-
import {
|
|
24
|
-
nativeConflictFiles,
|
|
25
|
-
nativeCommit,
|
|
26
|
-
nativeCheckoutTheirs,
|
|
27
|
-
nativeAddPaths,
|
|
28
|
-
nativeMergeAbort,
|
|
29
|
-
nativeRebaseAbort,
|
|
30
|
-
nativeResetHard,
|
|
31
|
-
} from "./native-git-bridge.js";
|
|
32
22
|
import {
|
|
33
23
|
resolveSlicePath,
|
|
34
24
|
resolveSliceFile,
|
|
@@ -46,7 +36,6 @@ import {
|
|
|
46
36
|
mkdirSync,
|
|
47
37
|
readFileSync,
|
|
48
38
|
writeFileSync,
|
|
49
|
-
unlinkSync,
|
|
50
39
|
} from "node:fs";
|
|
51
40
|
import { execFileSync } from "node:child_process";
|
|
52
41
|
import { dirname, join } from "node:path";
|
|
@@ -1001,205 +990,14 @@ export function writeBlockerPlaceholder(
|
|
|
1001
990
|
}
|
|
1002
991
|
|
|
1003
992
|
// ─── Merge State Reconciliation ───────────────────────────────────────────────
|
|
993
|
+
// Body relocated to state-reconciliation/drift/merge-state.ts (ADR-017 #5701).
|
|
994
|
+
// Re-exported here for backward compatibility with existing call sites:
|
|
995
|
+
// auto.ts, auto/loop-deps.ts, tests/integration/auto-recovery.test.ts.
|
|
1004
996
|
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
function abortAndResetMerge(
|
|
1010
|
-
basePath: string,
|
|
1011
|
-
hasMergeHead: boolean,
|
|
1012
|
-
squashMsgPath: string,
|
|
1013
|
-
): void {
|
|
1014
|
-
if (hasMergeHead) {
|
|
1015
|
-
try {
|
|
1016
|
-
nativeMergeAbort(basePath);
|
|
1017
|
-
} catch (err) {
|
|
1018
|
-
/* best-effort */
|
|
1019
|
-
logWarning("recovery", `git merge-abort failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1020
|
-
}
|
|
1021
|
-
} else if (squashMsgPath) {
|
|
1022
|
-
try {
|
|
1023
|
-
unlinkSync(squashMsgPath);
|
|
1024
|
-
} catch (err) {
|
|
1025
|
-
/* best-effort */
|
|
1026
|
-
logWarning("recovery", `file unlink failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
try {
|
|
1030
|
-
nativeResetHard(basePath);
|
|
1031
|
-
} catch (err) {
|
|
1032
|
-
/* best-effort */
|
|
1033
|
-
logError("recovery", `git reset failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1034
|
-
}
|
|
1035
|
-
}
|
|
1036
|
-
|
|
1037
|
-
export type MergeReconcileResult = "clean" | "reconciled" | "blocked";
|
|
1038
|
-
|
|
1039
|
-
/**
|
|
1040
|
-
* Detect and abort other in-progress git operations left behind by a SIGKILL'd
|
|
1041
|
-
* worker (rebase, cherry-pick, revert). Without this, a killed worker mid-rebase
|
|
1042
|
-
* leaves `.git/rebase-merge/` or `.git/CHERRY_PICK_HEAD` and the worktree is
|
|
1043
|
-
* wedged until the user manually runs the matching `--abort`.
|
|
1044
|
-
*
|
|
1045
|
-
* Called before merge-state reconciliation because these states block any
|
|
1046
|
-
* subsequent merge/commit operation. (Issue #4980 HIGH-7)
|
|
1047
|
-
*/
|
|
1048
|
-
function reconcileOtherInProgressGitOps(
|
|
1049
|
-
basePath: string,
|
|
1050
|
-
ctx: ExtensionContext,
|
|
1051
|
-
): "clean" | "reconciled" | "blocked" {
|
|
1052
|
-
const gitDir = join(basePath, ".git");
|
|
1053
|
-
const states: Array<{
|
|
1054
|
-
label: string;
|
|
1055
|
-
indicators: string[];
|
|
1056
|
-
abort: () => void;
|
|
1057
|
-
}> = [
|
|
1058
|
-
{
|
|
1059
|
-
label: "rebase",
|
|
1060
|
-
indicators: [join(gitDir, "rebase-merge"), join(gitDir, "rebase-apply")],
|
|
1061
|
-
abort: () => nativeRebaseAbort(basePath),
|
|
1062
|
-
},
|
|
1063
|
-
{
|
|
1064
|
-
label: "cherry-pick",
|
|
1065
|
-
indicators: [join(gitDir, "CHERRY_PICK_HEAD")],
|
|
1066
|
-
abort: () => {
|
|
1067
|
-
// No native helper; fall back to git CLI.
|
|
1068
|
-
try {
|
|
1069
|
-
execFileSync("git", ["cherry-pick", "--abort"], {
|
|
1070
|
-
cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8",
|
|
1071
|
-
});
|
|
1072
|
-
} catch (err) { logWarning("recovery", `cherry-pick --abort failed: ${getErrorMessage(err)}`); }
|
|
1073
|
-
},
|
|
1074
|
-
},
|
|
1075
|
-
{
|
|
1076
|
-
label: "revert",
|
|
1077
|
-
indicators: [join(gitDir, "REVERT_HEAD")],
|
|
1078
|
-
abort: () => {
|
|
1079
|
-
try {
|
|
1080
|
-
execFileSync("git", ["revert", "--abort"], {
|
|
1081
|
-
cwd: basePath, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8",
|
|
1082
|
-
});
|
|
1083
|
-
} catch (err) { logWarning("recovery", `revert --abort failed: ${getErrorMessage(err)}`); }
|
|
1084
|
-
},
|
|
1085
|
-
},
|
|
1086
|
-
];
|
|
1087
|
-
|
|
1088
|
-
let reconciled = false;
|
|
1089
|
-
for (const s of states) {
|
|
1090
|
-
const present = s.indicators.some((p) => existsSync(p));
|
|
1091
|
-
if (!present) continue;
|
|
1092
|
-
try {
|
|
1093
|
-
s.abort();
|
|
1094
|
-
ctx.ui.notify(
|
|
1095
|
-
`Detected leftover ${s.label} state from prior session — aborted.`,
|
|
1096
|
-
"warning",
|
|
1097
|
-
);
|
|
1098
|
-
reconciled = true;
|
|
1099
|
-
} catch (err) {
|
|
1100
|
-
logError("recovery", `${s.label} abort failed: ${getErrorMessage(err)}`);
|
|
1101
|
-
ctx.ui.notify(
|
|
1102
|
-
`Detected leftover ${s.label} state but auto-abort failed. ` +
|
|
1103
|
-
`Run \`git ${s.label} --abort\` manually before retrying.`,
|
|
1104
|
-
"error",
|
|
1105
|
-
);
|
|
1106
|
-
return "blocked";
|
|
1107
|
-
}
|
|
1108
|
-
}
|
|
1109
|
-
return reconciled ? "reconciled" : "clean";
|
|
1110
|
-
}
|
|
1111
|
-
|
|
1112
|
-
/**
|
|
1113
|
-
* Detect leftover merge state from a prior session and reconcile it.
|
|
1114
|
-
* If MERGE_HEAD or SQUASH_MSG exists, check whether conflicts are resolved.
|
|
1115
|
-
* If resolved: finalize the commit. If only .gsd conflicts remain: auto-resolve.
|
|
1116
|
-
* If code conflicts remain: fail safe without modifying the worktree.
|
|
1117
|
-
*/
|
|
1118
|
-
export function reconcileMergeState(
|
|
1119
|
-
basePath: string,
|
|
1120
|
-
ctx: ExtensionContext,
|
|
1121
|
-
): MergeReconcileResult {
|
|
1122
|
-
// First, abort any rebase/cherry-pick/revert left over from a SIGKILL'd
|
|
1123
|
-
// worker. Doing this before the merge-state check unblocks any merge that
|
|
1124
|
-
// would otherwise refuse with "you have unfinished operation". (HIGH-7)
|
|
1125
|
-
const otherOpsResult = reconcileOtherInProgressGitOps(basePath, ctx);
|
|
1126
|
-
if (otherOpsResult === "blocked") return "blocked";
|
|
1127
|
-
|
|
1128
|
-
const mergeHeadPath = join(basePath, ".git", "MERGE_HEAD");
|
|
1129
|
-
const squashMsgPath = join(basePath, ".git", "SQUASH_MSG");
|
|
1130
|
-
const hasMergeHead = existsSync(mergeHeadPath);
|
|
1131
|
-
const hasSquashMsg = existsSync(squashMsgPath);
|
|
1132
|
-
if (!hasMergeHead && !hasSquashMsg) {
|
|
1133
|
-
// If we cleaned up another op type, return "reconciled" so the caller
|
|
1134
|
-
// re-derives state from a known-good baseline.
|
|
1135
|
-
return otherOpsResult === "reconciled" ? "reconciled" : "clean";
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
const conflictedFiles = nativeConflictFiles(basePath);
|
|
1139
|
-
if (conflictedFiles.length === 0) {
|
|
1140
|
-
// All conflicts resolved — finalize the merge/squash commit
|
|
1141
|
-
try {
|
|
1142
|
-
const commitSha = nativeCommit(basePath, "chore(gsd): reconcile merge state");
|
|
1143
|
-
if (commitSha) {
|
|
1144
|
-
const mode = hasMergeHead ? "merge" : "squash commit";
|
|
1145
|
-
ctx.ui.notify(`Finalized leftover ${mode} from prior session.`, "info");
|
|
1146
|
-
} else {
|
|
1147
|
-
ctx.ui.notify("No new commit needed for leftover merge/squash state — already committed.", "info");
|
|
1148
|
-
}
|
|
1149
|
-
} catch (err) {
|
|
1150
|
-
const errorMessage = getErrorMessage(err);
|
|
1151
|
-
ctx.ui.notify(`Failed to finalize leftover merge/squash commit: ${errorMessage}`, "error");
|
|
1152
|
-
return "blocked";
|
|
1153
|
-
}
|
|
1154
|
-
} else {
|
|
1155
|
-
// Still conflicted — try auto-resolving .gsd/ state file conflicts (#530)
|
|
1156
|
-
const gsdConflicts = conflictedFiles.filter((f) => f.startsWith(".gsd/"));
|
|
1157
|
-
const codeConflicts = conflictedFiles.filter((f) => !f.startsWith(".gsd/"));
|
|
1158
|
-
|
|
1159
|
-
if (gsdConflicts.length > 0 && codeConflicts.length === 0) {
|
|
1160
|
-
// All conflicts are in .gsd/ state files — auto-resolve by accepting theirs
|
|
1161
|
-
let resolved = true;
|
|
1162
|
-
try {
|
|
1163
|
-
nativeCheckoutTheirs(basePath, gsdConflicts);
|
|
1164
|
-
nativeAddPaths(basePath, gsdConflicts);
|
|
1165
|
-
} catch (e) {
|
|
1166
|
-
logError("recovery", `auto-resolve .gsd/ conflicts failed: ${(e as Error).message}`);
|
|
1167
|
-
resolved = false;
|
|
1168
|
-
}
|
|
1169
|
-
if (resolved) {
|
|
1170
|
-
try {
|
|
1171
|
-
nativeCommit(
|
|
1172
|
-
basePath,
|
|
1173
|
-
"chore: auto-resolve .gsd/ state file conflicts",
|
|
1174
|
-
);
|
|
1175
|
-
ctx.ui.notify(
|
|
1176
|
-
`Auto-resolved ${gsdConflicts.length} .gsd/ state file conflict(s) from prior merge.`,
|
|
1177
|
-
"info",
|
|
1178
|
-
);
|
|
1179
|
-
} catch (e) {
|
|
1180
|
-
logError("recovery", `auto-commit .gsd/ conflict resolution failed: ${(e as Error).message}`);
|
|
1181
|
-
resolved = false;
|
|
1182
|
-
}
|
|
1183
|
-
}
|
|
1184
|
-
if (!resolved) {
|
|
1185
|
-
abortAndResetMerge(basePath, hasMergeHead, squashMsgPath);
|
|
1186
|
-
ctx.ui.notify(
|
|
1187
|
-
"Detected leftover merge state — auto-resolve failed, cleaned up. Re-deriving state.",
|
|
1188
|
-
"warning",
|
|
1189
|
-
);
|
|
1190
|
-
}
|
|
1191
|
-
} else {
|
|
1192
|
-
// Code conflicts present — fail safe and preserve any manual resolution
|
|
1193
|
-
// work instead of discarding it with merge --abort/reset --hard.
|
|
1194
|
-
ctx.ui.notify(
|
|
1195
|
-
"Detected leftover merge state with unresolved code conflicts. Auto-mode will pause without modifying the worktree so manual conflict resolution is preserved.",
|
|
1196
|
-
"error",
|
|
1197
|
-
);
|
|
1198
|
-
return "blocked";
|
|
1199
|
-
}
|
|
1200
|
-
}
|
|
1201
|
-
return "reconciled";
|
|
1202
|
-
}
|
|
997
|
+
export {
|
|
998
|
+
reconcileMergeState,
|
|
999
|
+
type MergeReconcileResult,
|
|
1000
|
+
} from "./state-reconciliation/drift/merge-state.js";
|
|
1203
1001
|
|
|
1204
1002
|
// ─── Loop Remediation ─────────────────────────────────────────────────────────
|
|
1205
1003
|
|
|
@@ -56,3 +56,8 @@ export function recordToolInvocationError(toolName: string, errorMsg: string): v
|
|
|
56
56
|
autoSession.lastToolInvocationError = `${toolName}: ${errorMsg}`;
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
export function clearToolInvocationError(): void {
|
|
61
|
+
if (!autoSession.active) return;
|
|
62
|
+
autoSession.lastToolInvocationError = null;
|
|
63
|
+
}
|
|
@@ -904,29 +904,24 @@ export async function bootstrapAutoSession(
|
|
|
904
904
|
{
|
|
905
905
|
const orphan = findUnmergedCompletedMilestone(base, getIsolationMode(base));
|
|
906
906
|
if (orphan && orphan !== state.activeMilestone?.id) {
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
s.originalBasePath
|
|
910
|
-
|
|
911
|
-
|
|
907
|
+
// ADR-016 phase 2 / B4 (#5622): the swap-run-revert protocol for
|
|
908
|
+
// the orphan-merge dance is owned by `adoptOrphanWorktree`. The
|
|
909
|
+
// verb snapshots prior `s.basePath` / `s.originalBasePath`, swaps
|
|
910
|
+
// into the orphan worktree, runs the merge callback under the
|
|
911
|
+
// swap, and reverts (or holds the swap) based on the result.
|
|
912
|
+
// Callers can no longer forget the revert step on failure — the
|
|
913
|
+
// pattern that originally motivated this verb.
|
|
914
|
+
const lifecycle = buildLifecycle();
|
|
915
|
+
const result = lifecycle.adoptOrphanWorktree(orphan, base, () =>
|
|
916
|
+
_mergeOrphanCompletedMilestone(lifecycle, orphan, ctx.ui),
|
|
917
|
+
);
|
|
912
918
|
if (!result.merged) {
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
try {
|
|
916
|
-
process.chdir(base);
|
|
917
|
-
} catch (err) {
|
|
918
|
-
logWarning("bootstrap", `could not restore cwd after orphan merge failure: ${err instanceof Error ? err.message : String(err)}`);
|
|
919
|
-
}
|
|
919
|
+
// Verb already restored basePath/originalBasePath to `base` and
|
|
920
|
+
// chdir'd there. Return early.
|
|
920
921
|
return releaseLockAndReturn();
|
|
921
922
|
}
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
s.originalBasePath = priorOriginalBasePath || base;
|
|
925
|
-
}
|
|
926
|
-
if (result.merged) {
|
|
927
|
-
invalidateAllCaches();
|
|
928
|
-
state = await deriveState(base);
|
|
929
|
-
}
|
|
923
|
+
invalidateAllCaches();
|
|
924
|
+
state = await deriveState(base);
|
|
930
925
|
}
|
|
931
926
|
}
|
|
932
927
|
|
|
@@ -1040,7 +1035,10 @@ export async function bootstrapAutoSession(
|
|
|
1040
1035
|
s.stepMode = requestedStepMode;
|
|
1041
1036
|
s.verbose = verboseMode;
|
|
1042
1037
|
s.cmdCtx = ctx;
|
|
1043
|
-
|
|
1038
|
+
// ADR-016 phase 2 / B2 (#5620): single owner of bootstrap basePath
|
|
1039
|
+
// mutation. Sets s.basePath = base and s.originalBasePath = base
|
|
1040
|
+
// (originalBasePath is empty on a fresh bootstrap).
|
|
1041
|
+
buildLifecycle().adoptSessionRoot(base);
|
|
1044
1042
|
s.unitDispatchCount.clear();
|
|
1045
1043
|
s.unitRecoveryCount.clear();
|
|
1046
1044
|
s.lastBudgetAlertLevel = 0;
|
|
@@ -1098,7 +1096,9 @@ export async function bootstrapAutoSession(
|
|
|
1098
1096
|
}
|
|
1099
1097
|
|
|
1100
1098
|
// ── Auto-worktree setup ──
|
|
1101
|
-
s.originalBasePath
|
|
1099
|
+
// s.originalBasePath was set to `base` by `adoptSessionRoot(base)` above
|
|
1100
|
+
// (ADR-016 phase 2 / B2, #5620). The redundant assignment that used to
|
|
1101
|
+
// live here is gone.
|
|
1102
1102
|
|
|
1103
1103
|
const isUnderGsdWorktrees = (p: string): boolean => {
|
|
1104
1104
|
// Direct layout: /.gsd/worktrees/
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Auto-mode unit closeout metrics, activity capture, and ghost-run detection.
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Unit closeout helper — consolidates the repeated pattern of
|
|
3
6
|
* snapshotting metrics + saving activity log + extracting memories
|
|
@@ -24,6 +27,54 @@ export interface CloseoutOptions {
|
|
|
24
27
|
gitError?: string;
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
export interface UnitActivitySnapshot {
|
|
31
|
+
elapsedMs: number;
|
|
32
|
+
toolCalls: number;
|
|
33
|
+
assistantMessages: number;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export const GHOST_COMPLETION_MAX_ELAPSED_MS = 500;
|
|
37
|
+
|
|
38
|
+
export function snapshotUnitActivity(
|
|
39
|
+
ctx: ExtensionContext,
|
|
40
|
+
startedAt: number,
|
|
41
|
+
now = Date.now(),
|
|
42
|
+
): UnitActivitySnapshot {
|
|
43
|
+
let toolCalls = 0;
|
|
44
|
+
let assistantMessages = 0;
|
|
45
|
+
const entries = ctx.sessionManager.getEntries() ?? [];
|
|
46
|
+
|
|
47
|
+
for (const entry of entries) {
|
|
48
|
+
if (entry.type !== "message") continue;
|
|
49
|
+
const msg = (entry as any).message;
|
|
50
|
+
if (!msg || msg.role !== "assistant") continue;
|
|
51
|
+
assistantMessages++;
|
|
52
|
+
if (!Array.isArray(msg.content)) continue;
|
|
53
|
+
for (const block of msg.content) {
|
|
54
|
+
if (block?.type === "toolCall") toolCalls++;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
elapsedMs: Math.max(0, now - startedAt),
|
|
60
|
+
toolCalls,
|
|
61
|
+
assistantMessages,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function isSuspiciousGhostCompletion(
|
|
66
|
+
ctx: ExtensionContext,
|
|
67
|
+
startedAt: number,
|
|
68
|
+
maxElapsedMs = GHOST_COMPLETION_MAX_ELAPSED_MS,
|
|
69
|
+
): boolean {
|
|
70
|
+
const activity = snapshotUnitActivity(ctx, startedAt);
|
|
71
|
+
return (
|
|
72
|
+
activity.elapsedMs < maxElapsedMs &&
|
|
73
|
+
activity.toolCalls === 0 &&
|
|
74
|
+
activity.assistantMessages === 0
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
27
78
|
/**
|
|
28
79
|
* Snapshot metrics, save activity log, and fire-and-forget memory extraction
|
|
29
80
|
* for a completed unit. Returns the activity log file path (if any).
|
|
@@ -39,6 +39,7 @@ import type { VerificationResult as VerificationGateResult } from "./types.js";
|
|
|
39
39
|
import { join } from "node:path";
|
|
40
40
|
import { resolveUokFlags } from "./uok/flags.js";
|
|
41
41
|
import { UokGateRunner } from "./uok/gate-runner.js";
|
|
42
|
+
import { verificationRetryKey } from "./auto/verification-retry-policy.js";
|
|
42
43
|
|
|
43
44
|
export interface VerificationContext {
|
|
44
45
|
s: AutoSession;
|
|
@@ -331,7 +332,8 @@ export async function runPostUnitVerification(
|
|
|
331
332
|
}
|
|
332
333
|
|
|
333
334
|
// Write verification evidence JSON
|
|
334
|
-
const
|
|
335
|
+
const retryKey = verificationRetryKey(s.currentUnit.type, s.currentUnit.id);
|
|
336
|
+
const attempt = s.verificationRetryCount.get(retryKey) ?? 0;
|
|
335
337
|
if (mid && sid && tid) {
|
|
336
338
|
try {
|
|
337
339
|
const sDir = resolveSlicePath(s.basePath, mid, sid);
|
|
@@ -364,7 +366,8 @@ export async function runPostUnitVerification(
|
|
|
364
366
|
));
|
|
365
367
|
|
|
366
368
|
if (advisoryFailure) {
|
|
367
|
-
s.verificationRetryCount.delete(
|
|
369
|
+
s.verificationRetryCount.delete(retryKey);
|
|
370
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
368
371
|
s.pendingVerificationRetry = null;
|
|
369
372
|
ctx.ui.notify(
|
|
370
373
|
result.discoverySource === "package-json"
|
|
@@ -565,13 +568,15 @@ export async function runPostUnitVerification(
|
|
|
565
568
|
|
|
566
569
|
// ── Auto-fix retry logic ──
|
|
567
570
|
if (result.passed) {
|
|
568
|
-
s.verificationRetryCount.delete(
|
|
571
|
+
s.verificationRetryCount.delete(retryKey);
|
|
572
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
569
573
|
s.pendingVerificationRetry = null;
|
|
570
574
|
return "continue";
|
|
571
575
|
} else if (postExecBlockingFailure) {
|
|
572
576
|
// Post-execution failures are cross-task consistency issues — retrying the same task won't fix them.
|
|
573
577
|
// Skip retry and pause immediately for human review.
|
|
574
|
-
s.verificationRetryCount.delete(
|
|
578
|
+
s.verificationRetryCount.delete(retryKey);
|
|
579
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
575
580
|
s.pendingVerificationRetry = null;
|
|
576
581
|
ctx.ui.notify(
|
|
577
582
|
`Post-execution checks failed — cross-task consistency issue detected, pausing for human review`,
|
|
@@ -581,7 +586,7 @@ export async function runPostUnitVerification(
|
|
|
581
586
|
return "pause";
|
|
582
587
|
} else if (autoFixEnabled && attempt + 1 <= maxRetries) {
|
|
583
588
|
const nextAttempt = attempt + 1;
|
|
584
|
-
s.verificationRetryCount.set(
|
|
589
|
+
s.verificationRetryCount.set(retryKey, nextAttempt);
|
|
585
590
|
s.pendingVerificationRetry = {
|
|
586
591
|
unitId: s.currentUnit.id,
|
|
587
592
|
failureContext: formatFailureContext(result),
|
|
@@ -601,7 +606,8 @@ export async function runPostUnitVerification(
|
|
|
601
606
|
return "retry";
|
|
602
607
|
} else {
|
|
603
608
|
// Gate failed, retries exhausted
|
|
604
|
-
s.verificationRetryCount.delete(
|
|
609
|
+
s.verificationRetryCount.delete(retryKey);
|
|
610
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
605
611
|
s.pendingVerificationRetry = null;
|
|
606
612
|
const exhaustedFails = result.checks
|
|
607
613
|
.filter((c) => c.exitCode !== 0)
|
|
@@ -1502,6 +1502,14 @@ function autoCommitDirtyState(cwd: string): boolean {
|
|
|
1502
1502
|
* On merge conflict: throws MergeConflictError.
|
|
1503
1503
|
* On "nothing to commit" after squash: safe only if milestone work is already
|
|
1504
1504
|
* on the integration branch. Throws if unanchored code changes would be lost.
|
|
1505
|
+
*
|
|
1506
|
+
* @internal **Do not call directly.** This is the inner squash-merge primitive
|
|
1507
|
+
* for the Worktree Lifecycle Module (ADR-016 phase 2 / A3, issue #5619).
|
|
1508
|
+
* Production callers must go through `WorktreeLifecycle.mergeMilestoneStandalone`
|
|
1509
|
+
* or `WorktreeLifecycle.exitMilestone({ merge: true })`. The export keyword
|
|
1510
|
+
* is preserved only so `auto.ts:buildWorktreeLifecycleDeps()` can wire this
|
|
1511
|
+
* function through the Module's deps seam — that is the construction of the
|
|
1512
|
+
* seam, not a bypass.
|
|
1505
1513
|
*/
|
|
1506
1514
|
export function mergeMilestoneToMain(
|
|
1507
1515
|
originalBasePath_: string,
|