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
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
// GSD-2 + src/resources/extensions/gsd/auto-dashboard.ts - Auto-mode progress widget rendering and dashboard helpers.
|
|
2
|
-
import { getCurrentBranch } from "./worktree.js";
|
|
3
2
|
import { getActiveHook } from "./post-unit-hooks.js";
|
|
4
|
-
import { getLedger
|
|
3
|
+
import { getLedger } from "./metrics.js";
|
|
5
4
|
import { getErrorMessage } from "./error-utils.js";
|
|
6
5
|
import { nativeIsRepo } from "./native-git-bridge.js";
|
|
7
6
|
import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
|
|
@@ -10,15 +9,12 @@ import { execFileSync } from "node:child_process";
|
|
|
10
9
|
import { truncateToWidth, visibleWidth } from "@gsd/pi-tui";
|
|
11
10
|
import { makeUI } from "../shared/tui.js";
|
|
12
11
|
import { GLYPH, INDENT } from "../shared/mod.js";
|
|
12
|
+
import { padRightVisible, renderFrame, renderProgressBar, rightAlign, wrapVisibleText } from "./tui/render-kit.js";
|
|
13
13
|
import { computeProgressScore } from "./progress-score.js";
|
|
14
|
-
import { getActiveWorktreeName } from "./worktree-command.js";
|
|
15
14
|
import { getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, parsePreferencesMarkdown, } from "./preferences.js";
|
|
16
|
-
import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.js";
|
|
17
15
|
import { parseUnitId } from "./unit-id.js";
|
|
18
|
-
import { formatRtkSavingsLabel, getRtkSessionSavings, } from "../shared/rtk-session-stats.js";
|
|
19
16
|
import { logWarning } from "./workflow-logger.js";
|
|
20
17
|
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
21
|
-
import { homedir } from "node:os";
|
|
22
18
|
import { readUnitRuntimeRecord } from "./unit-runtime.js";
|
|
23
19
|
// ─── UAT Slice Extraction ─────────────────────────────────────────────────────
|
|
24
20
|
/**
|
|
@@ -468,6 +464,7 @@ export function _resetWidgetModeForTests() {
|
|
|
468
464
|
export function updateProgressWidget(ctx, unitType, unitId, state, accessors, tierBadge) {
|
|
469
465
|
if (!ctx.hasUI)
|
|
470
466
|
return;
|
|
467
|
+
ctx.ui.setWidget("gsd-outcome", undefined);
|
|
471
468
|
// Welcome header is a startup-only banner — permanently suppress it once
|
|
472
469
|
// auto-mode activates. The dashboard widget owns all status from here.
|
|
473
470
|
// Note: setHeader(undefined) restores the built-in header (logo +
|
|
@@ -497,53 +494,11 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
497
494
|
if (mid) {
|
|
498
495
|
updateSliceProgressCache(accessors.getBasePath(), mid.id, slice?.id);
|
|
499
496
|
}
|
|
500
|
-
// Cache git branch at widget creation time (not per render)
|
|
501
|
-
let cachedBranch = null;
|
|
502
|
-
try {
|
|
503
|
-
cachedBranch = getCurrentBranch(accessors.getBasePath());
|
|
504
|
-
}
|
|
505
|
-
catch (err) { /* not in git repo */
|
|
506
|
-
logWarning("dashboard", `git branch detection failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
507
|
-
}
|
|
508
|
-
// Cache short pwd (last 2 path segments only) + worktree/branch info
|
|
509
|
-
let widgetPwd;
|
|
510
|
-
{
|
|
511
|
-
let fullPwd = process.cwd();
|
|
512
|
-
const widgetHome = homedir();
|
|
513
|
-
if (widgetHome && (fullPwd === widgetHome || fullPwd.startsWith(widgetHome + "/") || fullPwd.startsWith(widgetHome + "\\"))) {
|
|
514
|
-
fullPwd = `~${fullPwd.slice(widgetHome.length)}`;
|
|
515
|
-
}
|
|
516
|
-
const parts = fullPwd.split("/");
|
|
517
|
-
widgetPwd = parts.length > 2 ? parts.slice(-2).join("/") : fullPwd;
|
|
518
|
-
}
|
|
519
|
-
const worktreeName = getActiveWorktreeName();
|
|
520
|
-
if (worktreeName && cachedBranch) {
|
|
521
|
-
widgetPwd = `${widgetPwd} (\u2387 ${cachedBranch})`;
|
|
522
|
-
}
|
|
523
|
-
else if (cachedBranch) {
|
|
524
|
-
widgetPwd = `${widgetPwd} (${cachedBranch})`;
|
|
525
|
-
}
|
|
526
|
-
// Pre-fetch last commit for display
|
|
527
|
-
refreshLastCommit(accessors.getBasePath());
|
|
528
|
-
// Cache the effective service tier at widget creation time (reads preferences)
|
|
529
|
-
const effectiveServiceTier = getEffectiveServiceTier();
|
|
530
497
|
ctx.ui.setWidget("gsd-progress", (tui, theme) => {
|
|
531
498
|
let pulseBright = true;
|
|
532
499
|
let cachedLines;
|
|
533
500
|
let cachedWidth;
|
|
534
|
-
let cachedRtkLabel;
|
|
535
501
|
let cachedRuntimeRecord = null;
|
|
536
|
-
const refreshRtkLabel = () => {
|
|
537
|
-
try {
|
|
538
|
-
const sessionId = ctx.sessionManager.getSessionId();
|
|
539
|
-
const savings = sessionId ? getRtkSessionSavings(accessors.getBasePath(), sessionId) : null;
|
|
540
|
-
cachedRtkLabel = formatRtkSavingsLabel(savings);
|
|
541
|
-
}
|
|
542
|
-
catch (err) {
|
|
543
|
-
logWarning("dashboard", `RTK savings lookup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
544
|
-
cachedRtkLabel = null;
|
|
545
|
-
}
|
|
546
|
-
};
|
|
547
502
|
const refreshRuntimeRecord = () => {
|
|
548
503
|
try {
|
|
549
504
|
cachedRuntimeRecord = readUnitRuntimeRecord(accessors.getBasePath(), unitType, unitId);
|
|
@@ -552,7 +507,6 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
552
507
|
cachedRuntimeRecord = null;
|
|
553
508
|
}
|
|
554
509
|
};
|
|
555
|
-
refreshRtkLabel();
|
|
556
510
|
refreshRuntimeRecord();
|
|
557
511
|
const pulseTimer = setInterval(() => {
|
|
558
512
|
pulseBright = !pulseBright;
|
|
@@ -568,7 +522,6 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
568
522
|
if (mid) {
|
|
569
523
|
updateSliceProgressCache(accessors.getBasePath(), mid.id, slice?.id);
|
|
570
524
|
}
|
|
571
|
-
refreshRtkLabel();
|
|
572
525
|
refreshRuntimeRecord();
|
|
573
526
|
cachedLines = undefined;
|
|
574
527
|
}
|
|
@@ -635,44 +588,6 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
635
588
|
lines.push(`${pad} ${signalStr}`);
|
|
636
589
|
}
|
|
637
590
|
}
|
|
638
|
-
// ── Gather stats (needed by multiple modes) ─────────────────────
|
|
639
|
-
const cmdCtx = accessors.getCmdCtx();
|
|
640
|
-
let totalInput = 0;
|
|
641
|
-
let totalCacheRead = 0;
|
|
642
|
-
if (cmdCtx) {
|
|
643
|
-
for (const entry of cmdCtx.sessionManager.getEntries()) {
|
|
644
|
-
if (entry.type === "message") {
|
|
645
|
-
const msgEntry = entry;
|
|
646
|
-
if (msgEntry.message?.role === "assistant") {
|
|
647
|
-
const u = msgEntry.message.usage;
|
|
648
|
-
if (u) {
|
|
649
|
-
totalInput += u.input || 0;
|
|
650
|
-
totalCacheRead += u.cacheRead || 0;
|
|
651
|
-
}
|
|
652
|
-
}
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
}
|
|
656
|
-
const mLedger = getLedger();
|
|
657
|
-
const autoTotals = mLedger ? getProjectTotals(mLedger.units) : null;
|
|
658
|
-
const cumulativeCost = autoTotals?.cost ?? 0;
|
|
659
|
-
const cxUsage = cmdCtx?.getContextUsage?.();
|
|
660
|
-
const cxWindow = cxUsage?.contextWindow ?? cmdCtx?.model?.contextWindow ?? 0;
|
|
661
|
-
const cxPctVal = cxUsage?.percent ?? 0;
|
|
662
|
-
const cxPct = cxUsage?.percent !== null ? cxPctVal.toFixed(1) : "?";
|
|
663
|
-
// Model display — prefer dispatched model ID (set after selectAndApplyModel
|
|
664
|
-
// + hook overrides) over cmdCtx?.model which can be stale (#2899).
|
|
665
|
-
const dispatchedModelId = accessors.getCurrentDispatchedModelId();
|
|
666
|
-
const modelId = dispatchedModelId
|
|
667
|
-
? dispatchedModelId.split("/").slice(1).join("/") || dispatchedModelId
|
|
668
|
-
: (cmdCtx?.model?.id ?? "");
|
|
669
|
-
const modelProvider = dispatchedModelId
|
|
670
|
-
? dispatchedModelId.split("/")[0] || ""
|
|
671
|
-
: (cmdCtx?.model?.provider ?? "");
|
|
672
|
-
const tierIcon = resolveServiceTierIcon(effectiveServiceTier, modelId);
|
|
673
|
-
const modelDisplay = (modelProvider && modelId
|
|
674
|
-
? `${modelProvider}/${modelId}`
|
|
675
|
-
: modelId) + (tierIcon ? ` ${tierIcon}` : "");
|
|
676
591
|
// ── Mode: off — return empty ──────────────────────────────────
|
|
677
592
|
if (widgetMode === "off") {
|
|
678
593
|
cachedLines = [];
|
|
@@ -686,7 +601,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
686
601
|
cachedWidth = width;
|
|
687
602
|
return lines;
|
|
688
603
|
}
|
|
689
|
-
// ── Mode: small — header +
|
|
604
|
+
// ── Mode: small — header + active work progress ───────────────
|
|
690
605
|
if (widgetMode === "small") {
|
|
691
606
|
lines.push("");
|
|
692
607
|
// Action line
|
|
@@ -698,10 +613,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
698
613
|
if (shouldRenderRoadmapProgress(roadmapSlices)) {
|
|
699
614
|
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
700
615
|
const barWidth = Math.max(6, Math.min(18, Math.floor(width * 0.25)));
|
|
701
|
-
const
|
|
702
|
-
const filled = Math.round(pct * barWidth);
|
|
703
|
-
const bar = theme.fg("success", "━".repeat(filled))
|
|
704
|
-
+ theme.fg("dim", "─".repeat(barWidth - filled));
|
|
616
|
+
const bar = renderProgressBar(theme, done, total, barWidth);
|
|
705
617
|
let meta = `${theme.fg("text", `${done}`)}${theme.fg("dim", `/${total} slices`)}`;
|
|
706
618
|
if (activeSliceTasks && activeSliceTasks.total > 0) {
|
|
707
619
|
const tn = Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
|
|
@@ -709,20 +621,6 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
709
621
|
}
|
|
710
622
|
lines.push(`${pad}${bar} ${meta}`);
|
|
711
623
|
}
|
|
712
|
-
// Compact stats: cost + context only
|
|
713
|
-
const smallStats = [];
|
|
714
|
-
if (cumulativeCost)
|
|
715
|
-
smallStats.push(theme.fg("warning", `$${cumulativeCost.toFixed(2)}`));
|
|
716
|
-
const cxDisplay = `${cxPct}%ctx`;
|
|
717
|
-
if (cxPctVal > 90)
|
|
718
|
-
smallStats.push(theme.fg("error", cxDisplay));
|
|
719
|
-
else if (cxPctVal > 70)
|
|
720
|
-
smallStats.push(theme.fg("warning", cxDisplay));
|
|
721
|
-
else
|
|
722
|
-
smallStats.push(theme.fg("dim", cxDisplay));
|
|
723
|
-
if (smallStats.length > 0) {
|
|
724
|
-
lines.push(rightAlign("", smallStats.join(theme.fg("dim", " ")), width));
|
|
725
|
-
}
|
|
726
624
|
lines.push(...ui.bar());
|
|
727
625
|
cachedLines = lines;
|
|
728
626
|
cachedWidth = width;
|
|
@@ -730,11 +628,10 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
730
628
|
}
|
|
731
629
|
// ── Mode: full — complete two-column layout ───────────────────
|
|
732
630
|
lines.push("");
|
|
733
|
-
// Context section: milestone + slice
|
|
631
|
+
// Context section: milestone + slice. Footer owns model/cost/context.
|
|
734
632
|
const hasContext = !!(mid || (slice && unitType !== "research-milestone" && unitType !== "plan-milestone"));
|
|
735
633
|
if (mid) {
|
|
736
|
-
|
|
737
|
-
lines.push(truncateToWidth(`${pad}${theme.fg("dim", mid.title)}${modelTag}`, width, "…"));
|
|
634
|
+
lines.push(truncateToWidth(`${pad}${theme.fg("dim", mid.title)}`, width, "…"));
|
|
738
635
|
}
|
|
739
636
|
if (slice && unitType !== "research-milestone" && unitType !== "plan-milestone") {
|
|
740
637
|
lines.push(truncateToWidth(`${pad}${theme.fg("text", theme.bold(`${slice.id}: ${slice.title}`))}`, width, "…"));
|
|
@@ -759,10 +656,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
759
656
|
if (shouldRenderRoadmapProgress(roadmapSlices)) {
|
|
760
657
|
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
761
658
|
const barWidth = Math.max(6, Math.min(18, Math.floor(leftColWidth * 0.4)));
|
|
762
|
-
const
|
|
763
|
-
const filled = Math.round(pct * barWidth);
|
|
764
|
-
const bar = theme.fg("success", "━".repeat(filled))
|
|
765
|
-
+ theme.fg("dim", "─".repeat(barWidth - filled));
|
|
659
|
+
const bar = renderProgressBar(theme, done, total, barWidth);
|
|
766
660
|
let meta = `${theme.fg("text", `${done}`)}${theme.fg("dim", `/${total} slices`)}`;
|
|
767
661
|
if (activeSliceTasks && activeSliceTasks.total > 0) {
|
|
768
662
|
const taskNum = isHook
|
|
@@ -818,7 +712,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
818
712
|
if (maxRows > 0) {
|
|
819
713
|
lines.push("");
|
|
820
714
|
for (let i = 0; i < maxRows; i++) {
|
|
821
|
-
const left =
|
|
715
|
+
const left = padRightVisible(truncateToWidth(leftLines[i] ?? "", leftColWidth, "…"), leftColWidth);
|
|
822
716
|
const right = rightLines[i] ?? "";
|
|
823
717
|
lines.push(`${left}${right}`);
|
|
824
718
|
}
|
|
@@ -831,46 +725,8 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
831
725
|
lines.push(truncateToWidth(l, width, "…"));
|
|
832
726
|
}
|
|
833
727
|
}
|
|
834
|
-
// ──
|
|
728
|
+
// ── Auto controls. Footer owns cwd/branch/model/cost/context. ───
|
|
835
729
|
lines.push("");
|
|
836
|
-
{
|
|
837
|
-
const sp = [];
|
|
838
|
-
if (totalCacheRead + totalInput > 0) {
|
|
839
|
-
const hitRate = Math.round((totalCacheRead / (totalCacheRead + totalInput)) * 100);
|
|
840
|
-
const hitColor = hitRate >= 70 ? "success" : hitRate >= 40 ? "warning" : "error";
|
|
841
|
-
sp.push(theme.fg(hitColor, `${hitRate}%hit`));
|
|
842
|
-
}
|
|
843
|
-
if (cumulativeCost)
|
|
844
|
-
sp.push(theme.fg("warning", `$${cumulativeCost.toFixed(2)}`));
|
|
845
|
-
const CX_BAR_WIDTH = 8;
|
|
846
|
-
const cxBarFilled = Math.min(CX_BAR_WIDTH, Math.max(0, Math.round((cxPctVal / 100) * CX_BAR_WIDTH)));
|
|
847
|
-
const cxBarColor = cxPctVal > 90 ? "error" : cxPctVal > 70 ? "warning" : "success";
|
|
848
|
-
const cxBar = theme.fg(cxBarColor, "━".repeat(cxBarFilled)) +
|
|
849
|
-
theme.fg("dim", "─".repeat(CX_BAR_WIDTH - cxBarFilled));
|
|
850
|
-
const cxPctText = `${cxPct}%/${formatWidgetTokens(cxWindow)}`;
|
|
851
|
-
const cxColorized = cxPctVal > 90
|
|
852
|
-
? theme.fg("error", cxPctText)
|
|
853
|
-
: cxPctVal > 70
|
|
854
|
-
? theme.fg("warning", cxPctText)
|
|
855
|
-
: cxPctText;
|
|
856
|
-
sp.push(`${cxBar} ${cxColorized}`);
|
|
857
|
-
const statsLine = sp.map(p => p.includes("\x1b[") ? p : theme.fg("dim", p))
|
|
858
|
-
.join(theme.fg("dim", " "));
|
|
859
|
-
if (statsLine) {
|
|
860
|
-
lines.push(rightAlign("", statsLine, width));
|
|
861
|
-
}
|
|
862
|
-
if (cachedRtkLabel) {
|
|
863
|
-
lines.push(rightAlign("", theme.fg("dim", cachedRtkLabel), width));
|
|
864
|
-
}
|
|
865
|
-
}
|
|
866
|
-
// Last commit info
|
|
867
|
-
const lastCommit = getLastCommit(accessors.getBasePath());
|
|
868
|
-
const maxCommitLen = 65;
|
|
869
|
-
const commitMsg = lastCommit
|
|
870
|
-
? lastCommit.message.length > maxCommitLen
|
|
871
|
-
? lastCommit.message.slice(0, maxCommitLen - 1) + "…"
|
|
872
|
-
: lastCommit.message
|
|
873
|
-
: "";
|
|
874
730
|
// Step-mode guidance — shown above keyboard hints when auto is paused
|
|
875
731
|
if (accessors.isStepMode()) {
|
|
876
732
|
lines.push(`${pad}${theme.fg("accent", "→")} ${theme.fg("dim", "Ctrl+N to advance to next step · /gsd status for overview")}`);
|
|
@@ -881,16 +737,7 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
881
737
|
hintParts.push(`${formattedShortcutPair("dashboard")} dashboard`);
|
|
882
738
|
hintParts.push(`${formattedShortcutPair("parallel")} parallel`);
|
|
883
739
|
const hintStr = theme.fg("dim", hintParts.join(" | "));
|
|
884
|
-
|
|
885
|
-
? theme.fg("dim", `${lastCommit.timeAgo} ago: ${commitMsg}`)
|
|
886
|
-
: "";
|
|
887
|
-
const locationStr = theme.fg("dim", widgetPwd);
|
|
888
|
-
if (commitStr) {
|
|
889
|
-
lines.push(rightAlign(`${pad}${locationStr} · ${commitStr}`, hintStr, width));
|
|
890
|
-
}
|
|
891
|
-
else {
|
|
892
|
-
lines.push(rightAlign(`${pad}${locationStr}`, hintStr, width));
|
|
893
|
-
}
|
|
740
|
+
lines.push(rightAlign("", hintStr, width));
|
|
894
741
|
lines.push(...ui.bar());
|
|
895
742
|
cachedLines = lines;
|
|
896
743
|
cachedWidth = width;
|
|
@@ -908,18 +755,175 @@ export function updateProgressWidget(ctx, unitType, unitId, state, accessors, ti
|
|
|
908
755
|
};
|
|
909
756
|
});
|
|
910
757
|
}
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
}
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
758
|
+
export function setCompletionProgressWidget(ctx, snapshot) {
|
|
759
|
+
if (!ctx.hasUI)
|
|
760
|
+
return;
|
|
761
|
+
ctx.ui.setWidget("gsd-outcome", undefined);
|
|
762
|
+
if (typeof ctx.ui?.setHeader === "function") {
|
|
763
|
+
ctx.ui.setHeader(() => ({
|
|
764
|
+
render() { return []; },
|
|
765
|
+
invalidate() { },
|
|
766
|
+
}));
|
|
767
|
+
}
|
|
768
|
+
if (typeof ctx.ui?.setStatus === "function") {
|
|
769
|
+
ctx.ui.setStatus("gsd-step", undefined);
|
|
770
|
+
}
|
|
771
|
+
ctx.ui.setWidget("gsd-progress", (_tui, theme) => ({
|
|
772
|
+
render(width) {
|
|
773
|
+
const ui = makeUI(theme, width);
|
|
774
|
+
const pad = INDENT.base;
|
|
775
|
+
const lines = [];
|
|
776
|
+
const contentWidth = Math.max(20, width - visibleWidth(pad));
|
|
777
|
+
const add = (line = "") => {
|
|
778
|
+
lines.push(line ? truncateToWidth(`${pad}${line}`, width, "…") : "");
|
|
779
|
+
};
|
|
780
|
+
const addSection = (label, value, indent = "") => {
|
|
781
|
+
const clean = normalizeRollupText(value);
|
|
782
|
+
if (!clean)
|
|
783
|
+
return;
|
|
784
|
+
add(`${indent}${theme.fg("accent", label)} ${theme.fg("text", truncateToWidth(clean, contentWidth - indent.length - label.length - 1, "…"))}`);
|
|
785
|
+
};
|
|
786
|
+
const addList = (label, values, limit, indent = "") => {
|
|
787
|
+
const clean = (values ?? []).map(normalizeRollupText).filter((v) => !!v);
|
|
788
|
+
if (clean.length === 0)
|
|
789
|
+
return;
|
|
790
|
+
const shown = clean.slice(0, limit);
|
|
791
|
+
const more = clean.length > shown.length ? ` (+${clean.length - shown.length} more)` : "";
|
|
792
|
+
add(`${indent}${theme.fg("accent", label)} ${theme.fg("text", truncateToWidth(shown.join("; ") + more, contentWidth - indent.length - label.length - 1, "…"))}`);
|
|
793
|
+
};
|
|
794
|
+
lines.push(...ui.bar());
|
|
795
|
+
const elapsed = formatAutoElapsed(snapshot.startedAt);
|
|
796
|
+
const heading = snapshot.allMilestonesComplete
|
|
797
|
+
? "All milestones complete"
|
|
798
|
+
: snapshot.milestoneId
|
|
799
|
+
? `Milestone ${snapshot.milestoneId} roll-up`
|
|
800
|
+
: "Milestone roll-up";
|
|
801
|
+
lines.push(rightAlign(`${pad}${theme.fg("accent", theme.bold(heading))}`, elapsed ? theme.fg("dim", elapsed) : "", width));
|
|
802
|
+
if (snapshot.milestoneTitle) {
|
|
803
|
+
add(theme.fg("text", snapshot.milestoneTitle));
|
|
804
|
+
}
|
|
805
|
+
lines.push("");
|
|
806
|
+
add(theme.fg("accent", "Outcome"));
|
|
807
|
+
addSection("", snapshot.oneLiner, " ");
|
|
808
|
+
const changed = [
|
|
809
|
+
...(snapshot.successCriteriaResults ? [snapshot.successCriteriaResults] : []),
|
|
810
|
+
...(snapshot.requirementOutcomes ? [snapshot.requirementOutcomes] : []),
|
|
811
|
+
...(snapshot.keyDecisions ?? []),
|
|
812
|
+
].map(normalizeRollupText).filter((v) => !!v).slice(0, 4);
|
|
813
|
+
if (changed.length > 0) {
|
|
814
|
+
lines.push("");
|
|
815
|
+
add(theme.fg("accent", "What changed"));
|
|
816
|
+
for (const item of changed)
|
|
817
|
+
add(` - ${theme.fg("text", item)}`);
|
|
818
|
+
}
|
|
819
|
+
const verification = [
|
|
820
|
+
snapshot.definitionOfDoneResults,
|
|
821
|
+
snapshot.deviations ? `Deviations: ${snapshot.deviations}` : null,
|
|
822
|
+
snapshot.followUps ? `Follow-ups: ${snapshot.followUps}` : null,
|
|
823
|
+
].map(normalizeRollupText).filter((v) => !!v);
|
|
824
|
+
if (verification.length > 0 || (snapshot.keyFiles?.length ?? 0) > 0) {
|
|
825
|
+
lines.push("");
|
|
826
|
+
add(theme.fg("accent", "Verification"));
|
|
827
|
+
for (const item of verification.slice(0, 3))
|
|
828
|
+
add(` - ${theme.fg("text", item)}`);
|
|
829
|
+
addList("Files:", snapshot.keyFiles, 4, " ");
|
|
830
|
+
}
|
|
831
|
+
if ((snapshot.lessonsLearned?.length ?? 0) > 0) {
|
|
832
|
+
lines.push("");
|
|
833
|
+
addList("Lessons:", snapshot.lessonsLearned, 2);
|
|
834
|
+
}
|
|
835
|
+
const hasSliceTotals = typeof snapshot.completedSlices === "number" && typeof snapshot.totalSlices === "number" && snapshot.totalSlices > 0;
|
|
836
|
+
lines.push("");
|
|
837
|
+
const stats = [];
|
|
838
|
+
if (hasSliceTotals)
|
|
839
|
+
stats.push(theme.fg("success", `${snapshot.completedSlices}/${snapshot.totalSlices} slices`));
|
|
840
|
+
if (snapshot.unitCount > 0)
|
|
841
|
+
stats.push(theme.fg("dim", `${snapshot.unitCount} units`));
|
|
842
|
+
if (snapshot.totalTokens > 0)
|
|
843
|
+
stats.push(theme.fg("dim", `${formatWidgetTokens(snapshot.totalTokens)} tokens`));
|
|
844
|
+
if (snapshot.totalCost > 0)
|
|
845
|
+
stats.push(theme.fg("warning", `$${snapshot.totalCost.toFixed(2)}`));
|
|
846
|
+
if (typeof snapshot.cacheHitRate === "number") {
|
|
847
|
+
const hitColor = snapshot.cacheHitRate >= 70 ? "success" : snapshot.cacheHitRate >= 40 ? "warning" : "error";
|
|
848
|
+
stats.push(theme.fg(hitColor, `${Math.round(snapshot.cacheHitRate)}% cache hit`));
|
|
849
|
+
}
|
|
850
|
+
if (stats.length > 0) {
|
|
851
|
+
add(`${theme.fg("accent", "Run totals")} ${stats.join(theme.fg("dim", " · "))}`);
|
|
852
|
+
}
|
|
853
|
+
lines.push("");
|
|
854
|
+
const nextAction = snapshot.allMilestonesComplete
|
|
855
|
+
? "Review the roll-up, then start a new milestone when ready."
|
|
856
|
+
: "Review the roll-up, inspect status, or continue to the next milestone.";
|
|
857
|
+
const commands = snapshot.allMilestonesComplete
|
|
858
|
+
? ["/gsd status for overview", "/gsd visualize to inspect", "/gsd notifications for history", "/gsd start for new work"]
|
|
859
|
+
: ["/gsd status for overview", "/gsd visualize to inspect", "/gsd notifications for history", "/gsd auto for next milestone"];
|
|
860
|
+
add(`${theme.fg("success", "Next")} ${theme.fg("text", nextAction)}`);
|
|
861
|
+
add(theme.fg("dim", commands.join(" · ")));
|
|
862
|
+
const location = snapshot.basePath ? theme.fg("dim", snapshot.basePath) : "";
|
|
863
|
+
const reason = theme.fg("dim", snapshot.reason);
|
|
864
|
+
lines.push(rightAlign(`${pad}${truncateToWidth(location, Math.max(0, width - 32), "…")}`, reason, width));
|
|
865
|
+
lines.push(...ui.bar());
|
|
866
|
+
return lines;
|
|
867
|
+
},
|
|
868
|
+
invalidate() { },
|
|
869
|
+
dispose() { },
|
|
870
|
+
}));
|
|
871
|
+
}
|
|
872
|
+
export function setAutoOutcomeWidget(ctx, snapshot) {
|
|
873
|
+
if (!ctx.hasUI)
|
|
874
|
+
return;
|
|
875
|
+
ctx.ui.setWidget("gsd-outcome", (_tui, theme) => ({
|
|
876
|
+
render(width) {
|
|
877
|
+
const color = snapshot.status === "failed" || snapshot.status === "blocked"
|
|
878
|
+
? "warning"
|
|
879
|
+
: snapshot.status === "complete"
|
|
880
|
+
? "success"
|
|
881
|
+
: "borderAccent";
|
|
882
|
+
const icon = snapshot.status === "complete" ? "✓"
|
|
883
|
+
: snapshot.status === "failed" ? "x"
|
|
884
|
+
: snapshot.status === "blocked" ? "!"
|
|
885
|
+
: snapshot.status === "paused" ? "||"
|
|
886
|
+
: "●";
|
|
887
|
+
const innerWidth = Math.max(8, width - 4);
|
|
888
|
+
const maxLines = 7;
|
|
889
|
+
const lines = [];
|
|
890
|
+
const elapsed = snapshot.startedAt ? formatAutoElapsed(snapshot.startedAt) : "";
|
|
891
|
+
const heading = `${theme.fg(color, icon)} ${theme.fg("accent", theme.bold("GSD"))} ${theme.fg("text", snapshot.title)}`;
|
|
892
|
+
lines.push(rightAlign(heading, elapsed ? theme.fg("dim", elapsed) : "", innerWidth));
|
|
893
|
+
const commands = snapshot.commands?.filter(Boolean) ?? [];
|
|
894
|
+
const commandLine = commands.length > 0 ? theme.fg("dim", commands.join(" · ")) : null;
|
|
895
|
+
const addWrapped = (text, prefix = "") => {
|
|
896
|
+
const reserve = commandLine ? 1 : 0;
|
|
897
|
+
const remaining = Math.max(0, maxLines - reserve - lines.length);
|
|
898
|
+
if (remaining === 0)
|
|
899
|
+
return;
|
|
900
|
+
const available = Math.max(8, innerWidth - visibleWidth(prefix));
|
|
901
|
+
for (const [idx, line] of wrapVisibleText(text, available).slice(0, remaining).entries()) {
|
|
902
|
+
lines.push(`${idx === 0 ? prefix : " ".repeat(visibleWidth(prefix))}${line}`);
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
if (snapshot.detail) {
|
|
906
|
+
addWrapped(snapshot.detail, `${theme.fg("dim", "Reason")} `);
|
|
907
|
+
}
|
|
908
|
+
if (snapshot.unitLabel) {
|
|
909
|
+
addWrapped(snapshot.unitLabel, `${theme.fg("dim", "Last")} `);
|
|
910
|
+
}
|
|
911
|
+
addWrapped(snapshot.nextAction, `${theme.fg("success", "Next")} `);
|
|
912
|
+
if (commandLine && lines.length < maxLines) {
|
|
913
|
+
lines.push(commandLine);
|
|
914
|
+
}
|
|
915
|
+
return renderFrame(theme, lines, width, { borderColor: color, paddingX: 1 });
|
|
916
|
+
},
|
|
917
|
+
invalidate() { },
|
|
918
|
+
dispose() { },
|
|
919
|
+
}));
|
|
920
|
+
}
|
|
921
|
+
function normalizeRollupText(value) {
|
|
922
|
+
const clean = value
|
|
923
|
+
?.replace(/\s+/g, " ")
|
|
924
|
+
.replace(/^[-*]\s+/, "")
|
|
925
|
+
.trim();
|
|
926
|
+
if (!clean || clean === "(none)" || clean === "None." || clean === "Not provided.")
|
|
927
|
+
return null;
|
|
928
|
+
return clean;
|
|
925
929
|
}
|
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Each rule maps a GSD state to the unit type, unit ID, and prompt builder
|
|
5
|
-
* that should be dispatched. Rules are evaluated in order; the first match wins.
|
|
6
|
-
*
|
|
7
|
-
* This replaces the 130-line if-else chain in dispatchNextUnit with a
|
|
8
|
-
* data structure that is inspectable, testable per-rule, and extensible
|
|
9
|
-
* without modifying orchestration code.
|
|
10
|
-
*/
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Declarative auto-mode dispatch rules and dispatch resolver.
|
|
11
3
|
import { loadFile, extractUatType, loadActiveOverrides } from "./files.js";
|
|
12
4
|
import { isDbAvailable, getMilestoneSlices, getPendingGates, markAllGatesOmitted, getMilestone, insertAssessment, transaction } from "./gsd-db.js";
|
|
13
5
|
import { isClosedStatus } from "./status-guards.js";
|
|
@@ -1191,9 +1183,20 @@ export const DISPATCH_RULES = [
|
|
|
1191
1183
|
},
|
|
1192
1184
|
{
|
|
1193
1185
|
name: "complete → stop",
|
|
1194
|
-
match: async ({ state }) => {
|
|
1186
|
+
match: async ({ state, mid, midTitle, basePath }) => {
|
|
1195
1187
|
if (state.phase !== "complete")
|
|
1196
1188
|
return null;
|
|
1189
|
+
if (mid && isDbAvailable()) {
|
|
1190
|
+
const milestone = getMilestone(mid);
|
|
1191
|
+
if (milestone && !isClosedStatus(milestone.status)) {
|
|
1192
|
+
return {
|
|
1193
|
+
action: "dispatch",
|
|
1194
|
+
unitType: "complete-milestone",
|
|
1195
|
+
unitId: mid,
|
|
1196
|
+
prompt: await buildCompleteMilestonePrompt(mid, midTitle, basePath),
|
|
1197
|
+
};
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1197
1200
|
return {
|
|
1198
1201
|
action: "stop",
|
|
1199
1202
|
reason: "All milestones complete.",
|
|
@@ -55,6 +55,7 @@ import { detectAbandonMilestone } from "./abandon-detect.js";
|
|
|
55
55
|
import { isDeterministicPolicyError } from "./auto-tool-tracking.js";
|
|
56
56
|
import { clearProjectResearchInflightMarker, finalizeProjectResearchTimeout, } from "./project-research-policy.js";
|
|
57
57
|
import { validateArtifact } from "./schemas/validate.js";
|
|
58
|
+
import { verificationRetryKey } from "./auto/verification-retry-policy.js";
|
|
58
59
|
// ─── Path Comparison Helper ───────────────────────────────────────────────
|
|
59
60
|
/** Compare two paths for physical identity, tolerating trailing slashes and symlinks. */
|
|
60
61
|
function isSamePathLocal(a, b) {
|
|
@@ -865,6 +866,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
865
866
|
const outcome = finalizeProjectResearchTimeout(s.basePath, "Project research unit ended before all required dimensions produced durable files.");
|
|
866
867
|
s.pendingVerificationRetry = null;
|
|
867
868
|
s.verificationRetryCount.delete(retryKey);
|
|
869
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
868
870
|
triggerArtifactVerified = verifyExpectedArtifact(s.currentUnit.type, s.currentUnit.id, s.basePath);
|
|
869
871
|
if (triggerArtifactVerified) {
|
|
870
872
|
invalidateAllCaches();
|
|
@@ -915,6 +917,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
915
917
|
s.lastToolInvocationError = null;
|
|
916
918
|
s.pendingVerificationRetry = null;
|
|
917
919
|
s.verificationRetryCount.delete(retryKey);
|
|
920
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
918
921
|
writeBlockerPlaceholder(s.currentUnit.type, s.currentUnit.id, s.basePath, reason);
|
|
919
922
|
ctx.ui.notify(`${s.currentUnit.type} ${s.currentUnit.id} — deterministic policy rejection, wrote blocker placeholder (no retries) (#4973)`, "warning");
|
|
920
923
|
// Fall through to "continue" — do NOT enter the retry or db-unavailable paths.
|
|
@@ -943,6 +946,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
943
946
|
const failureDetails = describeArtifactVerificationFailure(s.currentUnit.type, s.currentUnit.id, s.basePath);
|
|
944
947
|
if (attempt > MAX_ARTIFACT_VERIFICATION_RETRIES) {
|
|
945
948
|
s.verificationRetryCount.delete(retryKey);
|
|
949
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
946
950
|
debugLog("postUnit", { phase: "artifact-verify-exhausted", unitType: s.currentUnit.type, unitId: s.currentUnit.id, attempt });
|
|
947
951
|
ctx.ui.notify(`${failureDetails} Pausing auto-mode after ${MAX_ARTIFACT_VERIFICATION_RETRIES} retries.`, "error");
|
|
948
952
|
await pauseAuto(ctx, pi);
|
|
@@ -962,7 +966,9 @@ export async function postUnitPreVerification(pctx, opts) {
|
|
|
962
966
|
// Verification succeeded — clear the retry counter so a future failure
|
|
963
967
|
// of the same unit gets a full retry budget instead of the stale count.
|
|
964
968
|
if (triggerArtifactVerified) {
|
|
965
|
-
|
|
969
|
+
const retryKey = verificationRetryKey(s.currentUnit.type, s.currentUnit.id);
|
|
970
|
+
s.verificationRetryCount.delete(retryKey);
|
|
971
|
+
s.verificationRetryFailureHashes.delete(retryKey);
|
|
966
972
|
}
|
|
967
973
|
}
|
|
968
974
|
else {
|