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
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
ExtensionAPI,
|
|
17
17
|
ExtensionContext,
|
|
18
18
|
ExtensionCommandContext,
|
|
19
|
+
SessionMessageEntry,
|
|
19
20
|
} from "@gsd/pi-coding-agent";
|
|
20
21
|
|
|
21
22
|
import { deriveState } from "./state.js";
|
|
@@ -32,7 +33,7 @@ import {
|
|
|
32
33
|
setRuntimeKv,
|
|
33
34
|
deleteRuntimeKv,
|
|
34
35
|
} from "./db/runtime-kv.js";
|
|
35
|
-
import { getManifestStatus } from "./files.js";
|
|
36
|
+
import { extractSection, getManifestStatus, splitFrontmatter, parseFrontmatterMap } from "./files.js";
|
|
36
37
|
export { inlinePriorMilestoneSummary } from "./files.js";
|
|
37
38
|
import { collectSecretsFromManifest } from "../get-secrets-from-user.js";
|
|
38
39
|
import {
|
|
@@ -188,6 +189,8 @@ import { isClosedStatus } from "./status-guards.js";
|
|
|
188
189
|
import {
|
|
189
190
|
type AutoDashboardData,
|
|
190
191
|
updateProgressWidget as _updateProgressWidget,
|
|
192
|
+
setCompletionProgressWidget,
|
|
193
|
+
setAutoOutcomeWidget,
|
|
191
194
|
updateSliceProgressCache,
|
|
192
195
|
clearSliceProgressCache,
|
|
193
196
|
describeNextUnit as _describeNextUnit,
|
|
@@ -201,7 +204,7 @@ import {
|
|
|
201
204
|
deregisterSigtermHandler as _deregisterSigtermHandler,
|
|
202
205
|
detectWorkingTreeActivity,
|
|
203
206
|
} from "./auto-supervisor.js";
|
|
204
|
-
import { isDbAvailable, getMilestone } from "./gsd-db.js";
|
|
207
|
+
import { isDbAvailable, getMilestone, getMilestoneSlices } from "./gsd-db.js";
|
|
205
208
|
import { markLatestActiveForWorkerCanceled } from "./db/unit-dispatches.js";
|
|
206
209
|
import { writeUnitRuntimeRecord } from "./unit-runtime.js";
|
|
207
210
|
import { countPendingCaptures } from "./captures.js";
|
|
@@ -231,7 +234,7 @@ import { bootstrapAutoSession, openProjectDbIfPresent, type BootstrapDeps } from
|
|
|
231
234
|
import { initHealthWidget } from "./health-widget.js";
|
|
232
235
|
import { runLegacyAutoLoop, runUokKernelLoop } from "./auto/loop.js";
|
|
233
236
|
import { resolveAgentEnd, resolveAgentEndCancelled, _resetPendingResolve, isSessionSwitchInFlight } from "./auto/resolve.js";
|
|
234
|
-
import type { LoopDeps } from "./auto/loop-deps.js";
|
|
237
|
+
import type { LoopDeps, StopAutoOptions } from "./auto/loop-deps.js";
|
|
235
238
|
import type { ErrorContext } from "./auto/types.js";
|
|
236
239
|
import { runAutoLoopWithUok } from "./uok/kernel.js";
|
|
237
240
|
import { resolveUokFlags } from "./uok/flags.js";
|
|
@@ -456,15 +459,10 @@ export function _synthesizePausedSessionRecoveryForTest(
|
|
|
456
459
|
return synthesizePausedSessionRecovery(basePath, unitType, unitId, sessionFile);
|
|
457
460
|
}
|
|
458
461
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
): string {
|
|
464
|
-
return pausedWorktreePath && pathExists(pausedWorktreePath)
|
|
465
|
-
? pausedWorktreePath
|
|
466
|
-
: basePath;
|
|
467
|
-
}
|
|
462
|
+
// `_resolvePausedResumeBasePathForTest` was retired in ADR-016 phase 2 / B3
|
|
463
|
+
// (#5621). Production callers go through
|
|
464
|
+
// `WorktreeLifecycle.resumeFromPausedSession`; the pure helper for tests is
|
|
465
|
+
// `resolvePausedResumeBasePath` exported from `worktree-lifecycle.ts`.
|
|
468
466
|
|
|
469
467
|
const DETACHED_AUTO_KEEPALIVE_INTERVAL_MS = 30_000;
|
|
470
468
|
|
|
@@ -668,6 +666,10 @@ export function isAutoActive(): boolean {
|
|
|
668
666
|
return s.active;
|
|
669
667
|
}
|
|
670
668
|
|
|
669
|
+
export function isAutoCompletionStopInProgress(): boolean {
|
|
670
|
+
return s.completionStopInProgress;
|
|
671
|
+
}
|
|
672
|
+
|
|
671
673
|
/** Test-only seam for validating auto-mode guards (#4704). Do not use in production code. */
|
|
672
674
|
export function _setAutoActiveForTest(active: boolean): void {
|
|
673
675
|
s.active = active;
|
|
@@ -928,6 +930,31 @@ function buildSnapshotOpts(
|
|
|
928
930
|
};
|
|
929
931
|
}
|
|
930
932
|
|
|
933
|
+
function currentUnitLabel(): string | null {
|
|
934
|
+
if (!s.currentUnit) return null;
|
|
935
|
+
return `${unitVerb(s.currentUnit.type)} ${s.currentUnit.id}`;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
function setLifecycleOutcome(
|
|
939
|
+
ctx: ExtensionContext | undefined,
|
|
940
|
+
input: {
|
|
941
|
+
status: "paused" | "stopped" | "blocked" | "failed" | "complete" | "waiting" | "step";
|
|
942
|
+
title: string;
|
|
943
|
+
detail?: string | null;
|
|
944
|
+
nextAction: string;
|
|
945
|
+
commands?: string[];
|
|
946
|
+
unitLabel?: string | null;
|
|
947
|
+
},
|
|
948
|
+
): void {
|
|
949
|
+
if (!ctx?.hasUI) return;
|
|
950
|
+
const { unitLabel: unitLabelOverride, ...rest } = input;
|
|
951
|
+
setAutoOutcomeWidget(ctx, {
|
|
952
|
+
...rest,
|
|
953
|
+
unitLabel: unitLabelOverride !== undefined ? unitLabelOverride : currentUnitLabel(),
|
|
954
|
+
startedAt: s.autoStartTime,
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
|
|
931
958
|
function handleLostSessionLock(
|
|
932
959
|
ctx?: ExtensionContext,
|
|
933
960
|
lockStatus?: SessionLockStatus,
|
|
@@ -1015,27 +1042,42 @@ export async function cleanupAfterLoopExit(ctx: ExtensionContext): Promise<void>
|
|
|
1015
1042
|
// visible so the user still has a resumable auto-mode signal on screen.
|
|
1016
1043
|
if (!s.paused) {
|
|
1017
1044
|
ctx.ui.setStatus("gsd-auto", undefined);
|
|
1018
|
-
|
|
1045
|
+
if (s.completionStopInProgress) {
|
|
1046
|
+
s.completionStopInProgress = false;
|
|
1047
|
+
}
|
|
1019
1048
|
initHealthWidget(ctx);
|
|
1020
1049
|
}
|
|
1021
1050
|
|
|
1022
|
-
//
|
|
1051
|
+
// ADR-016 phase 3 (#5693): the stop-path basePath restore routes through
|
|
1052
|
+
// `Lifecycle.restoreToProjectRoot()`, the sole owner of `s.basePath`
|
|
1053
|
+
// mutation. The verb assigns `s.basePath` before any throwable work
|
|
1054
|
+
// (rebuildGitService, cache invalidation), so a thrown error still leaves
|
|
1055
|
+
// basePath restored — no fallback assignment needed at the call site.
|
|
1056
|
+
// The chdir stays here because `restoreToProjectRoot` is a pure
|
|
1057
|
+
// session-state mutation.
|
|
1023
1058
|
if (s.originalBasePath) {
|
|
1024
|
-
s.basePath = s.originalBasePath;
|
|
1025
1059
|
try {
|
|
1026
|
-
|
|
1060
|
+
buildLifecycle().restoreToProjectRoot();
|
|
1061
|
+
} catch (err) {
|
|
1062
|
+
logWarning(
|
|
1063
|
+
"engine",
|
|
1064
|
+
`restore project root failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
1065
|
+
{ file: "auto.ts" },
|
|
1066
|
+
);
|
|
1067
|
+
}
|
|
1068
|
+
try {
|
|
1069
|
+
process.chdir(s.originalBasePath);
|
|
1027
1070
|
} catch (err) {
|
|
1028
|
-
|
|
1029
|
-
logWarning("engine", `chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
1071
|
+
logWarning("engine", `basePath restore/chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
1030
1072
|
}
|
|
1031
1073
|
}
|
|
1032
1074
|
|
|
1033
1075
|
if (s.originalBasePath && s.cmdCtx) {
|
|
1034
|
-
const result = await rerootCommandSession(s.cmdCtx, s.
|
|
1076
|
+
const result = await rerootCommandSession(s.cmdCtx, s.originalBasePath);
|
|
1035
1077
|
if (result.status === "cancelled") {
|
|
1036
|
-
logWarning("engine", "post-loop session re-root was cancelled", { file: "auto.ts", basePath: s.
|
|
1078
|
+
logWarning("engine", "post-loop session re-root was cancelled", { file: "auto.ts", basePath: s.originalBasePath });
|
|
1037
1079
|
} else if (result.status === "failed") {
|
|
1038
|
-
logWarning("engine", `post-loop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.
|
|
1080
|
+
logWarning("engine", `post-loop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.originalBasePath });
|
|
1039
1081
|
}
|
|
1040
1082
|
}
|
|
1041
1083
|
}
|
|
@@ -1046,6 +1088,58 @@ export function _cleanupAfterLoopExitForTest(ctx: ExtensionContext): Promise<voi
|
|
|
1046
1088
|
|
|
1047
1089
|
export type AutoWorktreeExitAction = "skip" | "merge" | "preserve";
|
|
1048
1090
|
|
|
1091
|
+
interface MilestoneCompletionRollup {
|
|
1092
|
+
milestoneTitle?: string;
|
|
1093
|
+
oneLiner?: string;
|
|
1094
|
+
successCriteriaResults?: string;
|
|
1095
|
+
definitionOfDoneResults?: string;
|
|
1096
|
+
requirementOutcomes?: string;
|
|
1097
|
+
deviations?: string;
|
|
1098
|
+
followUps?: string;
|
|
1099
|
+
keyDecisions?: string[];
|
|
1100
|
+
keyFiles?: string[];
|
|
1101
|
+
lessonsLearned?: string[];
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
function normalizeFrontmatterList(value: unknown): string[] {
|
|
1105
|
+
if (!Array.isArray(value)) return [];
|
|
1106
|
+
return value
|
|
1107
|
+
.map(item => typeof item === "string" ? item.trim() : "")
|
|
1108
|
+
.filter(item => item.length > 0 && item !== "(none)");
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
function firstBoldParagraph(body: string): string | undefined {
|
|
1112
|
+
const match = body.match(/\*\*([^*\n][\s\S]*?)\*\*/);
|
|
1113
|
+
return match?.[1]?.replace(/\s+/g, " ").trim() || undefined;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
function loadMilestoneCompletionRollup(basePath: string, milestoneId: string | null | undefined): MilestoneCompletionRollup {
|
|
1117
|
+
if (!milestoneId) return {};
|
|
1118
|
+
const summaryPath = resolveMilestoneFile(basePath, milestoneId, "SUMMARY");
|
|
1119
|
+
if (!summaryPath || !existsSync(summaryPath)) return {};
|
|
1120
|
+
|
|
1121
|
+
try {
|
|
1122
|
+
const raw = readFileSync(summaryPath, "utf-8");
|
|
1123
|
+
const [frontmatterLines, body] = splitFrontmatter(raw);
|
|
1124
|
+
const frontmatter = frontmatterLines ? parseFrontmatterMap(frontmatterLines) : {};
|
|
1125
|
+
return {
|
|
1126
|
+
milestoneTitle: typeof frontmatter.title === "string" ? frontmatter.title : undefined,
|
|
1127
|
+
oneLiner: firstBoldParagraph(body),
|
|
1128
|
+
successCriteriaResults: extractSection(body, "Success Criteria Results") ?? undefined,
|
|
1129
|
+
definitionOfDoneResults: extractSection(body, "Definition of Done Results") ?? undefined,
|
|
1130
|
+
requirementOutcomes: extractSection(body, "Requirement Outcomes") ?? undefined,
|
|
1131
|
+
deviations: extractSection(body, "Deviations") ?? undefined,
|
|
1132
|
+
followUps: extractSection(body, "Follow-ups") ?? undefined,
|
|
1133
|
+
keyDecisions: normalizeFrontmatterList(frontmatter.key_decisions),
|
|
1134
|
+
keyFiles: normalizeFrontmatterList(frontmatter.key_files),
|
|
1135
|
+
lessonsLearned: normalizeFrontmatterList(frontmatter.lessons_learned),
|
|
1136
|
+
};
|
|
1137
|
+
} catch (err) {
|
|
1138
|
+
logWarning("dashboard", `completion roll-up summary read failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1139
|
+
return {};
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1049
1143
|
export function _resolveAutoWorktreeExitActionForTest(
|
|
1050
1144
|
currentMilestoneId: string | null | undefined,
|
|
1051
1145
|
milestoneMergedInPhases: boolean,
|
|
@@ -1063,15 +1157,17 @@ export async function stopAuto(
|
|
|
1063
1157
|
ctx?: ExtensionContext,
|
|
1064
1158
|
pi?: ExtensionAPI,
|
|
1065
1159
|
reason?: string,
|
|
1160
|
+
options: StopAutoOptions = {},
|
|
1066
1161
|
): Promise<void> {
|
|
1067
1162
|
if (!s.active && !s.paused) return;
|
|
1068
1163
|
const loadedPreferences = loadEffectiveGSDPreferences(s.basePath || undefined)?.preferences;
|
|
1069
1164
|
const reasonSuffix = reason ? ` — ${reason}` : "";
|
|
1165
|
+
const preserveCompletionSurface = Boolean(options.completionWidget);
|
|
1166
|
+
s.completionStopInProgress = preserveCompletionSurface;
|
|
1070
1167
|
|
|
1071
|
-
// #4764 — telemetry: record the exit reason
|
|
1072
|
-
// was
|
|
1073
|
-
//
|
|
1074
|
-
// is exactly the pattern that strands work.
|
|
1168
|
+
// #4764 — telemetry: record the exit reason, isolation mode, whether an auto
|
|
1169
|
+
// worktree was active, and whether the current milestone was merged before
|
|
1170
|
+
// stopAuto. The unmerged-work warning is only meaningful for real worktrees.
|
|
1075
1171
|
try {
|
|
1076
1172
|
const { emitAutoExit } = await import("./worktree-telemetry.js");
|
|
1077
1173
|
type AutoExitReason =
|
|
@@ -1096,10 +1192,13 @@ export async function stopAuto(
|
|
|
1096
1192
|
: rawReason === "stop" || rawReason === "pause"
|
|
1097
1193
|
? rawReason
|
|
1098
1194
|
: "other";
|
|
1099
|
-
|
|
1195
|
+
const telemetryBase = s.originalBasePath || s.basePath;
|
|
1196
|
+
emitAutoExit(telemetryBase, {
|
|
1100
1197
|
reason: normalizedReason,
|
|
1101
1198
|
milestoneId: s.currentMilestoneId ?? undefined,
|
|
1102
1199
|
milestoneMerged: s.milestoneMergedInPhases === true,
|
|
1200
|
+
isolationMode: getIsolationMode(telemetryBase),
|
|
1201
|
+
worktreeActive: isInAutoWorktree(s.basePath),
|
|
1103
1202
|
});
|
|
1104
1203
|
} catch (err) {
|
|
1105
1204
|
logWarning("engine", `auto-exit telemetry failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -1257,6 +1356,21 @@ export async function stopAuto(
|
|
|
1257
1356
|
}
|
|
1258
1357
|
}
|
|
1259
1358
|
|
|
1359
|
+
// Pre-compute completion widget slice counts while the DB is still open.
|
|
1360
|
+
// Step 8 runs after closeDatabase(), so DB-backed slice lookups must happen here.
|
|
1361
|
+
const completionMilestoneId = options.completionWidget?.milestoneId ?? s.currentMilestoneId;
|
|
1362
|
+
let completedSlices: number | null = null;
|
|
1363
|
+
let totalSlices: number | null = null;
|
|
1364
|
+
if (preserveCompletionSurface && options.completionWidget && completionMilestoneId && isDbAvailable()) {
|
|
1365
|
+
try {
|
|
1366
|
+
const slices = getMilestoneSlices(completionMilestoneId);
|
|
1367
|
+
completedSlices = slices.filter(slice => isClosedStatus(slice.status)).length;
|
|
1368
|
+
totalSlices = slices.length;
|
|
1369
|
+
} catch (err) {
|
|
1370
|
+
logWarning("dashboard", `completion slice stats lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1260
1374
|
// ── Step 6: DB cleanup ──
|
|
1261
1375
|
if (isDbAvailable()) {
|
|
1262
1376
|
try {
|
|
@@ -1269,19 +1383,21 @@ export async function stopAuto(
|
|
|
1269
1383
|
}
|
|
1270
1384
|
}
|
|
1271
1385
|
|
|
1272
|
-
// ── Step 7: Restore basePath and chdir ──
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1386
|
+
// ── Step 7: Restore basePath and chdir (ADR-016 phase 3, #5693) ──
|
|
1387
|
+
// `restoreToProjectRoot` assigns s.basePath before any throwable work;
|
|
1388
|
+
// no fallback assignment is needed at the call site.
|
|
1389
|
+
if (s.originalBasePath) {
|
|
1390
|
+
try {
|
|
1391
|
+
buildLifecycle().restoreToProjectRoot();
|
|
1392
|
+
} catch (e) {
|
|
1393
|
+
debugLog("stop-cleanup-basepath", { error: e instanceof Error ? e.message : String(e) });
|
|
1394
|
+
}
|
|
1395
|
+
try {
|
|
1396
|
+
process.chdir(s.basePath);
|
|
1397
|
+
} catch (err) {
|
|
1398
|
+
/* best-effort */
|
|
1399
|
+
logWarning("engine", `chdir failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
1282
1400
|
}
|
|
1283
|
-
} catch (e) {
|
|
1284
|
-
debugLog("stop-cleanup-basepath", { error: e instanceof Error ? e.message : String(e) });
|
|
1285
1401
|
}
|
|
1286
1402
|
|
|
1287
1403
|
// Re-root the active command session/tool runtime after worktree teardown.
|
|
@@ -1289,30 +1405,91 @@ export async function stopAuto(
|
|
|
1289
1405
|
// its own cwd for tools and system prompt; refresh it before returning to the
|
|
1290
1406
|
// user so follow-up commands do not target a removed milestone worktree.
|
|
1291
1407
|
if (s.originalBasePath && ctx && s.cmdCtx) {
|
|
1292
|
-
const result = await rerootCommandSession(s.cmdCtx, s.
|
|
1408
|
+
const result = await rerootCommandSession(s.cmdCtx, s.originalBasePath);
|
|
1293
1409
|
if (result.status === "cancelled") {
|
|
1294
|
-
logWarning("engine", "post-stop session re-root was cancelled", { file: "auto.ts", basePath: s.
|
|
1410
|
+
logWarning("engine", "post-stop session re-root was cancelled", { file: "auto.ts", basePath: s.originalBasePath });
|
|
1295
1411
|
} else if (result.status === "failed") {
|
|
1296
|
-
logWarning("engine", `post-stop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.
|
|
1412
|
+
logWarning("engine", `post-stop session re-root failed: ${result.error ?? "unknown"}`, { file: "auto.ts", basePath: s.originalBasePath });
|
|
1297
1413
|
}
|
|
1298
1414
|
}
|
|
1299
1415
|
|
|
1300
1416
|
// ── Step 8: Ledger notification ──
|
|
1301
1417
|
try {
|
|
1302
1418
|
const ledger = getLedger();
|
|
1419
|
+
const isAllComplete = reason === "All milestones complete";
|
|
1420
|
+
const isMilestoneComplete = /^Milestone\s+\S+\s+complete$/i.test(reason ?? "");
|
|
1421
|
+
const notificationPrefix = isAllComplete
|
|
1422
|
+
? "All milestones complete"
|
|
1423
|
+
: isMilestoneComplete
|
|
1424
|
+
? `${reason}. Auto-mode finished this milestone`
|
|
1425
|
+
: `Auto-mode stopped${reasonSuffix}`;
|
|
1303
1426
|
if (ledger && ledger.units.length > 0) {
|
|
1304
1427
|
const totals = getProjectTotals(ledger.units);
|
|
1305
1428
|
ctx?.ui.notify(
|
|
1306
|
-
|
|
1429
|
+
`${notificationPrefix}. Session: ${formatCost(totals.cost)} · ${formatTokenCount(totals.tokens.total)} tokens · ${ledger.units.length} units`,
|
|
1307
1430
|
"info",
|
|
1308
1431
|
);
|
|
1309
1432
|
} else {
|
|
1310
|
-
ctx?.ui.notify(
|
|
1433
|
+
ctx?.ui.notify(`${notificationPrefix}.`, "info");
|
|
1311
1434
|
}
|
|
1312
1435
|
} catch (e) {
|
|
1313
1436
|
debugLog("stop-cleanup-ledger", { error: e instanceof Error ? e.message : String(e) });
|
|
1314
1437
|
}
|
|
1315
1438
|
|
|
1439
|
+
if (preserveCompletionSurface && ctx && options.completionWidget) {
|
|
1440
|
+
const ledger = getLedger();
|
|
1441
|
+
const units = ledger?.units ?? [];
|
|
1442
|
+
const totals = units.length > 0 ? getProjectTotals(units) : null;
|
|
1443
|
+
let totalInput = 0;
|
|
1444
|
+
let totalCacheRead = 0;
|
|
1445
|
+
try {
|
|
1446
|
+
for (const entry of s.cmdCtx?.sessionManager?.getEntries?.() ?? []) {
|
|
1447
|
+
if (entry.type === "message") {
|
|
1448
|
+
const msgEntry = entry as SessionMessageEntry;
|
|
1449
|
+
if (msgEntry.message?.role === "assistant") {
|
|
1450
|
+
const usage = (msgEntry.message as any).usage;
|
|
1451
|
+
if (usage) {
|
|
1452
|
+
totalInput += usage.input || 0;
|
|
1453
|
+
totalCacheRead += usage.cacheRead || 0;
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
} catch (err) {
|
|
1459
|
+
logWarning("dashboard", `completion stats lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1460
|
+
}
|
|
1461
|
+
const contextUsage = s.cmdCtx?.getContextUsage?.();
|
|
1462
|
+
const milestoneId = completionMilestoneId;
|
|
1463
|
+
const rollup = loadMilestoneCompletionRollup(s.originalBasePath || s.basePath, milestoneId);
|
|
1464
|
+
setCompletionProgressWidget(ctx, {
|
|
1465
|
+
milestoneId,
|
|
1466
|
+
milestoneTitle: options.completionWidget.milestoneTitle ?? rollup.milestoneTitle,
|
|
1467
|
+
oneLiner: rollup.oneLiner,
|
|
1468
|
+
successCriteriaResults: rollup.successCriteriaResults,
|
|
1469
|
+
definitionOfDoneResults: rollup.definitionOfDoneResults,
|
|
1470
|
+
requirementOutcomes: rollup.requirementOutcomes,
|
|
1471
|
+
deviations: rollup.deviations,
|
|
1472
|
+
followUps: rollup.followUps,
|
|
1473
|
+
keyDecisions: rollup.keyDecisions,
|
|
1474
|
+
keyFiles: rollup.keyFiles,
|
|
1475
|
+
lessonsLearned: rollup.lessonsLearned,
|
|
1476
|
+
reason: reason ?? "Milestone complete",
|
|
1477
|
+
startedAt: s.autoStartTime,
|
|
1478
|
+
totalCost: totals?.cost ?? 0,
|
|
1479
|
+
totalTokens: totals?.tokens.total ?? 0,
|
|
1480
|
+
unitCount: units.length,
|
|
1481
|
+
cacheHitRate: totalCacheRead + totalInput > 0
|
|
1482
|
+
? (totalCacheRead / (totalCacheRead + totalInput)) * 100
|
|
1483
|
+
: null,
|
|
1484
|
+
contextPercent: contextUsage?.percent ?? null,
|
|
1485
|
+
contextWindow: contextUsage?.contextWindow ?? s.cmdCtx?.model?.contextWindow ?? null,
|
|
1486
|
+
completedSlices,
|
|
1487
|
+
totalSlices,
|
|
1488
|
+
allMilestonesComplete: options.completionWidget.allMilestonesComplete,
|
|
1489
|
+
basePath: s.originalBasePath || s.basePath || null,
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1316
1493
|
// ── Step 9: Cmux sidebar / event log ──
|
|
1317
1494
|
try {
|
|
1318
1495
|
pi?.events.emit(CMUX_CHANNELS.SIDEBAR, { action: "clear" as const, preferences: loadedPreferences });
|
|
@@ -1403,8 +1580,20 @@ export async function stopAuto(
|
|
|
1403
1580
|
|
|
1404
1581
|
// UI cleanup
|
|
1405
1582
|
ctx?.ui.setStatus("gsd-auto", undefined);
|
|
1406
|
-
|
|
1407
|
-
|
|
1583
|
+
if (!preserveCompletionSurface) {
|
|
1584
|
+
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
1585
|
+
const status = reason?.startsWith("Blocked:") ? "blocked" : reason?.toLowerCase().includes("fail") ? "failed" : "stopped";
|
|
1586
|
+
setLifecycleOutcome(ctx, {
|
|
1587
|
+
status,
|
|
1588
|
+
title: status === "blocked" ? "Auto-mode blocked" : status === "failed" ? "Auto-mode stopped with an issue" : "Auto-mode stopped",
|
|
1589
|
+
detail: reason ?? "Auto-mode stopped.",
|
|
1590
|
+
nextAction: status === "blocked"
|
|
1591
|
+
? "Fix the blocker, then run /gsd auto to resume."
|
|
1592
|
+
: "Run /gsd status for the current project state, or /gsd auto to continue.",
|
|
1593
|
+
commands: ["/gsd status for overview", "/gsd auto to run", "/gsd visualize to inspect", "/gsd notifications for history"],
|
|
1594
|
+
});
|
|
1595
|
+
if (ctx) initHealthWidget(ctx);
|
|
1596
|
+
}
|
|
1408
1597
|
restoreProjectRootEnv();
|
|
1409
1598
|
restoreMilestoneLockEnv();
|
|
1410
1599
|
|
|
@@ -1421,7 +1610,7 @@ export async function stopAuto(
|
|
|
1421
1610
|
}
|
|
1422
1611
|
|
|
1423
1612
|
// Reset all session state in one call
|
|
1424
|
-
s.
|
|
1613
|
+
s.resetAfterStop({ preserveCompletionSurface });
|
|
1425
1614
|
}
|
|
1426
1615
|
}
|
|
1427
1616
|
|
|
@@ -1495,6 +1684,8 @@ export async function pauseAuto(
|
|
|
1495
1684
|
logWarning("engine", `paused-session DB write failed: ${err instanceof Error ? err.message : String(err)}`, { file: "auto.ts" });
|
|
1496
1685
|
}
|
|
1497
1686
|
|
|
1687
|
+
const pausedUnitLabel = currentUnitLabel();
|
|
1688
|
+
|
|
1498
1689
|
// Close out the current unit so its runtime record doesn't stay at "dispatched"
|
|
1499
1690
|
if (s.currentUnit && ctx) {
|
|
1500
1691
|
try {
|
|
@@ -1545,8 +1736,16 @@ export async function pauseAuto(
|
|
|
1545
1736
|
s.verificationRetryCount.clear();
|
|
1546
1737
|
ctx?.ui.setStatus("gsd-auto", "paused");
|
|
1547
1738
|
ctx?.ui.setWidget("gsd-progress", undefined);
|
|
1548
|
-
if (ctx) initHealthWidget(ctx);
|
|
1549
1739
|
const resumeCmd = s.stepMode ? "/gsd next" : "/gsd auto";
|
|
1740
|
+
setLifecycleOutcome(ctx, {
|
|
1741
|
+
status: "paused",
|
|
1742
|
+
title: `${s.stepMode ? "Step" : "Auto"}-mode paused`,
|
|
1743
|
+
detail: _errorContext?.message ?? "Paused by user request.",
|
|
1744
|
+
nextAction: `Type to steer, or run ${resumeCmd} to resume.`,
|
|
1745
|
+
commands: [resumeCmd, "/gsd status for overview", "/gsd notifications for history"],
|
|
1746
|
+
unitLabel: pausedUnitLabel,
|
|
1747
|
+
});
|
|
1748
|
+
if (ctx) initHealthWidget(ctx);
|
|
1550
1749
|
ctx?.ui.notify(
|
|
1551
1750
|
`${s.stepMode ? "Step" : "Auto"}-mode paused (Escape). Type to interact, or ${resumeCmd} to resume.`,
|
|
1552
1751
|
"info",
|
|
@@ -1561,29 +1760,36 @@ export async function pauseAuto(
|
|
|
1561
1760
|
* deps bag is intentionally focused — Lifecycle does not see the wider auto-
|
|
1562
1761
|
* mode dependency graph.
|
|
1563
1762
|
*/
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1763
|
+
/**
|
|
1764
|
+
* Construct a `WorktreeLifecycleDeps` bag without binding to any session.
|
|
1765
|
+
*
|
|
1766
|
+
* Exported so session-less callers (currently `parallel-merge.ts`) can build
|
|
1767
|
+
* the same deps and call `mergeMilestoneStandalone` through the Worktree
|
|
1768
|
+
* Lifecycle Module instead of bypassing it (ADR-016 phase 2 / A2).
|
|
1769
|
+
*/
|
|
1770
|
+
export function buildWorktreeLifecycleDeps(): WorktreeLifecycleDeps {
|
|
1771
|
+
// ADR-016 phase 2 / C-track close-out:
|
|
1772
|
+
// C1 (#5624) — fs + git-CLI primitives inlined
|
|
1773
|
+
// C2 (#5625) — worktree-manager helpers inlined
|
|
1774
|
+
// C3 (#5626) — cache + preferences + paths inlined
|
|
1775
|
+
// C4 (#5627) — GitServiceImpl constructor → gitServiceFactory
|
|
1776
|
+
//
|
|
1777
|
+
// Final WorktreeLifecycleDeps shape: 3 fields (gitServiceFactory,
|
|
1778
|
+
// worktreeProjection, mergeMilestoneToMain). Down from 18 at slice-7
|
|
1779
|
+
// closure.
|
|
1780
|
+
return {
|
|
1781
|
+
gitServiceFactory: (basePath: string) => {
|
|
1782
|
+
const gitConfig =
|
|
1783
|
+
loadEffectiveGSDPreferences()?.preferences?.git ?? {};
|
|
1784
|
+
return new GitServiceImpl(basePath, gitConfig);
|
|
1785
|
+
},
|
|
1574
1786
|
worktreeProjection: new WorktreeStateProjection(),
|
|
1575
|
-
isInAutoWorktree,
|
|
1576
|
-
autoCommitCurrentBranch,
|
|
1577
|
-
autoWorktreeBranch,
|
|
1578
|
-
teardownAutoWorktree,
|
|
1579
1787
|
mergeMilestoneToMain,
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
} as unknown as WorktreeLifecycleDeps;
|
|
1586
|
-
return new WorktreeLifecycle(s, lifecycleDeps);
|
|
1788
|
+
};
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
function buildLifecycle(): WorktreeLifecycle {
|
|
1792
|
+
return new WorktreeLifecycle(s, buildWorktreeLifecycleDeps());
|
|
1587
1793
|
}
|
|
1588
1794
|
|
|
1589
1795
|
/**
|
|
@@ -1606,16 +1812,20 @@ export function createWiredAutoOrchestrationModule(
|
|
|
1606
1812
|
stateReconciliation: {
|
|
1607
1813
|
async reconcileBeforeDispatch() {
|
|
1608
1814
|
const result = await reconcileBeforeDispatch(dispatchBasePath);
|
|
1609
|
-
if (
|
|
1815
|
+
if (result.blockers.length > 0) {
|
|
1610
1816
|
return {
|
|
1611
1817
|
ok: false,
|
|
1612
|
-
reason: result.
|
|
1818
|
+
reason: result.blockers[0],
|
|
1613
1819
|
stateSnapshot: result.stateSnapshot,
|
|
1614
1820
|
};
|
|
1615
1821
|
}
|
|
1822
|
+
const repairedKinds = result.repaired.map((d) => d.kind);
|
|
1616
1823
|
return {
|
|
1617
1824
|
ok: true,
|
|
1618
|
-
reason:
|
|
1825
|
+
reason:
|
|
1826
|
+
repairedKinds.length > 0
|
|
1827
|
+
? `repaired: ${repairedKinds.join(", ")}`
|
|
1828
|
+
: "clean",
|
|
1619
1829
|
stateSnapshot: result.stateSnapshot,
|
|
1620
1830
|
};
|
|
1621
1831
|
},
|
|
@@ -1825,7 +2035,6 @@ function buildLoopDeps(pi: ExtensionAPI): LoopDeps {
|
|
|
1825
2035
|
pruneQueueOrder,
|
|
1826
2036
|
isInAutoWorktree,
|
|
1827
2037
|
shouldUseWorktreeIsolation,
|
|
1828
|
-
mergeMilestoneToMain,
|
|
1829
2038
|
teardownAutoWorktree,
|
|
1830
2039
|
createAutoWorktree,
|
|
1831
2040
|
captureIntegrationBranch,
|
|
@@ -2145,7 +2354,12 @@ export async function startAuto(
|
|
|
2145
2354
|
s.verbose = verboseMode;
|
|
2146
2355
|
s.stepMode = requestedStepMode;
|
|
2147
2356
|
s.cmdCtx = ctx;
|
|
2148
|
-
|
|
2357
|
+
// ADR-016 phase 2 / B2 (#5620): bootstrap basePath transition before
|
|
2358
|
+
// the resume path consults persisted worktree state. Defensive about
|
|
2359
|
+
// s.originalBasePath — the meta-restore above (line 2003 / 2055) may
|
|
2360
|
+
// have already populated it from paused metadata; the verb preserves
|
|
2361
|
+
// that value.
|
|
2362
|
+
buildLifecycle().adoptSessionRoot(base);
|
|
2149
2363
|
// ── Resume worktree: if the paused session was inside a milestone worktree,
|
|
2150
2364
|
// apply that path as the dispatch basePath immediately (#3723).
|
|
2151
2365
|
// This ensures the dispatch loop runs from the worktree directory even when
|
|
@@ -2161,7 +2375,8 @@ export async function startAuto(
|
|
|
2161
2375
|
{ file: "auto.ts", milestoneId: s.currentMilestoneId ?? "" },
|
|
2162
2376
|
);
|
|
2163
2377
|
}
|
|
2164
|
-
|
|
2378
|
+
// ADR-016 phase 2 / B3 (#5621): paused-resume worktree-path adoption.
|
|
2379
|
+
buildLifecycle().resumeFromPausedSession(base, resumeWorktreePath);
|
|
2165
2380
|
// Rebuild scope now that s.basePath reflects the actual worktree (or project root).
|
|
2166
2381
|
rebuildScope(s.basePath, s.currentMilestoneId);
|
|
2167
2382
|
// Ensure the workflow-logger audit log is pinned to the project root
|
|
@@ -2463,7 +2678,12 @@ export async function dispatchHookUnit(
|
|
|
2463
2678
|
s.pendingQuickTasks = [];
|
|
2464
2679
|
}
|
|
2465
2680
|
|
|
2466
|
-
|
|
2681
|
+
// ADR-016 phase 2 / B2 (#5620): hook-trigger basePath transition. Treats
|
|
2682
|
+
// the trigger as a bootstrap variant — if the session is fresh,
|
|
2683
|
+
// `originalBasePath` gets set to `targetBasePath`; if the session was
|
|
2684
|
+
// already active with an established `originalBasePath`, the verb
|
|
2685
|
+
// preserves it.
|
|
2686
|
+
buildLifecycle().adoptSessionRoot(targetBasePath);
|
|
2467
2687
|
if (!s.orchestration) {
|
|
2468
2688
|
ensureOrchestrationModule(ctx, pi, s.basePath);
|
|
2469
2689
|
}
|
|
@@ -12,7 +12,14 @@ import {
|
|
|
12
12
|
resetEmptyTurnCounter,
|
|
13
13
|
} from "../guided-flow.js";
|
|
14
14
|
import { clearPathCache } from "../paths.js";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
getAutoDashboardData,
|
|
17
|
+
getAutoModeStartModel,
|
|
18
|
+
isAutoActive,
|
|
19
|
+
isAutoCompletionStopInProgress,
|
|
20
|
+
pauseAuto,
|
|
21
|
+
setCurrentDispatchedModelId,
|
|
22
|
+
} from "../auto.js";
|
|
16
23
|
import { getNextFallbackModel, resolveModelWithFallbacksForUnit } from "../preferences.js";
|
|
17
24
|
import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
|
18
25
|
import {
|
|
@@ -146,8 +153,7 @@ export function isBareClaudeCodeStreamAbortPlaceholder(lastMsg: unknown): boolea
|
|
|
146
153
|
* Claude Code abort markers are intentionally ignored when the abort fires
|
|
147
154
|
* while the session-switch is in flight: the abort is the expected side-effect
|
|
148
155
|
* of the transition, not a user signal. Other branches (genuine `stopReason
|
|
149
|
-
* === "aborted"` with
|
|
150
|
-
* behavior.
|
|
156
|
+
* === "aborted"` with explicit errorMessage) preserve the prior behavior.
|
|
151
157
|
*/
|
|
152
158
|
export function _handleSessionSwitchAgentEnd(
|
|
153
159
|
lastMsg: unknown,
|
|
@@ -171,10 +177,8 @@ export function _handleSessionSwitchAgentEnd(
|
|
|
171
177
|
}
|
|
172
178
|
|
|
173
179
|
if (m.stopReason === "aborted") {
|
|
174
|
-
const content = m.content;
|
|
175
|
-
const hasEmptyContent = Array.isArray(content) && content.length === 0;
|
|
176
180
|
const hasErrorMessage = !!m.errorMessage;
|
|
177
|
-
if (
|
|
181
|
+
if (hasErrorMessage) {
|
|
178
182
|
resolveCancelled(_buildAbortedPauseContext(m as { errorMessage?: unknown }));
|
|
179
183
|
}
|
|
180
184
|
}
|
|
@@ -295,6 +299,12 @@ export async function handleAgentEnd(
|
|
|
295
299
|
}
|
|
296
300
|
|
|
297
301
|
if (isObjectRecord(lastMsg) && "stopReason" in lastMsg && lastMsg.stopReason === "aborted") {
|
|
302
|
+
if (isAutoCompletionStopInProgress()) {
|
|
303
|
+
resetRetryState(retryState);
|
|
304
|
+
resolveAgentEnd(event);
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
|
|
298
308
|
// Empty content with aborted stopReason is a non-fatal agent stop (the LLM
|
|
299
309
|
// chose to end without producing output). Only pause on genuine fatal aborts
|
|
300
310
|
// that carry error context — e.g. errorMessage field or non-empty content
|
|
@@ -326,6 +336,11 @@ export async function handleAgentEnd(
|
|
|
326
336
|
// errorMessage looks uninformative.
|
|
327
337
|
const rawErrorMsg = ("errorMessage" in lastMsg && lastMsg.errorMessage) ? String(lastMsg.errorMessage) : "";
|
|
328
338
|
if (isUserInitiatedAbortMessage(rawErrorMsg)) {
|
|
339
|
+
if (isAutoCompletionStopInProgress()) {
|
|
340
|
+
resetRetryState(retryState);
|
|
341
|
+
resolveAgentEnd(event);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
329
344
|
resolveAgentEndCancelled({
|
|
330
345
|
message: rawErrorMsg,
|
|
331
346
|
category: "aborted",
|