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
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Central retry policy for auto-mode verification redispatches.
|
|
3
|
+
|
|
4
|
+
import { createHash } from "node:crypto";
|
|
5
|
+
|
|
6
|
+
import type { PendingVerificationRetry } from "./session.js";
|
|
7
|
+
|
|
8
|
+
export const VERIFICATION_RETRY_BASE_DELAY_MS = 2_000;
|
|
9
|
+
export const VERIFICATION_RETRY_MAX_DELAY_MS = 30_000;
|
|
10
|
+
export const VERIFICATION_RETRY_JITTER_RATIO = 0.1;
|
|
11
|
+
|
|
12
|
+
export type VerificationRetryDecision =
|
|
13
|
+
| {
|
|
14
|
+
action: "delay";
|
|
15
|
+
key: string;
|
|
16
|
+
failureHash: string;
|
|
17
|
+
delayMs: number;
|
|
18
|
+
baseDelayMs: number;
|
|
19
|
+
}
|
|
20
|
+
| {
|
|
21
|
+
action: "pause";
|
|
22
|
+
reason: "missing-retry-context" | "duplicate-failure-context";
|
|
23
|
+
key?: string;
|
|
24
|
+
failureHash?: string;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export function verificationRetryKey(unitType: string, unitId: string): string {
|
|
28
|
+
return `${unitType}:${unitId}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function hashVerificationFailureContext(failureContext: string): string {
|
|
32
|
+
const normalized = failureContext.replace(/\r\n/g, "\n").trim();
|
|
33
|
+
return createHash("sha256").update(normalized).digest("hex");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function verificationRetryDelayMs(
|
|
37
|
+
attempt: number,
|
|
38
|
+
random: () => number = Math.random,
|
|
39
|
+
): { delayMs: number; baseDelayMs: number } {
|
|
40
|
+
const safeAttempt = Math.max(1, Math.floor(attempt));
|
|
41
|
+
const baseDelayMs = Math.min(
|
|
42
|
+
VERIFICATION_RETRY_MAX_DELAY_MS,
|
|
43
|
+
VERIFICATION_RETRY_BASE_DELAY_MS * 2 ** (safeAttempt - 1),
|
|
44
|
+
);
|
|
45
|
+
const jitterSpanMs = Math.round(baseDelayMs * VERIFICATION_RETRY_JITTER_RATIO);
|
|
46
|
+
const jitterMs = Math.round((random() - 0.5) * 2 * jitterSpanMs);
|
|
47
|
+
const delayMs = Math.min(
|
|
48
|
+
VERIFICATION_RETRY_MAX_DELAY_MS,
|
|
49
|
+
Math.max(0, baseDelayMs + jitterMs),
|
|
50
|
+
);
|
|
51
|
+
return { delayMs, baseDelayMs };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function decideVerificationRetry(input: {
|
|
55
|
+
unitType: string | undefined;
|
|
56
|
+
retryInfo: PendingVerificationRetry | null | undefined;
|
|
57
|
+
previousFailureHash: string | undefined;
|
|
58
|
+
random?: () => number;
|
|
59
|
+
}): VerificationRetryDecision {
|
|
60
|
+
const { retryInfo, unitType } = input;
|
|
61
|
+
if (!retryInfo || !unitType) {
|
|
62
|
+
return { action: "pause", reason: "missing-retry-context" };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const key = verificationRetryKey(unitType, retryInfo.unitId);
|
|
66
|
+
const failureHash = hashVerificationFailureContext(retryInfo.failureContext);
|
|
67
|
+
if (input.previousFailureHash === failureHash) {
|
|
68
|
+
return {
|
|
69
|
+
action: "pause",
|
|
70
|
+
reason: "duplicate-failure-context",
|
|
71
|
+
key,
|
|
72
|
+
failureHash,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
action: "delay",
|
|
78
|
+
key,
|
|
79
|
+
failureHash,
|
|
80
|
+
...verificationRetryDelayMs(retryInfo.attempt, input.random),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -11,14 +11,12 @@
|
|
|
11
11
|
import type {
|
|
12
12
|
ExtensionContext,
|
|
13
13
|
ExtensionCommandContext,
|
|
14
|
-
SessionMessageEntry,
|
|
15
14
|
ReadonlyFooterDataProvider,
|
|
16
15
|
Theme,
|
|
17
16
|
} from "@gsd/pi-coding-agent";
|
|
18
17
|
import type { GSDState } from "./types.js";
|
|
19
|
-
import { getCurrentBranch } from "./worktree.js";
|
|
20
18
|
import { getActiveHook } from "./post-unit-hooks.js";
|
|
21
|
-
import { getLedger
|
|
19
|
+
import { getLedger } from "./metrics.js";
|
|
22
20
|
import { getErrorMessage } from "./error-utils.js";
|
|
23
21
|
import { nativeIsRepo } from "./native-git-bridge.js";
|
|
24
22
|
import {
|
|
@@ -31,23 +29,19 @@ import { execFileSync } from "node:child_process";
|
|
|
31
29
|
import { truncateToWidth, visibleWidth } from "@gsd/pi-tui";
|
|
32
30
|
import { makeUI } from "../shared/tui.js";
|
|
33
31
|
import { GLYPH, INDENT } from "../shared/mod.js";
|
|
32
|
+
import { padRightVisible, renderFrame, renderProgressBar, rightAlign, wrapVisibleText } from "./tui/render-kit.js";
|
|
34
33
|
import { computeProgressScore } from "./progress-score.js";
|
|
35
|
-
import { getActiveWorktreeName } from "./worktree-command.js";
|
|
36
34
|
import {
|
|
37
35
|
getGlobalGSDPreferencesPath,
|
|
38
36
|
getProjectGSDPreferencesPath,
|
|
39
37
|
parsePreferencesMarkdown,
|
|
40
38
|
} from "./preferences.js";
|
|
41
|
-
import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.js";
|
|
42
39
|
import { parseUnitId } from "./unit-id.js";
|
|
43
40
|
import {
|
|
44
|
-
formatRtkSavingsLabel,
|
|
45
|
-
getRtkSessionSavings,
|
|
46
41
|
type RtkSessionSavings,
|
|
47
42
|
} from "../shared/rtk-session-stats.js";
|
|
48
43
|
import { logWarning } from "./workflow-logger.js";
|
|
49
44
|
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
50
|
-
import { homedir } from "node:os";
|
|
51
45
|
import { readUnitRuntimeRecord, type AutoUnitRuntimeRecord } from "./unit-runtime.js";
|
|
52
46
|
|
|
53
47
|
// ─── UAT Slice Extraction ─────────────────────────────────────────────────────
|
|
@@ -90,6 +84,42 @@ export interface AutoDashboardData {
|
|
|
90
84
|
remoteSession?: { pid: number; startedAt: string; unitType: string; unitId: string };
|
|
91
85
|
}
|
|
92
86
|
|
|
87
|
+
export interface CompletionDashboardSnapshot {
|
|
88
|
+
milestoneId?: string | null;
|
|
89
|
+
milestoneTitle?: string | null;
|
|
90
|
+
oneLiner?: string | null;
|
|
91
|
+
successCriteriaResults?: string | null;
|
|
92
|
+
definitionOfDoneResults?: string | null;
|
|
93
|
+
requirementOutcomes?: string | null;
|
|
94
|
+
deviations?: string | null;
|
|
95
|
+
followUps?: string | null;
|
|
96
|
+
keyDecisions?: string[];
|
|
97
|
+
keyFiles?: string[];
|
|
98
|
+
lessonsLearned?: string[];
|
|
99
|
+
reason: string;
|
|
100
|
+
startedAt: number;
|
|
101
|
+
totalCost: number;
|
|
102
|
+
totalTokens: number;
|
|
103
|
+
unitCount: number;
|
|
104
|
+
cacheHitRate?: number | null;
|
|
105
|
+
contextPercent?: number | null;
|
|
106
|
+
contextWindow?: number | null;
|
|
107
|
+
completedSlices?: number | null;
|
|
108
|
+
totalSlices?: number | null;
|
|
109
|
+
allMilestonesComplete?: boolean;
|
|
110
|
+
basePath?: string | null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface AutoOutcomeSurfaceSnapshot {
|
|
114
|
+
status: "paused" | "stopped" | "blocked" | "failed" | "complete" | "waiting" | "step";
|
|
115
|
+
title: string;
|
|
116
|
+
detail?: string | null;
|
|
117
|
+
unitLabel?: string | null;
|
|
118
|
+
nextAction: string;
|
|
119
|
+
commands?: string[];
|
|
120
|
+
startedAt?: number;
|
|
121
|
+
}
|
|
122
|
+
|
|
93
123
|
// ─── Unit Description Helpers ─────────────────────────────────────────────────
|
|
94
124
|
|
|
95
125
|
export function unitVerb(unitType: string): string {
|
|
@@ -601,6 +631,7 @@ export function updateProgressWidget(
|
|
|
601
631
|
tierBadge?: string,
|
|
602
632
|
): void {
|
|
603
633
|
if (!ctx.hasUI) return;
|
|
634
|
+
ctx.ui.setWidget("gsd-outcome", undefined);
|
|
604
635
|
|
|
605
636
|
// Welcome header is a startup-only banner — permanently suppress it once
|
|
606
637
|
// auto-mode activates. The dashboard widget owns all status from here.
|
|
@@ -635,54 +666,12 @@ export function updateProgressWidget(
|
|
|
635
666
|
updateSliceProgressCache(accessors.getBasePath(), mid.id, slice?.id);
|
|
636
667
|
}
|
|
637
668
|
|
|
638
|
-
// Cache git branch at widget creation time (not per render)
|
|
639
|
-
let cachedBranch: string | null = null;
|
|
640
|
-
try { cachedBranch = getCurrentBranch(accessors.getBasePath()); } catch (err) { /* not in git repo */
|
|
641
|
-
logWarning("dashboard", `git branch detection failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
// Cache short pwd (last 2 path segments only) + worktree/branch info
|
|
645
|
-
let widgetPwd: string;
|
|
646
|
-
{
|
|
647
|
-
let fullPwd = process.cwd();
|
|
648
|
-
const widgetHome = homedir();
|
|
649
|
-
if (widgetHome && (fullPwd === widgetHome || fullPwd.startsWith(widgetHome + "/") || fullPwd.startsWith(widgetHome + "\\"))) {
|
|
650
|
-
fullPwd = `~${fullPwd.slice(widgetHome.length)}`;
|
|
651
|
-
}
|
|
652
|
-
const parts = fullPwd.split("/");
|
|
653
|
-
widgetPwd = parts.length > 2 ? parts.slice(-2).join("/") : fullPwd;
|
|
654
|
-
}
|
|
655
|
-
const worktreeName = getActiveWorktreeName();
|
|
656
|
-
if (worktreeName && cachedBranch) {
|
|
657
|
-
widgetPwd = `${widgetPwd} (\u2387 ${cachedBranch})`;
|
|
658
|
-
} else if (cachedBranch) {
|
|
659
|
-
widgetPwd = `${widgetPwd} (${cachedBranch})`;
|
|
660
|
-
}
|
|
661
|
-
|
|
662
|
-
// Pre-fetch last commit for display
|
|
663
|
-
refreshLastCommit(accessors.getBasePath());
|
|
664
|
-
|
|
665
|
-
// Cache the effective service tier at widget creation time (reads preferences)
|
|
666
|
-
const effectiveServiceTier = getEffectiveServiceTier();
|
|
667
|
-
|
|
668
669
|
ctx.ui.setWidget("gsd-progress", (tui, theme) => {
|
|
669
670
|
let pulseBright = true;
|
|
670
671
|
let cachedLines: string[] | undefined;
|
|
671
672
|
let cachedWidth: number | undefined;
|
|
672
|
-
let cachedRtkLabel: string | null | undefined;
|
|
673
673
|
let cachedRuntimeRecord: AutoUnitRuntimeRecord | null = null;
|
|
674
674
|
|
|
675
|
-
const refreshRtkLabel = (): void => {
|
|
676
|
-
try {
|
|
677
|
-
const sessionId = ctx.sessionManager.getSessionId();
|
|
678
|
-
const savings = sessionId ? getRtkSessionSavings(accessors.getBasePath(), sessionId) : null;
|
|
679
|
-
cachedRtkLabel = formatRtkSavingsLabel(savings);
|
|
680
|
-
} catch (err) {
|
|
681
|
-
logWarning("dashboard", `RTK savings lookup failed: ${err instanceof Error ? (err as Error).message : String(err)}`);
|
|
682
|
-
cachedRtkLabel = null;
|
|
683
|
-
}
|
|
684
|
-
};
|
|
685
|
-
|
|
686
675
|
const refreshRuntimeRecord = (): void => {
|
|
687
676
|
try {
|
|
688
677
|
cachedRuntimeRecord = readUnitRuntimeRecord(accessors.getBasePath(), unitType, unitId);
|
|
@@ -691,7 +680,6 @@ export function updateProgressWidget(
|
|
|
691
680
|
}
|
|
692
681
|
};
|
|
693
682
|
|
|
694
|
-
refreshRtkLabel();
|
|
695
683
|
refreshRuntimeRecord();
|
|
696
684
|
|
|
697
685
|
const pulseTimer = setInterval(() => {
|
|
@@ -709,7 +697,6 @@ export function updateProgressWidget(
|
|
|
709
697
|
if (mid) {
|
|
710
698
|
updateSliceProgressCache(accessors.getBasePath(), mid.id, slice?.id);
|
|
711
699
|
}
|
|
712
|
-
refreshRtkLabel();
|
|
713
700
|
refreshRuntimeRecord();
|
|
714
701
|
cachedLines = undefined;
|
|
715
702
|
} catch (err) { /* non-fatal */
|
|
@@ -783,46 +770,6 @@ export function updateProgressWidget(
|
|
|
783
770
|
}
|
|
784
771
|
}
|
|
785
772
|
|
|
786
|
-
// ── Gather stats (needed by multiple modes) ─────────────────────
|
|
787
|
-
const cmdCtx = accessors.getCmdCtx();
|
|
788
|
-
let totalInput = 0;
|
|
789
|
-
let totalCacheRead = 0;
|
|
790
|
-
if (cmdCtx) {
|
|
791
|
-
for (const entry of cmdCtx.sessionManager.getEntries()) {
|
|
792
|
-
if (entry.type === "message") {
|
|
793
|
-
const msgEntry = entry as SessionMessageEntry;
|
|
794
|
-
if (msgEntry.message?.role === "assistant") {
|
|
795
|
-
const u = (msgEntry.message as any).usage;
|
|
796
|
-
if (u) {
|
|
797
|
-
totalInput += u.input || 0;
|
|
798
|
-
totalCacheRead += u.cacheRead || 0;
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
const mLedger = getLedger();
|
|
805
|
-
const autoTotals = mLedger ? getProjectTotals(mLedger.units) : null;
|
|
806
|
-
const cumulativeCost = autoTotals?.cost ?? 0;
|
|
807
|
-
const cxUsage = cmdCtx?.getContextUsage?.();
|
|
808
|
-
const cxWindow = cxUsage?.contextWindow ?? cmdCtx?.model?.contextWindow ?? 0;
|
|
809
|
-
const cxPctVal = cxUsage?.percent ?? 0;
|
|
810
|
-
const cxPct = cxUsage?.percent !== null ? cxPctVal.toFixed(1) : "?";
|
|
811
|
-
|
|
812
|
-
// Model display — prefer dispatched model ID (set after selectAndApplyModel
|
|
813
|
-
// + hook overrides) over cmdCtx?.model which can be stale (#2899).
|
|
814
|
-
const dispatchedModelId = accessors.getCurrentDispatchedModelId();
|
|
815
|
-
const modelId = dispatchedModelId
|
|
816
|
-
? dispatchedModelId.split("/").slice(1).join("/") || dispatchedModelId
|
|
817
|
-
: (cmdCtx?.model?.id ?? "");
|
|
818
|
-
const modelProvider = dispatchedModelId
|
|
819
|
-
? dispatchedModelId.split("/")[0] || ""
|
|
820
|
-
: (cmdCtx?.model?.provider ?? "");
|
|
821
|
-
const tierIcon = resolveServiceTierIcon(effectiveServiceTier, modelId);
|
|
822
|
-
const modelDisplay = (modelProvider && modelId
|
|
823
|
-
? `${modelProvider}/${modelId}`
|
|
824
|
-
: modelId) + (tierIcon ? ` ${tierIcon}` : "");
|
|
825
|
-
|
|
826
773
|
// ── Mode: off — return empty ──────────────────────────────────
|
|
827
774
|
if (widgetMode === "off") {
|
|
828
775
|
cachedLines = [];
|
|
@@ -838,7 +785,7 @@ export function updateProgressWidget(
|
|
|
838
785
|
return lines;
|
|
839
786
|
}
|
|
840
787
|
|
|
841
|
-
// ── Mode: small — header +
|
|
788
|
+
// ── Mode: small — header + active work progress ───────────────
|
|
842
789
|
if (widgetMode === "small") {
|
|
843
790
|
lines.push("");
|
|
844
791
|
|
|
@@ -852,10 +799,7 @@ export function updateProgressWidget(
|
|
|
852
799
|
if (shouldRenderRoadmapProgress(roadmapSlices)) {
|
|
853
800
|
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
854
801
|
const barWidth = Math.max(6, Math.min(18, Math.floor(width * 0.25)));
|
|
855
|
-
const
|
|
856
|
-
const filled = Math.round(pct * barWidth);
|
|
857
|
-
const bar = theme.fg("success", "━".repeat(filled))
|
|
858
|
-
+ theme.fg("dim", "─".repeat(barWidth - filled));
|
|
802
|
+
const bar = renderProgressBar(theme, done, total, barWidth);
|
|
859
803
|
let meta = `${theme.fg("text", `${done}`)}${theme.fg("dim", `/${total} slices`)}`;
|
|
860
804
|
if (activeSliceTasks && activeSliceTasks.total > 0) {
|
|
861
805
|
const tn = Math.min(activeSliceTasks.done + 1, activeSliceTasks.total);
|
|
@@ -864,17 +808,6 @@ export function updateProgressWidget(
|
|
|
864
808
|
lines.push(`${pad}${bar} ${meta}`);
|
|
865
809
|
}
|
|
866
810
|
|
|
867
|
-
// Compact stats: cost + context only
|
|
868
|
-
const smallStats: string[] = [];
|
|
869
|
-
if (cumulativeCost) smallStats.push(theme.fg("warning", `$${cumulativeCost.toFixed(2)}`));
|
|
870
|
-
const cxDisplay = `${cxPct}%ctx`;
|
|
871
|
-
if (cxPctVal > 90) smallStats.push(theme.fg("error", cxDisplay));
|
|
872
|
-
else if (cxPctVal > 70) smallStats.push(theme.fg("warning", cxDisplay));
|
|
873
|
-
else smallStats.push(theme.fg("dim", cxDisplay));
|
|
874
|
-
if (smallStats.length > 0) {
|
|
875
|
-
lines.push(rightAlign("", smallStats.join(theme.fg("dim", " ")), width));
|
|
876
|
-
}
|
|
877
|
-
|
|
878
811
|
lines.push(...ui.bar());
|
|
879
812
|
cachedLines = lines;
|
|
880
813
|
cachedWidth = width;
|
|
@@ -884,11 +817,10 @@ export function updateProgressWidget(
|
|
|
884
817
|
// ── Mode: full — complete two-column layout ───────────────────
|
|
885
818
|
lines.push("");
|
|
886
819
|
|
|
887
|
-
// Context section: milestone + slice
|
|
820
|
+
// Context section: milestone + slice. Footer owns model/cost/context.
|
|
888
821
|
const hasContext = !!(mid || (slice && unitType !== "research-milestone" && unitType !== "plan-milestone"));
|
|
889
822
|
if (mid) {
|
|
890
|
-
|
|
891
|
-
lines.push(truncateToWidth(`${pad}${theme.fg("dim", mid.title)}${modelTag}`, width, "…"));
|
|
823
|
+
lines.push(truncateToWidth(`${pad}${theme.fg("dim", mid.title)}`, width, "…"));
|
|
892
824
|
}
|
|
893
825
|
if (slice && unitType !== "research-milestone" && unitType !== "plan-milestone") {
|
|
894
826
|
lines.push(truncateToWidth(
|
|
@@ -920,10 +852,7 @@ export function updateProgressWidget(
|
|
|
920
852
|
if (shouldRenderRoadmapProgress(roadmapSlices)) {
|
|
921
853
|
const { done, total, activeSliceTasks } = roadmapSlices;
|
|
922
854
|
const barWidth = Math.max(6, Math.min(18, Math.floor(leftColWidth * 0.4)));
|
|
923
|
-
const
|
|
924
|
-
const filled = Math.round(pct * barWidth);
|
|
925
|
-
const bar = theme.fg("success", "━".repeat(filled))
|
|
926
|
-
+ theme.fg("dim", "─".repeat(barWidth - filled));
|
|
855
|
+
const bar = renderProgressBar(theme, done, total, barWidth);
|
|
927
856
|
|
|
928
857
|
let meta = `${theme.fg("text", `${done}`)}${theme.fg("dim", `/${total} slices`)}`;
|
|
929
858
|
if (activeSliceTasks && activeSliceTasks.total > 0) {
|
|
@@ -984,7 +913,7 @@ export function updateProgressWidget(
|
|
|
984
913
|
if (maxRows > 0) {
|
|
985
914
|
lines.push("");
|
|
986
915
|
for (let i = 0; i < maxRows; i++) {
|
|
987
|
-
const left =
|
|
916
|
+
const left = padRightVisible(truncateToWidth(leftLines[i] ?? "", leftColWidth, "…"), leftColWidth);
|
|
988
917
|
const right = rightLines[i] ?? "";
|
|
989
918
|
lines.push(`${left}${right}`);
|
|
990
919
|
}
|
|
@@ -996,53 +925,8 @@ export function updateProgressWidget(
|
|
|
996
925
|
}
|
|
997
926
|
}
|
|
998
927
|
|
|
999
|
-
// ──
|
|
928
|
+
// ── Auto controls. Footer owns cwd/branch/model/cost/context. ───
|
|
1000
929
|
lines.push("");
|
|
1001
|
-
{
|
|
1002
|
-
const sp: string[] = [];
|
|
1003
|
-
if (totalCacheRead + totalInput > 0) {
|
|
1004
|
-
const hitRate = Math.round((totalCacheRead / (totalCacheRead + totalInput)) * 100);
|
|
1005
|
-
const hitColor = hitRate >= 70 ? "success" : hitRate >= 40 ? "warning" : "error";
|
|
1006
|
-
sp.push(theme.fg(hitColor, `${hitRate}%hit`));
|
|
1007
|
-
}
|
|
1008
|
-
if (cumulativeCost) sp.push(theme.fg("warning", `$${cumulativeCost.toFixed(2)}`));
|
|
1009
|
-
|
|
1010
|
-
const CX_BAR_WIDTH = 8;
|
|
1011
|
-
const cxBarFilled = Math.min(
|
|
1012
|
-
CX_BAR_WIDTH,
|
|
1013
|
-
Math.max(0, Math.round((cxPctVal / 100) * CX_BAR_WIDTH)),
|
|
1014
|
-
);
|
|
1015
|
-
const cxBarColor: "error" | "warning" | "success" =
|
|
1016
|
-
cxPctVal > 90 ? "error" : cxPctVal > 70 ? "warning" : "success";
|
|
1017
|
-
const cxBar =
|
|
1018
|
-
theme.fg(cxBarColor, "━".repeat(cxBarFilled)) +
|
|
1019
|
-
theme.fg("dim", "─".repeat(CX_BAR_WIDTH - cxBarFilled));
|
|
1020
|
-
const cxPctText = `${cxPct}%/${formatWidgetTokens(cxWindow)}`;
|
|
1021
|
-
const cxColorized =
|
|
1022
|
-
cxPctVal > 90
|
|
1023
|
-
? theme.fg("error", cxPctText)
|
|
1024
|
-
: cxPctVal > 70
|
|
1025
|
-
? theme.fg("warning", cxPctText)
|
|
1026
|
-
: cxPctText;
|
|
1027
|
-
sp.push(`${cxBar} ${cxColorized}`);
|
|
1028
|
-
|
|
1029
|
-
const statsLine = sp.map(p => p.includes("\x1b[") ? p : theme.fg("dim", p))
|
|
1030
|
-
.join(theme.fg("dim", " "));
|
|
1031
|
-
if (statsLine) {
|
|
1032
|
-
lines.push(rightAlign("", statsLine, width));
|
|
1033
|
-
}
|
|
1034
|
-
if (cachedRtkLabel) {
|
|
1035
|
-
lines.push(rightAlign("", theme.fg("dim", cachedRtkLabel), width));
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1038
|
-
// Last commit info
|
|
1039
|
-
const lastCommit = getLastCommit(accessors.getBasePath());
|
|
1040
|
-
const maxCommitLen = 65;
|
|
1041
|
-
const commitMsg = lastCommit
|
|
1042
|
-
? lastCommit.message.length > maxCommitLen
|
|
1043
|
-
? lastCommit.message.slice(0, maxCommitLen - 1) + "…"
|
|
1044
|
-
: lastCommit.message
|
|
1045
|
-
: "";
|
|
1046
930
|
// Step-mode guidance — shown above keyboard hints when auto is paused
|
|
1047
931
|
if (accessors.isStepMode()) {
|
|
1048
932
|
lines.push(`${pad}${theme.fg("accent", "→")} ${theme.fg("dim", "Ctrl+N to advance to next step · /gsd status for overview")}`);
|
|
@@ -1054,15 +938,7 @@ export function updateProgressWidget(
|
|
|
1054
938
|
hintParts.push(`${formattedShortcutPair("dashboard")} dashboard`);
|
|
1055
939
|
hintParts.push(`${formattedShortcutPair("parallel")} parallel`);
|
|
1056
940
|
const hintStr = theme.fg("dim", hintParts.join(" | "));
|
|
1057
|
-
|
|
1058
|
-
? theme.fg("dim", `${lastCommit.timeAgo} ago: ${commitMsg}`)
|
|
1059
|
-
: "";
|
|
1060
|
-
const locationStr = theme.fg("dim", widgetPwd);
|
|
1061
|
-
if (commitStr) {
|
|
1062
|
-
lines.push(rightAlign(`${pad}${locationStr} · ${commitStr}`, hintStr, width));
|
|
1063
|
-
} else {
|
|
1064
|
-
lines.push(rightAlign(`${pad}${locationStr}`, hintStr, width));
|
|
1065
|
-
}
|
|
941
|
+
lines.push(rightAlign("", hintStr, width));
|
|
1066
942
|
|
|
1067
943
|
lines.push(...ui.bar());
|
|
1068
944
|
|
|
@@ -1082,19 +958,190 @@ export function updateProgressWidget(
|
|
|
1082
958
|
});
|
|
1083
959
|
}
|
|
1084
960
|
|
|
1085
|
-
|
|
961
|
+
export function setCompletionProgressWidget(
|
|
962
|
+
ctx: ExtensionContext,
|
|
963
|
+
snapshot: CompletionDashboardSnapshot,
|
|
964
|
+
): void {
|
|
965
|
+
if (!ctx.hasUI) return;
|
|
966
|
+
ctx.ui.setWidget("gsd-outcome", undefined);
|
|
967
|
+
|
|
968
|
+
if (typeof ctx.ui?.setHeader === "function") {
|
|
969
|
+
ctx.ui.setHeader(() => ({
|
|
970
|
+
render(): string[] { return []; },
|
|
971
|
+
invalidate(): void {},
|
|
972
|
+
}));
|
|
973
|
+
}
|
|
974
|
+
if (typeof ctx.ui?.setStatus === "function") {
|
|
975
|
+
ctx.ui.setStatus("gsd-step", undefined);
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
ctx.ui.setWidget("gsd-progress", (_tui, theme) => ({
|
|
979
|
+
render(width: number): string[] {
|
|
980
|
+
const ui = makeUI(theme, width);
|
|
981
|
+
const pad = INDENT.base;
|
|
982
|
+
const lines: string[] = [];
|
|
983
|
+
const contentWidth = Math.max(20, width - visibleWidth(pad));
|
|
984
|
+
const add = (line = ""): void => {
|
|
985
|
+
lines.push(line ? truncateToWidth(`${pad}${line}`, width, "…") : "");
|
|
986
|
+
};
|
|
987
|
+
const addSection = (label: string, value: string | null | undefined, indent = ""): void => {
|
|
988
|
+
const clean = normalizeRollupText(value);
|
|
989
|
+
if (!clean) return;
|
|
990
|
+
add(`${indent}${theme.fg("accent", label)} ${theme.fg("text", truncateToWidth(clean, contentWidth - indent.length - label.length - 1, "…"))}`);
|
|
991
|
+
};
|
|
992
|
+
const addList = (label: string, values: string[] | undefined, limit: number, indent = ""): void => {
|
|
993
|
+
const clean = (values ?? []).map(normalizeRollupText).filter((v): v is string => !!v);
|
|
994
|
+
if (clean.length === 0) return;
|
|
995
|
+
const shown = clean.slice(0, limit);
|
|
996
|
+
const more = clean.length > shown.length ? ` (+${clean.length - shown.length} more)` : "";
|
|
997
|
+
add(`${indent}${theme.fg("accent", label)} ${theme.fg("text", truncateToWidth(shown.join("; ") + more, contentWidth - indent.length - label.length - 1, "…"))}`);
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
lines.push(...ui.bar());
|
|
1001
|
+
|
|
1002
|
+
const elapsed = formatAutoElapsed(snapshot.startedAt);
|
|
1003
|
+
const heading = snapshot.allMilestonesComplete
|
|
1004
|
+
? "All milestones complete"
|
|
1005
|
+
: snapshot.milestoneId
|
|
1006
|
+
? `Milestone ${snapshot.milestoneId} roll-up`
|
|
1007
|
+
: "Milestone roll-up";
|
|
1008
|
+
lines.push(rightAlign(`${pad}${theme.fg("accent", theme.bold(heading))}`, elapsed ? theme.fg("dim", elapsed) : "", width));
|
|
1009
|
+
|
|
1010
|
+
if (snapshot.milestoneTitle) {
|
|
1011
|
+
add(theme.fg("text", snapshot.milestoneTitle));
|
|
1012
|
+
}
|
|
1013
|
+
|
|
1014
|
+
lines.push("");
|
|
1015
|
+
add(theme.fg("accent", "Outcome"));
|
|
1016
|
+
addSection("", snapshot.oneLiner, " ");
|
|
1017
|
+
|
|
1018
|
+
const changed = [
|
|
1019
|
+
...(snapshot.successCriteriaResults ? [snapshot.successCriteriaResults] : []),
|
|
1020
|
+
...(snapshot.requirementOutcomes ? [snapshot.requirementOutcomes] : []),
|
|
1021
|
+
...(snapshot.keyDecisions ?? []),
|
|
1022
|
+
].map(normalizeRollupText).filter((v): v is string => !!v).slice(0, 4);
|
|
1023
|
+
if (changed.length > 0) {
|
|
1024
|
+
lines.push("");
|
|
1025
|
+
add(theme.fg("accent", "What changed"));
|
|
1026
|
+
for (const item of changed) add(` - ${theme.fg("text", item)}`);
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
const verification = [
|
|
1030
|
+
snapshot.definitionOfDoneResults,
|
|
1031
|
+
snapshot.deviations ? `Deviations: ${snapshot.deviations}` : null,
|
|
1032
|
+
snapshot.followUps ? `Follow-ups: ${snapshot.followUps}` : null,
|
|
1033
|
+
].map(normalizeRollupText).filter((v): v is string => !!v);
|
|
1034
|
+
if (verification.length > 0 || (snapshot.keyFiles?.length ?? 0) > 0) {
|
|
1035
|
+
lines.push("");
|
|
1036
|
+
add(theme.fg("accent", "Verification"));
|
|
1037
|
+
for (const item of verification.slice(0, 3)) add(` - ${theme.fg("text", item)}`);
|
|
1038
|
+
addList("Files:", snapshot.keyFiles, 4, " ");
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
if ((snapshot.lessonsLearned?.length ?? 0) > 0) {
|
|
1042
|
+
lines.push("");
|
|
1043
|
+
addList("Lessons:", snapshot.lessonsLearned, 2);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
const hasSliceTotals = typeof snapshot.completedSlices === "number" && typeof snapshot.totalSlices === "number" && snapshot.totalSlices > 0;
|
|
1047
|
+
|
|
1048
|
+
lines.push("");
|
|
1049
|
+
const stats: string[] = [];
|
|
1050
|
+
if (hasSliceTotals) stats.push(theme.fg("success", `${snapshot.completedSlices}/${snapshot.totalSlices} slices`));
|
|
1051
|
+
if (snapshot.unitCount > 0) stats.push(theme.fg("dim", `${snapshot.unitCount} units`));
|
|
1052
|
+
if (snapshot.totalTokens > 0) stats.push(theme.fg("dim", `${formatWidgetTokens(snapshot.totalTokens)} tokens`));
|
|
1053
|
+
if (snapshot.totalCost > 0) stats.push(theme.fg("warning", `$${snapshot.totalCost.toFixed(2)}`));
|
|
1054
|
+
if (typeof snapshot.cacheHitRate === "number") {
|
|
1055
|
+
const hitColor = snapshot.cacheHitRate >= 70 ? "success" : snapshot.cacheHitRate >= 40 ? "warning" : "error";
|
|
1056
|
+
stats.push(theme.fg(hitColor, `${Math.round(snapshot.cacheHitRate)}% cache hit`));
|
|
1057
|
+
}
|
|
1058
|
+
if (stats.length > 0) {
|
|
1059
|
+
add(`${theme.fg("accent", "Run totals")} ${stats.join(theme.fg("dim", " · "))}`);
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
lines.push("");
|
|
1063
|
+
const nextAction = snapshot.allMilestonesComplete
|
|
1064
|
+
? "Review the roll-up, then start a new milestone when ready."
|
|
1065
|
+
: "Review the roll-up, inspect status, or continue to the next milestone.";
|
|
1066
|
+
const commands = snapshot.allMilestonesComplete
|
|
1067
|
+
? ["/gsd status for overview", "/gsd visualize to inspect", "/gsd notifications for history", "/gsd start for new work"]
|
|
1068
|
+
: ["/gsd status for overview", "/gsd visualize to inspect", "/gsd notifications for history", "/gsd auto for next milestone"];
|
|
1069
|
+
add(`${theme.fg("success", "Next")} ${theme.fg("text", nextAction)}`);
|
|
1070
|
+
add(theme.fg("dim", commands.join(" · ")));
|
|
1071
|
+
|
|
1072
|
+
const location = snapshot.basePath ? theme.fg("dim", snapshot.basePath) : "";
|
|
1073
|
+
const reason = theme.fg("dim", snapshot.reason);
|
|
1074
|
+
lines.push(rightAlign(`${pad}${truncateToWidth(location, Math.max(0, width - 32), "…")}`, reason, width));
|
|
1075
|
+
lines.push(...ui.bar());
|
|
1076
|
+
|
|
1077
|
+
return lines;
|
|
1078
|
+
},
|
|
1079
|
+
invalidate(): void {},
|
|
1080
|
+
dispose(): void {},
|
|
1081
|
+
}));
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
export function setAutoOutcomeWidget(
|
|
1085
|
+
ctx: ExtensionContext,
|
|
1086
|
+
snapshot: AutoOutcomeSurfaceSnapshot,
|
|
1087
|
+
): void {
|
|
1088
|
+
if (!ctx.hasUI) return;
|
|
1089
|
+
|
|
1090
|
+
ctx.ui.setWidget("gsd-outcome", (_tui, theme) => ({
|
|
1091
|
+
render(width: number): string[] {
|
|
1092
|
+
const color = snapshot.status === "failed" || snapshot.status === "blocked"
|
|
1093
|
+
? "warning"
|
|
1094
|
+
: snapshot.status === "complete"
|
|
1095
|
+
? "success"
|
|
1096
|
+
: "borderAccent";
|
|
1097
|
+
const icon = snapshot.status === "complete" ? "✓"
|
|
1098
|
+
: snapshot.status === "failed" ? "x"
|
|
1099
|
+
: snapshot.status === "blocked" ? "!"
|
|
1100
|
+
: snapshot.status === "paused" ? "||"
|
|
1101
|
+
: "●";
|
|
1102
|
+
const innerWidth = Math.max(8, width - 4);
|
|
1103
|
+
const maxLines = 7;
|
|
1104
|
+
const lines: string[] = [];
|
|
1105
|
+
const elapsed = snapshot.startedAt ? formatAutoElapsed(snapshot.startedAt) : "";
|
|
1106
|
+
const heading = `${theme.fg(color, icon)} ${theme.fg("accent", theme.bold("GSD"))} ${theme.fg("text", snapshot.title)}`;
|
|
1107
|
+
lines.push(rightAlign(heading, elapsed ? theme.fg("dim", elapsed) : "", innerWidth));
|
|
1108
|
+
const commands = snapshot.commands?.filter(Boolean) ?? [];
|
|
1109
|
+
const commandLine = commands.length > 0 ? theme.fg("dim", commands.join(" · ")) : null;
|
|
1110
|
+
|
|
1111
|
+
const addWrapped = (text: string, prefix = ""): void => {
|
|
1112
|
+
const reserve = commandLine ? 1 : 0;
|
|
1113
|
+
const remaining = Math.max(0, maxLines - reserve - lines.length);
|
|
1114
|
+
if (remaining === 0) return;
|
|
1115
|
+
const available = Math.max(8, innerWidth - visibleWidth(prefix));
|
|
1116
|
+
for (const [idx, line] of wrapVisibleText(text, available).slice(0, remaining).entries()) {
|
|
1117
|
+
lines.push(`${idx === 0 ? prefix : " ".repeat(visibleWidth(prefix))}${line}`);
|
|
1118
|
+
}
|
|
1119
|
+
};
|
|
1120
|
+
|
|
1121
|
+
if (snapshot.detail) {
|
|
1122
|
+
addWrapped(snapshot.detail, `${theme.fg("dim", "Reason")} `);
|
|
1123
|
+
}
|
|
1124
|
+
if (snapshot.unitLabel) {
|
|
1125
|
+
addWrapped(snapshot.unitLabel, `${theme.fg("dim", "Last")} `);
|
|
1126
|
+
}
|
|
1127
|
+
addWrapped(snapshot.nextAction, `${theme.fg("success", "Next")} `);
|
|
1128
|
+
|
|
1129
|
+
if (commandLine && lines.length < maxLines) {
|
|
1130
|
+
lines.push(commandLine);
|
|
1131
|
+
}
|
|
1086
1132
|
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
return truncateToWidth(left + " ".repeat(gap) + right, width, "…");
|
|
1133
|
+
return renderFrame(theme, lines, width, { borderColor: color, paddingX: 1 });
|
|
1134
|
+
},
|
|
1135
|
+
invalidate(): void {},
|
|
1136
|
+
dispose(): void {},
|
|
1137
|
+
}));
|
|
1093
1138
|
}
|
|
1094
1139
|
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1140
|
+
function normalizeRollupText(value: string | null | undefined): string | null {
|
|
1141
|
+
const clean = value
|
|
1142
|
+
?.replace(/\s+/g, " ")
|
|
1143
|
+
.replace(/^[-*]\s+/, "")
|
|
1144
|
+
.trim();
|
|
1145
|
+
if (!clean || clean === "(none)" || clean === "None." || clean === "Not provided.") return null;
|
|
1146
|
+
return clean;
|
|
1100
1147
|
}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Declarative auto-mode dispatch rules and dispatch resolver.
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* Auto-mode Dispatch Table — declarative phase → unit mapping.
|
|
3
6
|
*
|
|
@@ -1418,8 +1421,19 @@ export const DISPATCH_RULES: DispatchRule[] = [
|
|
|
1418
1421
|
},
|
|
1419
1422
|
{
|
|
1420
1423
|
name: "complete → stop",
|
|
1421
|
-
match: async ({ state }) => {
|
|
1424
|
+
match: async ({ state, mid, midTitle, basePath }) => {
|
|
1422
1425
|
if (state.phase !== "complete") return null;
|
|
1426
|
+
if (mid && isDbAvailable()) {
|
|
1427
|
+
const milestone = getMilestone(mid);
|
|
1428
|
+
if (milestone && !isClosedStatus(milestone.status)) {
|
|
1429
|
+
return {
|
|
1430
|
+
action: "dispatch",
|
|
1431
|
+
unitType: "complete-milestone",
|
|
1432
|
+
unitId: mid,
|
|
1433
|
+
prompt: await buildCompleteMilestonePrompt(mid, midTitle, basePath),
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1423
1437
|
return {
|
|
1424
1438
|
action: "stop",
|
|
1425
1439
|
reason: "All milestones complete.",
|