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
|
@@ -15,7 +15,7 @@ import { deriveState } from "./state.js";
|
|
|
15
15
|
import { parseUnitId } from "./unit-id.js";
|
|
16
16
|
import { assessInterruptedSession, readPausedSessionMetadata, PAUSED_SESSION_KV_KEY, } from "./interrupted-session.js";
|
|
17
17
|
import { setRuntimeKv, deleteRuntimeKv, } from "./db/runtime-kv.js";
|
|
18
|
-
import { getManifestStatus } from "./files.js";
|
|
18
|
+
import { extractSection, getManifestStatus, splitFrontmatter, parseFrontmatterMap } from "./files.js";
|
|
19
19
|
export { inlinePriorMilestoneSummary } from "./files.js";
|
|
20
20
|
import { collectSecretsFromManifest } from "../get-secrets-from-user.js";
|
|
21
21
|
import { gsdRoot, resolveMilestoneFile, resolveMilestonePath, resolveDir, milestonesDir, } from "./paths.js";
|
|
@@ -45,11 +45,10 @@ import { isAbsolute, join } from "node:path";
|
|
|
45
45
|
import { pathToFileURL } from "node:url";
|
|
46
46
|
import { readFileSync, existsSync, mkdirSync } from "node:fs";
|
|
47
47
|
import { atomicWriteSync } from "./atomic-write.js";
|
|
48
|
-
import {
|
|
48
|
+
import { captureIntegrationBranch, detectWorktreeName, getCurrentBranch, getMainBranch, setActiveMilestoneId, resolveProjectRoot, } from "./worktree.js";
|
|
49
49
|
import { GitServiceImpl } from "./git-service.js";
|
|
50
|
-
import { nativeCheckoutBranch } from "./native-git-bridge.js";
|
|
51
50
|
import { getPriorSliceCompletionBlocker } from "./dispatch-guard.js";
|
|
52
|
-
import { createAutoWorktree,
|
|
51
|
+
import { createAutoWorktree, teardownAutoWorktree, isInAutoWorktree, getAutoWorktreePath, mergeMilestoneToMain, autoWorktreeBranch, checkResourcesStale, escapeStaleWorktree, } from "./auto-worktree.js";
|
|
53
52
|
import { pruneQueueOrder } from "./queue-order.js";
|
|
54
53
|
import { startCommandPolling as _startCommandPolling, isRemoteConfigured } from "../remote-questions/manager.js";
|
|
55
54
|
import { debugLog, isDebugEnabled, writeDebugSummary } from "./debug-logger.js";
|
|
@@ -61,9 +60,9 @@ import { recoverFailedMigration } from "./migrate-external.js";
|
|
|
61
60
|
import { initRegistry, convertDispatchRules } from "./rule-registry.js";
|
|
62
61
|
import { emitJournalEvent as _emitJournalEvent } from "./journal.js";
|
|
63
62
|
import { isClosedStatus } from "./status-guards.js";
|
|
64
|
-
import { updateProgressWidget as _updateProgressWidget, updateSliceProgressCache, clearSliceProgressCache, } from "./auto-dashboard.js";
|
|
63
|
+
import { updateProgressWidget as _updateProgressWidget, setCompletionProgressWidget, setAutoOutcomeWidget, updateSliceProgressCache, clearSliceProgressCache, unitVerb, } from "./auto-dashboard.js";
|
|
65
64
|
import { registerSigtermHandler as _registerSigtermHandler, deregisterSigtermHandler as _deregisterSigtermHandler, } from "./auto-supervisor.js";
|
|
66
|
-
import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
65
|
+
import { isDbAvailable, getMilestone, getMilestoneSlices } from "./gsd-db.js";
|
|
67
66
|
import { markLatestActiveForWorkerCanceled } from "./db/unit-dispatches.js";
|
|
68
67
|
import { writeUnitRuntimeRecord } from "./unit-runtime.js";
|
|
69
68
|
import { countPendingCaptures } from "./captures.js";
|
|
@@ -253,11 +252,10 @@ function synthesizePausedSessionRecovery(basePath, unitType, unitId, sessionFile
|
|
|
253
252
|
export function _synthesizePausedSessionRecoveryForTest(basePath, unitType, unitId, sessionFile) {
|
|
254
253
|
return synthesizePausedSessionRecovery(basePath, unitType, unitId, sessionFile);
|
|
255
254
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
}
|
|
255
|
+
// `_resolvePausedResumeBasePathForTest` was retired in ADR-016 phase 2 / B3
|
|
256
|
+
// (#5621). Production callers go through
|
|
257
|
+
// `WorktreeLifecycle.resumeFromPausedSession`; the pure helper for tests is
|
|
258
|
+
// `resolvePausedResumeBasePath` exported from `worktree-lifecycle.ts`.
|
|
261
259
|
const DETACHED_AUTO_KEEPALIVE_INTERVAL_MS = 30_000;
|
|
262
260
|
function withDetachedAutoKeepalive(run) {
|
|
263
261
|
const keepAlive = setInterval(() => { }, DETACHED_AUTO_KEEPALIVE_INTERVAL_MS);
|
|
@@ -415,6 +413,9 @@ export function getAutoDashboardData() {
|
|
|
415
413
|
export function isAutoActive() {
|
|
416
414
|
return s.active;
|
|
417
415
|
}
|
|
416
|
+
export function isAutoCompletionStopInProgress() {
|
|
417
|
+
return s.completionStopInProgress;
|
|
418
|
+
}
|
|
418
419
|
/** Test-only seam for validating auto-mode guards (#4704). Do not use in production code. */
|
|
419
420
|
export function _setAutoActiveForTest(active) {
|
|
420
421
|
s.active = active;
|
|
@@ -611,6 +612,21 @@ function buildSnapshotOpts(_unitType, _unitId) {
|
|
|
611
612
|
...(s.currentUnitRouting ?? {}),
|
|
612
613
|
};
|
|
613
614
|
}
|
|
615
|
+
function currentUnitLabel() {
|
|
616
|
+
if (!s.currentUnit)
|
|
617
|
+
return null;
|
|
618
|
+
return `${unitVerb(s.currentUnit.type)} ${s.currentUnit.id}`;
|
|
619
|
+
}
|
|
620
|
+
function setLifecycleOutcome(ctx, input) {
|
|
621
|
+
if (!ctx?.hasUI)
|
|
622
|
+
return;
|
|
623
|
+
const { unitLabel: unitLabelOverride, ...rest } = input;
|
|
624
|
+
setAutoOutcomeWidget(ctx, {
|
|
625
|
+
...rest,
|
|
626
|
+
unitLabel: unitLabelOverride !== undefined ? unitLabelOverride : currentUnitLabel(),
|
|
627
|
+
startedAt: s.autoStartTime,
|
|
628
|
+
});
|
|
629
|
+
}
|
|
614
630
|
function handleLostSessionLock(ctx, lockStatus) {
|
|
615
631
|
debugLog("session-lock-lost", {
|
|
616
632
|
lockBase: lockBase(),
|
|
@@ -690,33 +706,84 @@ export async function cleanupAfterLoopExit(ctx) {
|
|
|
690
706
|
// visible so the user still has a resumable auto-mode signal on screen.
|
|
691
707
|
if (!s.paused) {
|
|
692
708
|
ctx.ui.setStatus("gsd-auto", undefined);
|
|
693
|
-
|
|
709
|
+
if (s.completionStopInProgress) {
|
|
710
|
+
s.completionStopInProgress = false;
|
|
711
|
+
}
|
|
694
712
|
initHealthWidget(ctx);
|
|
695
713
|
}
|
|
696
|
-
//
|
|
714
|
+
// ADR-016 phase 3 (#5693): the stop-path basePath restore routes through
|
|
715
|
+
// `Lifecycle.restoreToProjectRoot()`, the sole owner of `s.basePath`
|
|
716
|
+
// mutation. The verb assigns `s.basePath` before any throwable work
|
|
717
|
+
// (rebuildGitService, cache invalidation), so a thrown error still leaves
|
|
718
|
+
// basePath restored — no fallback assignment needed at the call site.
|
|
719
|
+
// The chdir stays here because `restoreToProjectRoot` is a pure
|
|
720
|
+
// session-state mutation.
|
|
697
721
|
if (s.originalBasePath) {
|
|
698
|
-
s.basePath = s.originalBasePath;
|
|
699
722
|
try {
|
|
700
|
-
|
|
723
|
+
buildLifecycle().restoreToProjectRoot();
|
|
701
724
|
}
|
|
702
725
|
catch (err) {
|
|
703
|
-
|
|
704
|
-
|
|
726
|
+
logWarning("engine", `restore project root failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
727
|
+
}
|
|
728
|
+
try {
|
|
729
|
+
process.chdir(s.originalBasePath);
|
|
730
|
+
}
|
|
731
|
+
catch (err) {
|
|
732
|
+
logWarning("engine", `basePath restore/chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
705
733
|
}
|
|
706
734
|
}
|
|
707
735
|
if (s.originalBasePath && s.cmdCtx) {
|
|
708
|
-
const result = await rerootCommandSession(s.cmdCtx, s.
|
|
736
|
+
const result = await rerootCommandSession(s.cmdCtx, s.originalBasePath);
|
|
709
737
|
if (result.status === "cancelled") {
|
|
710
|
-
logWarning("engine", "post-loop session re-root was cancelled", { file: "auto.ts", basePath: s.
|
|
738
|
+
logWarning("engine", "post-loop session re-root was cancelled", { file: "auto.ts", basePath: s.originalBasePath });
|
|
711
739
|
}
|
|
712
740
|
else if (result.status === "failed") {
|
|
713
|
-
logWarning("engine", `post-loop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.
|
|
741
|
+
logWarning("engine", `post-loop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.originalBasePath });
|
|
714
742
|
}
|
|
715
743
|
}
|
|
716
744
|
}
|
|
717
745
|
export function _cleanupAfterLoopExitForTest(ctx) {
|
|
718
746
|
return cleanupAfterLoopExit(ctx);
|
|
719
747
|
}
|
|
748
|
+
function normalizeFrontmatterList(value) {
|
|
749
|
+
if (!Array.isArray(value))
|
|
750
|
+
return [];
|
|
751
|
+
return value
|
|
752
|
+
.map(item => typeof item === "string" ? item.trim() : "")
|
|
753
|
+
.filter(item => item.length > 0 && item !== "(none)");
|
|
754
|
+
}
|
|
755
|
+
function firstBoldParagraph(body) {
|
|
756
|
+
const match = body.match(/\*\*([^*\n][\s\S]*?)\*\*/);
|
|
757
|
+
return match?.[1]?.replace(/\s+/g, " ").trim() || undefined;
|
|
758
|
+
}
|
|
759
|
+
function loadMilestoneCompletionRollup(basePath, milestoneId) {
|
|
760
|
+
if (!milestoneId)
|
|
761
|
+
return {};
|
|
762
|
+
const summaryPath = resolveMilestoneFile(basePath, milestoneId, "SUMMARY");
|
|
763
|
+
if (!summaryPath || !existsSync(summaryPath))
|
|
764
|
+
return {};
|
|
765
|
+
try {
|
|
766
|
+
const raw = readFileSync(summaryPath, "utf-8");
|
|
767
|
+
const [frontmatterLines, body] = splitFrontmatter(raw);
|
|
768
|
+
const frontmatter = frontmatterLines ? parseFrontmatterMap(frontmatterLines) : {};
|
|
769
|
+
return {
|
|
770
|
+
milestoneTitle: typeof frontmatter.title === "string" ? frontmatter.title : undefined,
|
|
771
|
+
oneLiner: firstBoldParagraph(body),
|
|
772
|
+
successCriteriaResults: extractSection(body, "Success Criteria Results") ?? undefined,
|
|
773
|
+
definitionOfDoneResults: extractSection(body, "Definition of Done Results") ?? undefined,
|
|
774
|
+
requirementOutcomes: extractSection(body, "Requirement Outcomes") ?? undefined,
|
|
775
|
+
deviations: extractSection(body, "Deviations") ?? undefined,
|
|
776
|
+
followUps: extractSection(body, "Follow-ups") ?? undefined,
|
|
777
|
+
keyDecisions: normalizeFrontmatterList(frontmatter.key_decisions),
|
|
778
|
+
keyFiles: normalizeFrontmatterList(frontmatter.key_files),
|
|
779
|
+
lessonsLearned: normalizeFrontmatterList(frontmatter.lessons_learned),
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
catch (err) {
|
|
783
|
+
logWarning("dashboard", `completion roll-up summary read failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
784
|
+
return {};
|
|
785
|
+
}
|
|
786
|
+
}
|
|
720
787
|
export function _resolveAutoWorktreeExitActionForTest(currentMilestoneId, milestoneMergedInPhases, milestoneComplete) {
|
|
721
788
|
const action = _selectStopAutoWorktreeExit({
|
|
722
789
|
currentMilestoneId: currentMilestoneId ?? null,
|
|
@@ -725,15 +792,16 @@ export function _resolveAutoWorktreeExitActionForTest(currentMilestoneId, milest
|
|
|
725
792
|
});
|
|
726
793
|
return action === "none" ? "skip" : action;
|
|
727
794
|
}
|
|
728
|
-
export async function stopAuto(ctx, pi, reason) {
|
|
795
|
+
export async function stopAuto(ctx, pi, reason, options = {}) {
|
|
729
796
|
if (!s.active && !s.paused)
|
|
730
797
|
return;
|
|
731
798
|
const loadedPreferences = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
|
|
732
799
|
const reasonSuffix = reason ? ` — ${reason}` : "";
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
//
|
|
736
|
-
//
|
|
800
|
+
const preserveCompletionSurface = Boolean(options.completionWidget);
|
|
801
|
+
s.completionStopInProgress = preserveCompletionSurface;
|
|
802
|
+
// #4764 — telemetry: record the exit reason, isolation mode, whether an auto
|
|
803
|
+
// worktree was active, and whether the current milestone was merged before
|
|
804
|
+
// stopAuto. The unmerged-work warning is only meaningful for real worktrees.
|
|
737
805
|
try {
|
|
738
806
|
const { emitAutoExit } = await import("./worktree-telemetry.js");
|
|
739
807
|
// Normalize the free-form reason to a closed set so the telemetry
|
|
@@ -755,10 +823,13 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
755
823
|
: rawReason === "stop" || rawReason === "pause"
|
|
756
824
|
? rawReason
|
|
757
825
|
: "other";
|
|
758
|
-
|
|
826
|
+
const telemetryBase = s.originalBasePath || s.basePath;
|
|
827
|
+
emitAutoExit(telemetryBase, {
|
|
759
828
|
reason: normalizedReason,
|
|
760
829
|
milestoneId: s.currentMilestoneId ?? undefined,
|
|
761
830
|
milestoneMerged: s.milestoneMergedInPhases === true,
|
|
831
|
+
isolationMode: getIsolationMode(telemetryBase),
|
|
832
|
+
worktreeActive: isInAutoWorktree(s.basePath),
|
|
762
833
|
});
|
|
763
834
|
}
|
|
764
835
|
catch (err) {
|
|
@@ -902,6 +973,21 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
902
973
|
});
|
|
903
974
|
}
|
|
904
975
|
}
|
|
976
|
+
// Pre-compute completion widget slice counts while the DB is still open.
|
|
977
|
+
// Step 8 runs after closeDatabase(), so DB-backed slice lookups must happen here.
|
|
978
|
+
const completionMilestoneId = options.completionWidget?.milestoneId ?? s.currentMilestoneId;
|
|
979
|
+
let completedSlices = null;
|
|
980
|
+
let totalSlices = null;
|
|
981
|
+
if (preserveCompletionSurface && options.completionWidget && completionMilestoneId && isDbAvailable()) {
|
|
982
|
+
try {
|
|
983
|
+
const slices = getMilestoneSlices(completionMilestoneId);
|
|
984
|
+
completedSlices = slices.filter(slice => isClosedStatus(slice.status)).length;
|
|
985
|
+
totalSlices = slices.length;
|
|
986
|
+
}
|
|
987
|
+
catch (err) {
|
|
988
|
+
logWarning("dashboard", `completion slice stats lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
905
991
|
// ── Step 6: DB cleanup ──
|
|
906
992
|
if (isDbAvailable()) {
|
|
907
993
|
try {
|
|
@@ -914,49 +1000,112 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
914
1000
|
});
|
|
915
1001
|
}
|
|
916
1002
|
}
|
|
917
|
-
// ── Step 7: Restore basePath and chdir ──
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
1003
|
+
// ── Step 7: Restore basePath and chdir (ADR-016 phase 3, #5693) ──
|
|
1004
|
+
// `restoreToProjectRoot` assigns s.basePath before any throwable work;
|
|
1005
|
+
// no fallback assignment is needed at the call site.
|
|
1006
|
+
if (s.originalBasePath) {
|
|
1007
|
+
try {
|
|
1008
|
+
buildLifecycle().restoreToProjectRoot();
|
|
1009
|
+
}
|
|
1010
|
+
catch (e) {
|
|
1011
|
+
debugLog("stop-cleanup-basepath", { error: e instanceof Error ? e.message : String(e) });
|
|
1012
|
+
}
|
|
1013
|
+
try {
|
|
1014
|
+
process.chdir(s.basePath);
|
|
1015
|
+
}
|
|
1016
|
+
catch (err) {
|
|
1017
|
+
/* best-effort */
|
|
1018
|
+
logWarning("engine", `chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
928
1019
|
}
|
|
929
|
-
}
|
|
930
|
-
catch (e) {
|
|
931
|
-
debugLog("stop-cleanup-basepath", { error: e instanceof Error ? e.message : String(e) });
|
|
932
1020
|
}
|
|
933
1021
|
// Re-root the active command session/tool runtime after worktree teardown.
|
|
934
1022
|
// mergeAndExit restores process.cwd(), but AgentSession has already captured
|
|
935
1023
|
// its own cwd for tools and system prompt; refresh it before returning to the
|
|
936
1024
|
// user so follow-up commands do not target a removed milestone worktree.
|
|
937
1025
|
if (s.originalBasePath && ctx && s.cmdCtx) {
|
|
938
|
-
const result = await rerootCommandSession(s.cmdCtx, s.
|
|
1026
|
+
const result = await rerootCommandSession(s.cmdCtx, s.originalBasePath);
|
|
939
1027
|
if (result.status === "cancelled") {
|
|
940
|
-
logWarning("engine", "post-stop session re-root was cancelled", { file: "auto.ts", basePath: s.
|
|
1028
|
+
logWarning("engine", "post-stop session re-root was cancelled", { file: "auto.ts", basePath: s.originalBasePath });
|
|
941
1029
|
}
|
|
942
1030
|
else if (result.status === "failed") {
|
|
943
|
-
logWarning("engine", `post-stop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.
|
|
1031
|
+
logWarning("engine", `post-stop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.originalBasePath });
|
|
944
1032
|
}
|
|
945
1033
|
}
|
|
946
1034
|
// ── Step 8: Ledger notification ──
|
|
947
1035
|
try {
|
|
948
1036
|
const ledger = getLedger();
|
|
1037
|
+
const isAllComplete = reason === "All milestones complete";
|
|
1038
|
+
const isMilestoneComplete = /^Milestone\s+\S+\s+complete$/i.test(reason ?? "");
|
|
1039
|
+
const notificationPrefix = isAllComplete
|
|
1040
|
+
? "All milestones complete"
|
|
1041
|
+
: isMilestoneComplete
|
|
1042
|
+
? `${reason}. Auto-mode finished this milestone`
|
|
1043
|
+
: `Auto-mode stopped${reasonSuffix}`;
|
|
949
1044
|
if (ledger && ledger.units.length > 0) {
|
|
950
1045
|
const totals = getProjectTotals(ledger.units);
|
|
951
|
-
ctx?.ui.notify(
|
|
1046
|
+
ctx?.ui.notify(`${notificationPrefix}. Session: ${formatCost(totals.cost)} · ${formatTokenCount(totals.tokens.total)} tokens · ${ledger.units.length} units`, "info");
|
|
952
1047
|
}
|
|
953
1048
|
else {
|
|
954
|
-
ctx?.ui.notify(
|
|
1049
|
+
ctx?.ui.notify(`${notificationPrefix}.`, "info");
|
|
955
1050
|
}
|
|
956
1051
|
}
|
|
957
1052
|
catch (e) {
|
|
958
1053
|
debugLog("stop-cleanup-ledger", { error: e instanceof Error ? e.message : String(e) });
|
|
959
1054
|
}
|
|
1055
|
+
if (preserveCompletionSurface && ctx && options.completionWidget) {
|
|
1056
|
+
const ledger = getLedger();
|
|
1057
|
+
const units = ledger?.units ?? [];
|
|
1058
|
+
const totals = units.length > 0 ? getProjectTotals(units) : null;
|
|
1059
|
+
let totalInput = 0;
|
|
1060
|
+
let totalCacheRead = 0;
|
|
1061
|
+
try {
|
|
1062
|
+
for (const entry of s.cmdCtx?.sessionManager?.getEntries?.() ?? []) {
|
|
1063
|
+
if (entry.type === "message") {
|
|
1064
|
+
const msgEntry = entry;
|
|
1065
|
+
if (msgEntry.message?.role === "assistant") {
|
|
1066
|
+
const usage = msgEntry.message.usage;
|
|
1067
|
+
if (usage) {
|
|
1068
|
+
totalInput += usage.input || 0;
|
|
1069
|
+
totalCacheRead += usage.cacheRead || 0;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
catch (err) {
|
|
1076
|
+
logWarning("dashboard", `completion stats lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1077
|
+
}
|
|
1078
|
+
const contextUsage = s.cmdCtx?.getContextUsage?.();
|
|
1079
|
+
const milestoneId = completionMilestoneId;
|
|
1080
|
+
const rollup = loadMilestoneCompletionRollup(s.originalBasePath || s.basePath, milestoneId);
|
|
1081
|
+
setCompletionProgressWidget(ctx, {
|
|
1082
|
+
milestoneId,
|
|
1083
|
+
milestoneTitle: options.completionWidget.milestoneTitle ?? rollup.milestoneTitle,
|
|
1084
|
+
oneLiner: rollup.oneLiner,
|
|
1085
|
+
successCriteriaResults: rollup.successCriteriaResults,
|
|
1086
|
+
definitionOfDoneResults: rollup.definitionOfDoneResults,
|
|
1087
|
+
requirementOutcomes: rollup.requirementOutcomes,
|
|
1088
|
+
deviations: rollup.deviations,
|
|
1089
|
+
followUps: rollup.followUps,
|
|
1090
|
+
keyDecisions: rollup.keyDecisions,
|
|
1091
|
+
keyFiles: rollup.keyFiles,
|
|
1092
|
+
lessonsLearned: rollup.lessonsLearned,
|
|
1093
|
+
reason: reason ?? "Milestone complete",
|
|
1094
|
+
startedAt: s.autoStartTime,
|
|
1095
|
+
totalCost: totals?.cost ?? 0,
|
|
1096
|
+
totalTokens: totals?.tokens.total ?? 0,
|
|
1097
|
+
unitCount: units.length,
|
|
1098
|
+
cacheHitRate: totalCacheRead + totalInput > 0
|
|
1099
|
+
? (totalCacheRead / (totalCacheRead + totalInput)) * 100
|
|
1100
|
+
: null,
|
|
1101
|
+
contextPercent: contextUsage?.percent ?? null,
|
|
1102
|
+
contextWindow: contextUsage?.contextWindow ?? s.cmdCtx?.model?.contextWindow ?? null,
|
|
1103
|
+
completedSlices,
|
|
1104
|
+
totalSlices,
|
|
1105
|
+
allMilestonesComplete: options.completionWidget.allMilestonesComplete,
|
|
1106
|
+
basePath: s.originalBasePath || s.basePath || null,
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
960
1109
|
// ── Step 9: Cmux sidebar / event log ──
|
|
961
1110
|
try {
|
|
962
1111
|
pi?.events.emit(CMUX_CHANNELS.SIDEBAR, { action: "clear", preferences: loadedPreferences });
|
|
@@ -1047,9 +1196,21 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
1047
1196
|
resetProactiveHealing();
|
|
1048
1197
|
// UI cleanup
|
|
1049
1198
|
ctx?.ui.setStatus("gsd-auto", undefined);
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1199
|
+
if (!preserveCompletionSurface) {
|
|
1200
|
+
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
1201
|
+
const status = reason?.startsWith("Blocked:") ? "blocked" : reason?.toLowerCase().includes("fail") ? "failed" : "stopped";
|
|
1202
|
+
setLifecycleOutcome(ctx, {
|
|
1203
|
+
status,
|
|
1204
|
+
title: status === "blocked" ? "Auto-mode blocked" : status === "failed" ? "Auto-mode stopped with an issue" : "Auto-mode stopped",
|
|
1205
|
+
detail: reason ?? "Auto-mode stopped.",
|
|
1206
|
+
nextAction: status === "blocked"
|
|
1207
|
+
? "Fix the blocker, then run /gsd auto to resume."
|
|
1208
|
+
: "Run /gsd status for the current project state, or /gsd auto to continue.",
|
|
1209
|
+
commands: ["/gsd status for overview", "/gsd auto to run", "/gsd visualize to inspect", "/gsd notifications for history"],
|
|
1210
|
+
});
|
|
1211
|
+
if (ctx)
|
|
1212
|
+
initHealthWidget(ctx);
|
|
1213
|
+
}
|
|
1053
1214
|
restoreProjectRootEnv();
|
|
1054
1215
|
restoreMilestoneLockEnv();
|
|
1055
1216
|
// Drop the active-tool baseline so a subsequent /gsd auto run on the
|
|
@@ -1065,7 +1226,7 @@ export async function stopAuto(ctx, pi, reason) {
|
|
|
1065
1226
|
debugLog("stop-orchestration-stop", { error: err instanceof Error ? err.message : String(err) });
|
|
1066
1227
|
}
|
|
1067
1228
|
// Reset all session state in one call
|
|
1068
|
-
s.
|
|
1229
|
+
s.resetAfterStop({ preserveCompletionSurface });
|
|
1069
1230
|
}
|
|
1070
1231
|
}
|
|
1071
1232
|
export function _selectStopAutoWorktreeExit(args) {
|
|
@@ -1126,6 +1287,7 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
|
|
|
1126
1287
|
// Non-fatal — resume will still work via full bootstrap, just without worktree context
|
|
1127
1288
|
logWarning("engine", `paused-session DB write failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
1128
1289
|
}
|
|
1290
|
+
const pausedUnitLabel = currentUnitLabel();
|
|
1129
1291
|
// Close out the current unit so its runtime record doesn't stay at "dispatched"
|
|
1130
1292
|
if (s.currentUnit && ctx) {
|
|
1131
1293
|
try {
|
|
@@ -1173,9 +1335,17 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
|
|
|
1173
1335
|
s.verificationRetryCount.clear();
|
|
1174
1336
|
ctx?.ui.setStatus("gsd-auto", "paused");
|
|
1175
1337
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
1338
|
+
const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
|
|
1339
|
+
setLifecycleOutcome(ctx, {
|
|
1340
|
+
status: "paused",
|
|
1341
|
+
title: `${s.stepMode ? "Step" : "Auto"}-mode paused`,
|
|
1342
|
+
detail: _errorContext?.message ?? "Paused by user request.",
|
|
1343
|
+
nextAction: `Type to steer, or run ${resumeCmd} to resume.`,
|
|
1344
|
+
commands: [resumeCmd, "/gsd status for overview", "/gsd notifications for history"],
|
|
1345
|
+
unitLabel: pausedUnitLabel,
|
|
1346
|
+
});
|
|
1176
1347
|
if (ctx)
|
|
1177
1348
|
initHealthWidget(ctx);
|
|
1178
|
-
const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
|
|
1179
1349
|
ctx?.ui.notify(`${s.stepMode ? "Step" : "Auto"}-mode paused (Escape). Type to interact, or ${resumeCmd} to resume.`, "info");
|
|
1180
1350
|
}
|
|
1181
1351
|
/**
|
|
@@ -1186,28 +1356,34 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
|
|
|
1186
1356
|
* deps bag is intentionally focused — Lifecycle does not see the wider auto-
|
|
1187
1357
|
* mode dependency graph.
|
|
1188
1358
|
*/
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1359
|
+
/**
|
|
1360
|
+
* Construct a `WorktreeLifecycleDeps` bag without binding to any session.
|
|
1361
|
+
*
|
|
1362
|
+
* Exported so session-less callers (currently `parallel-merge.ts`) can build
|
|
1363
|
+
* the same deps and call `mergeMilestoneStandalone` through the Worktree
|
|
1364
|
+
* Lifecycle Module instead of bypassing it (ADR-016 phase 2 / A2).
|
|
1365
|
+
*/
|
|
1366
|
+
export function buildWorktreeLifecycleDeps() {
|
|
1367
|
+
// ADR-016 phase 2 / C-track close-out:
|
|
1368
|
+
// C1 (#5624) — fs + git-CLI primitives inlined
|
|
1369
|
+
// C2 (#5625) — worktree-manager helpers inlined
|
|
1370
|
+
// C3 (#5626) — cache + preferences + paths inlined
|
|
1371
|
+
// C4 (#5627) — GitServiceImpl constructor → gitServiceFactory
|
|
1372
|
+
//
|
|
1373
|
+
// Final WorktreeLifecycleDeps shape: 3 fields (gitServiceFactory,
|
|
1374
|
+
// worktreeProjection, mergeMilestoneToMain). Down from 18 at slice-7
|
|
1375
|
+
// closure.
|
|
1376
|
+
return {
|
|
1377
|
+
gitServiceFactory: (basePath) => {
|
|
1378
|
+
const gitConfig = loadEffectiveGSDPreferences()?.preferences?.git ?? {};
|
|
1379
|
+
return new GitServiceImpl(basePath, gitConfig);
|
|
1380
|
+
},
|
|
1199
1381
|
worktreeProjection: new WorktreeStateProjection(),
|
|
1200
|
-
isInAutoWorktree,
|
|
1201
|
-
autoCommitCurrentBranch,
|
|
1202
|
-
autoWorktreeBranch,
|
|
1203
|
-
teardownAutoWorktree,
|
|
1204
1382
|
mergeMilestoneToMain,
|
|
1205
|
-
getCurrentBranch,
|
|
1206
|
-
checkoutBranch: nativeCheckoutBranch,
|
|
1207
|
-
resolveMilestoneFile,
|
|
1208
|
-
readFileSync: (path, encoding) => readFileSync(path, encoding),
|
|
1209
1383
|
};
|
|
1210
|
-
|
|
1384
|
+
}
|
|
1385
|
+
function buildLifecycle() {
|
|
1386
|
+
return new WorktreeLifecycle(s, buildWorktreeLifecycleDeps());
|
|
1211
1387
|
}
|
|
1212
1388
|
/**
|
|
1213
1389
|
* Thin entry glue for the new Auto Orchestration module.
|
|
@@ -1223,16 +1399,19 @@ export function createWiredAutoOrchestrationModule(ctx, _pi, dispatchBasePath, r
|
|
|
1223
1399
|
stateReconciliation: {
|
|
1224
1400
|
async reconcileBeforeDispatch() {
|
|
1225
1401
|
const result = await reconcileBeforeDispatch(dispatchBasePath);
|
|
1226
|
-
if (
|
|
1402
|
+
if (result.blockers.length > 0) {
|
|
1227
1403
|
return {
|
|
1228
1404
|
ok: false,
|
|
1229
|
-
reason: result.
|
|
1405
|
+
reason: result.blockers[0],
|
|
1230
1406
|
stateSnapshot: result.stateSnapshot,
|
|
1231
1407
|
};
|
|
1232
1408
|
}
|
|
1409
|
+
const repairedKinds = result.repaired.map((d) => d.kind);
|
|
1233
1410
|
return {
|
|
1234
1411
|
ok: true,
|
|
1235
|
-
reason:
|
|
1412
|
+
reason: repairedKinds.length > 0
|
|
1413
|
+
? `repaired: ${repairedKinds.join(", ")}`
|
|
1414
|
+
: "clean",
|
|
1236
1415
|
stateSnapshot: result.stateSnapshot,
|
|
1237
1416
|
};
|
|
1238
1417
|
},
|
|
@@ -1431,7 +1610,6 @@ function buildLoopDeps(pi) {
|
|
|
1431
1610
|
pruneQueueOrder,
|
|
1432
1611
|
isInAutoWorktree,
|
|
1433
1612
|
shouldUseWorktreeIsolation,
|
|
1434
|
-
mergeMilestoneToMain,
|
|
1435
1613
|
teardownAutoWorktree,
|
|
1436
1614
|
createAutoWorktree,
|
|
1437
1615
|
captureIntegrationBranch,
|
|
@@ -1701,7 +1879,12 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1701
1879
|
s.verbose = verboseMode;
|
|
1702
1880
|
s.stepMode = requestedStepMode;
|
|
1703
1881
|
s.cmdCtx = ctx;
|
|
1704
|
-
|
|
1882
|
+
// ADR-016 phase 2 / B2 (#5620): bootstrap basePath transition before
|
|
1883
|
+
// the resume path consults persisted worktree state. Defensive about
|
|
1884
|
+
// s.originalBasePath — the meta-restore above (line 2003 / 2055) may
|
|
1885
|
+
// have already populated it from paused metadata; the verb preserves
|
|
1886
|
+
// that value.
|
|
1887
|
+
buildLifecycle().adoptSessionRoot(base);
|
|
1705
1888
|
// ── Resume worktree: if the paused session was inside a milestone worktree,
|
|
1706
1889
|
// apply that path as the dispatch basePath immediately (#3723).
|
|
1707
1890
|
// This ensures the dispatch loop runs from the worktree directory even when
|
|
@@ -1713,7 +1896,8 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|
|
1713
1896
|
if (resumeWorktreePath && !existsSync(resumeWorktreePath)) {
|
|
1714
1897
|
logWarning("session", `Worktree was expected at ${resumeWorktreePath} but is missing. Continuing in project-root mode. To restart with a fresh worktree, run /gsd-debug or recreate the milestone.`, { file: "auto.ts", milestoneId: s.currentMilestoneId ?? "" });
|
|
1715
1898
|
}
|
|
1716
|
-
|
|
1899
|
+
// ADR-016 phase 2 / B3 (#5621): paused-resume worktree-path adoption.
|
|
1900
|
+
buildLifecycle().resumeFromPausedSession(base, resumeWorktreePath);
|
|
1717
1901
|
// Rebuild scope now that s.basePath reflects the actual worktree (or project root).
|
|
1718
1902
|
rebuildScope(s.basePath, s.currentMilestoneId);
|
|
1719
1903
|
// Ensure the workflow-logger audit log is pinned to the project root
|
|
@@ -1936,7 +2120,12 @@ export async function dispatchHookUnit(ctx, pi, hookName, triggerUnitType, trigg
|
|
|
1936
2120
|
s.currentUnit = null;
|
|
1937
2121
|
s.pendingQuickTasks = [];
|
|
1938
2122
|
}
|
|
1939
|
-
|
|
2123
|
+
// ADR-016 phase 2 / B2 (#5620): hook-trigger basePath transition. Treats
|
|
2124
|
+
// the trigger as a bootstrap variant — if the session is fresh,
|
|
2125
|
+
// `originalBasePath` gets set to `targetBasePath`; if the session was
|
|
2126
|
+
// already active with an established `originalBasePath`, the verb
|
|
2127
|
+
// preserves it.
|
|
2128
|
+
buildLifecycle().adoptSessionRoot(targetBasePath);
|
|
1940
2129
|
if (!s.orchestration) {
|
|
1941
2130
|
ensureOrchestrationModule(ctx, pi, s.basePath);
|
|
1942
2131
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { logWarning } from "../workflow-logger.js";
|
|
3
3
|
import { checkDeepProjectSetupAfterTurn, checkAutoStartAfterDiscuss, maybeHandleReadyPhraseWithoutFiles, maybeHandleEmptyIntentTurn, resetEmptyTurnCounter, } from "../guided-flow.js";
|
|
4
4
|
import { clearPathCache } from "../paths.js";
|
|
5
|
-
import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, pauseAuto, setCurrentDispatchedModelId } from "../auto.js";
|
|
5
|
+
import { getAutoDashboardData, getAutoModeStartModel, isAutoActive, isAutoCompletionStopInProgress, pauseAuto, setCurrentDispatchedModelId, } from "../auto.js";
|
|
6
6
|
import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
|
|
7
7
|
import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
|
8
8
|
import { isSessionSwitchAbortGraceActive, isSessionSwitchInFlight, resolveAgentEnd, resolveAgentEndCancelled, } from "../auto/resolve.js";
|
|
@@ -116,8 +116,7 @@ export function isBareClaudeCodeStreamAbortPlaceholder(lastMsg) {
|
|
|
116
116
|
* Claude Code abort markers are intentionally ignored when the abort fires
|
|
117
117
|
* while the session-switch is in flight: the abort is the expected side-effect
|
|
118
118
|
* of the transition, not a user signal. Other branches (genuine `stopReason
|
|
119
|
-
* === "aborted"` with
|
|
120
|
-
* behavior.
|
|
119
|
+
* === "aborted"` with explicit errorMessage) preserve the prior behavior.
|
|
121
120
|
*/
|
|
122
121
|
export function _handleSessionSwitchAgentEnd(lastMsg, resolveCancelled) {
|
|
123
122
|
if (!lastMsg || typeof lastMsg !== "object")
|
|
@@ -136,10 +135,8 @@ export function _handleSessionSwitchAgentEnd(lastMsg, resolveCancelled) {
|
|
|
136
135
|
return;
|
|
137
136
|
}
|
|
138
137
|
if (m.stopReason === "aborted") {
|
|
139
|
-
const content = m.content;
|
|
140
|
-
const hasEmptyContent = Array.isArray(content) && content.length === 0;
|
|
141
138
|
const hasErrorMessage = !!m.errorMessage;
|
|
142
|
-
if (
|
|
139
|
+
if (hasErrorMessage) {
|
|
143
140
|
resolveCancelled(_buildAbortedPauseContext(m));
|
|
144
141
|
}
|
|
145
142
|
}
|
|
@@ -239,6 +236,11 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
239
236
|
return;
|
|
240
237
|
}
|
|
241
238
|
if (isObjectRecord(lastMsg) && "stopReason" in lastMsg && lastMsg.stopReason === "aborted") {
|
|
239
|
+
if (isAutoCompletionStopInProgress()) {
|
|
240
|
+
resetRetryState(retryState);
|
|
241
|
+
resolveAgentEnd(event);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
242
244
|
// Empty content with aborted stopReason is a non-fatal agent stop (the LLM
|
|
243
245
|
// chose to end without producing output). Only pause on genuine fatal aborts
|
|
244
246
|
// that carry error context — e.g. errorMessage field or non-empty content
|
|
@@ -274,6 +276,11 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|
|
274
276
|
// errorMessage looks uninformative.
|
|
275
277
|
const rawErrorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
|
|
276
278
|
if (isUserInitiatedAbortMessage(rawErrorMsg)) {
|
|
279
|
+
if (isAutoCompletionStopInProgress()) {
|
|
280
|
+
resetRetryState(retryState);
|
|
281
|
+
resolveAgentEnd(event);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
277
284
|
resolveAgentEndCancelled({
|
|
278
285
|
message: rawErrorMsg,
|
|
279
286
|
category: "aborted",
|
|
@@ -10,7 +10,7 @@ import { canonicalToolName, clearDiscussionFlowState, isDepthConfirmationAnswer,
|
|
|
10
10
|
import { resolveManifest } from "../unit-context-manifest.js";
|
|
11
11
|
import { isBlockedStateFile, isBashWriteToStateFile, BLOCKED_WRITE_ERROR } from "../write-intercept.js";
|
|
12
12
|
import { loadFile, saveFile, formatContinue } from "../files.js";
|
|
13
|
-
import { getAutoRuntimeSnapshot, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto-runtime-state.js";
|
|
13
|
+
import { clearToolInvocationError, getAutoRuntimeSnapshot, isAutoActive, isAutoPaused, markToolEnd, markToolStart, recordToolInvocationError } from "../auto-runtime-state.js";
|
|
14
14
|
import { checkToolCallLoop, resetToolCallLoopGuard } from "./tool-call-loop-guard.js";
|
|
15
15
|
import { saveActivityLog } from "../activity-log.js";
|
|
16
16
|
import { recordToolCall as safetyRecordToolCall, recordToolResult as safetyRecordToolResult, saveEvidenceToDisk } from "../safety/evidence-collector.js";
|
|
@@ -123,7 +123,7 @@ const AUTO_UNIT_SCOPED_TOOLS = {
|
|
|
123
123
|
"plan-slice": ["gsd_plan_slice", "gsd_plan_task", "gsd_decision_save"],
|
|
124
124
|
"refine-slice": ["gsd_plan_slice", "gsd_plan_task", "gsd_decision_save"],
|
|
125
125
|
"replan-slice": ["gsd_replan_slice", "gsd_plan_task", "gsd_decision_save"],
|
|
126
|
-
"complete-slice": ["gsd_slice_complete", "gsd_decision_save", "gsd_requirement_update", "subagent"],
|
|
126
|
+
"complete-slice": ["gsd_slice_complete", "gsd_task_reopen", "gsd_replan_slice", "gsd_decision_save", "gsd_requirement_update", "subagent"],
|
|
127
127
|
"reassess-roadmap": ["gsd_reassess_roadmap"],
|
|
128
128
|
"execute-task": ["gsd_task_complete", "gsd_decision_save"],
|
|
129
129
|
"execute-task-simple": ["gsd_task_complete", "gsd_decision_save"],
|
|
@@ -773,6 +773,9 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
773
773
|
// errors and deterministic policy rejections are handled consistently.
|
|
774
774
|
recordToolInvocationError(event.toolName, errorText);
|
|
775
775
|
}
|
|
776
|
+
else if (isAutoActive()) {
|
|
777
|
+
clearToolInvocationError();
|
|
778
|
+
}
|
|
776
779
|
const toolName = canonicalToolName(event.toolName);
|
|
777
780
|
if (toolName !== "ask_user_questions")
|
|
778
781
|
return;
|
|
@@ -891,6 +894,9 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
891
894
|
// errors and deterministic policy rejections are handled consistently.
|
|
892
895
|
recordToolInvocationError(event.toolName, errorText);
|
|
893
896
|
}
|
|
897
|
+
else if (isAutoActive()) {
|
|
898
|
+
clearToolInvocationError();
|
|
899
|
+
}
|
|
894
900
|
// Safety harness: record tool execution results for evidence cross-referencing
|
|
895
901
|
if (isAutoActive()) {
|
|
896
902
|
safetyRecordToolResult(event.toolCallId, event.toolName, event.result, event.isError);
|