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,99 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: ADR-017 drift-driven State Reconciliation Module entry point.
|
|
3
|
+
// reconcileBeforeDispatch runs before every Dispatch decision and worker spawn.
|
|
4
|
+
import { deriveState as defaultDeriveState, invalidateStateCache as defaultInvalidate, } from "../state.js";
|
|
5
|
+
import { ReconciliationFailedError, } from "./errors.js";
|
|
6
|
+
import { DRIFT_REGISTRY } from "./registry.js";
|
|
7
|
+
export { ReconciliationFailedError } from "./errors.js";
|
|
8
|
+
export { DRIFT_REGISTRY } from "./registry.js";
|
|
9
|
+
const MAX_PASSES = 2;
|
|
10
|
+
const defaultDeps = {
|
|
11
|
+
invalidateStateCache: defaultInvalidate,
|
|
12
|
+
deriveState: defaultDeriveState,
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* Drift-driven pre-dispatch reconciliation per ADR-017.
|
|
16
|
+
*
|
|
17
|
+
* Lifecycle: derive → detect drift → apply repairs → re-derive. Capped at
|
|
18
|
+
* MAX_PASSES (=2) cycles. The loop runs only when the prior pass fully
|
|
19
|
+
* succeeded but re-derive surfaces NEW drift (cascading repairs — e.g.
|
|
20
|
+
* fixing milestone registration uncovers a downstream completion-timestamp
|
|
21
|
+
* drift).
|
|
22
|
+
*
|
|
23
|
+
* Returns ok=true with `repaired` and terminal `blockers` populated.
|
|
24
|
+
* Throws ReconciliationFailedError when:
|
|
25
|
+
* - any repair function throws within a pass, or
|
|
26
|
+
* - drift persists after the cap.
|
|
27
|
+
*/
|
|
28
|
+
export async function reconcileBeforeDispatch(basePath, deps = defaultDeps) {
|
|
29
|
+
const registry = deps.registry ?? DRIFT_REGISTRY;
|
|
30
|
+
const repaired = [];
|
|
31
|
+
for (let pass = 0; pass < MAX_PASSES; pass++) {
|
|
32
|
+
deps.invalidateStateCache();
|
|
33
|
+
const stateSnapshot = await deps.deriveState(basePath, deps.deriveStateOptions);
|
|
34
|
+
const ctx = { basePath, state: stateSnapshot };
|
|
35
|
+
const drift = await detectAllDrift(stateSnapshot, ctx, registry, pass);
|
|
36
|
+
if (drift.length === 0) {
|
|
37
|
+
return {
|
|
38
|
+
ok: true,
|
|
39
|
+
stateSnapshot,
|
|
40
|
+
repaired,
|
|
41
|
+
blockers: stateSnapshot.blockers ?? [],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
const failures = [];
|
|
45
|
+
for (const record of drift) {
|
|
46
|
+
const handler = registry.find((h) => h.kind === record.kind);
|
|
47
|
+
if (!handler) {
|
|
48
|
+
failures.push({
|
|
49
|
+
drift: record,
|
|
50
|
+
cause: new Error(`No drift handler registered for kind "${record.kind}"`),
|
|
51
|
+
});
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
await handler.repair(record, ctx);
|
|
56
|
+
repaired.push(record);
|
|
57
|
+
}
|
|
58
|
+
catch (cause) {
|
|
59
|
+
failures.push({ drift: record, cause });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (failures.length > 0) {
|
|
63
|
+
throw new ReconciliationFailedError({ failures, pass });
|
|
64
|
+
}
|
|
65
|
+
// Pass fully succeeded; loop runs again to detect cascading drift.
|
|
66
|
+
}
|
|
67
|
+
// After MAX_PASSES, one more derive+detect to verify nothing persists.
|
|
68
|
+
deps.invalidateStateCache();
|
|
69
|
+
const finalState = await deps.deriveState(basePath, deps.deriveStateOptions);
|
|
70
|
+
const finalCtx = { basePath, state: finalState };
|
|
71
|
+
const persistent = await detectAllDrift(finalState, finalCtx, registry);
|
|
72
|
+
if (persistent.length > 0) {
|
|
73
|
+
throw new ReconciliationFailedError({ persistentDrift: persistent });
|
|
74
|
+
}
|
|
75
|
+
return {
|
|
76
|
+
ok: true,
|
|
77
|
+
stateSnapshot: finalState,
|
|
78
|
+
repaired,
|
|
79
|
+
blockers: finalState.blockers ?? [],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
async function detectAllDrift(state, ctx,
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
84
|
+
registry, pass) {
|
|
85
|
+
const collected = [];
|
|
86
|
+
for (const handler of registry) {
|
|
87
|
+
try {
|
|
88
|
+
const detected = await handler.detect(state, ctx);
|
|
89
|
+
collected.push(...detected);
|
|
90
|
+
}
|
|
91
|
+
catch (cause) {
|
|
92
|
+
throw new ReconciliationFailedError({
|
|
93
|
+
failures: [{ drift: { kind: handler.kind }, cause }],
|
|
94
|
+
pass,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return collected;
|
|
99
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: ADR-017 drift handler registry. Single source of truth for
|
|
3
|
+
// the catalog. Tests can override per-call via ReconciliationDeps.registry.
|
|
4
|
+
import { completionTimestampHandler } from "./drift/completion.js";
|
|
5
|
+
import { mergeStateHandler } from "./drift/merge-state.js";
|
|
6
|
+
import { unregisteredMilestoneHandler } from "./drift/project-md.js";
|
|
7
|
+
import { roadmapDivergenceHandler } from "./drift/roadmap.js";
|
|
8
|
+
import { sketchFlagHandler } from "./drift/sketch-flag.js";
|
|
9
|
+
import { staleRenderHandler } from "./drift/stale-render.js";
|
|
10
|
+
import { staleWorkerHandler } from "./drift/stale-worker.js";
|
|
11
|
+
// Each handler is parameterized over its specific DriftRecord variant for
|
|
12
|
+
// internal type safety. The registry stores them under DriftHandler<any> so
|
|
13
|
+
// handlers with disjoint repair parameter types coexist; the lifecycle matches
|
|
14
|
+
// by kind before invoking repair, so this is sound at runtime.
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
16
|
+
export const DRIFT_REGISTRY = [
|
|
17
|
+
sketchFlagHandler,
|
|
18
|
+
mergeStateHandler,
|
|
19
|
+
staleRenderHandler,
|
|
20
|
+
staleWorkerHandler,
|
|
21
|
+
unregisteredMilestoneHandler,
|
|
22
|
+
roadmapDivergenceHandler,
|
|
23
|
+
completionTimestampHandler,
|
|
24
|
+
];
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: ADR-017 #5707 caller-closure helper. Parent processes that
|
|
3
|
+
// spawn auto-loop workers must reconcile before spawn — otherwise each
|
|
4
|
+
// worker independently detects+repairs the same drift, racing on shared
|
|
5
|
+
// state. This helper centralises the reconcile+catch flow so the two
|
|
6
|
+
// production spawn sites (commands/handlers/parallel.ts and auto/phases.ts
|
|
7
|
+
// startSliceParallel) share one contract.
|
|
8
|
+
import { reconcileBeforeDispatch, ReconciliationFailedError, } from "./index.js";
|
|
9
|
+
/**
|
|
10
|
+
* Run reconciliation before spawning workers. Returns ok=true when the run
|
|
11
|
+
* completed without throwing (blockers ride along but don't fail the gate —
|
|
12
|
+
* spawn callers can choose how to handle them). On
|
|
13
|
+
* ReconciliationFailedError, returns ok=false with the error message so the
|
|
14
|
+
* caller can surface it to the user without re-throwing.
|
|
15
|
+
*
|
|
16
|
+
* Other unexpected errors propagate; they are not part of the drift
|
|
17
|
+
* taxonomy.
|
|
18
|
+
*/
|
|
19
|
+
export async function reconcileBeforeSpawn(basePath, deps = {}) {
|
|
20
|
+
const reconcileFn = deps.reconcile ?? reconcileBeforeDispatch;
|
|
21
|
+
try {
|
|
22
|
+
const result = await reconcileFn(basePath, deps);
|
|
23
|
+
if (result.blockers.length > 0) {
|
|
24
|
+
return {
|
|
25
|
+
ok: false,
|
|
26
|
+
reason: `Reconciliation blocker: ${result.blockers[0]}`,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
const repairedKinds = result.repaired.map((d) => d.kind);
|
|
30
|
+
return {
|
|
31
|
+
ok: true,
|
|
32
|
+
reason: repairedKinds.length > 0
|
|
33
|
+
? `repaired before spawn: ${repairedKinds.join(", ")}`
|
|
34
|
+
: undefined,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
if (err instanceof ReconciliationFailedError) {
|
|
39
|
+
return { ok: false, reason: err.message };
|
|
40
|
+
}
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,27 +1,6 @@
|
|
|
1
1
|
// Project/App: GSD-2
|
|
2
|
-
// File Purpose: ADR-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
};
|
|
8
|
-
export async function reconcileBeforeDispatch(basePath, deps = defaultDeps, opts) {
|
|
9
|
-
deps.invalidateStateCache();
|
|
10
|
-
const stateSnapshot = await deps.deriveState(basePath, opts);
|
|
11
|
-
const blockers = stateSnapshot.blockers ?? [];
|
|
12
|
-
if (blockers.length > 0 || stateSnapshot.phase === "blocked") {
|
|
13
|
-
return {
|
|
14
|
-
ok: false,
|
|
15
|
-
reason: blockers[0] ?? `State reconciliation blocked in phase ${stateSnapshot.phase}`,
|
|
16
|
-
stateSnapshot,
|
|
17
|
-
repaired: ["derive-state-cache-invalidated"],
|
|
18
|
-
blockers,
|
|
19
|
-
};
|
|
20
|
-
}
|
|
21
|
-
return {
|
|
22
|
-
ok: true,
|
|
23
|
-
stateSnapshot,
|
|
24
|
-
repaired: ["derive-state-cache-invalidated"],
|
|
25
|
-
blockers,
|
|
26
|
-
};
|
|
27
|
-
}
|
|
2
|
+
// File Purpose: ADR-017 State Reconciliation Module — public entry point.
|
|
3
|
+
// Re-exports the drift-driven implementation from the state-reconciliation/
|
|
4
|
+
// folder so existing import paths (./state-reconciliation.js) keep working.
|
|
5
|
+
export { reconcileBeforeDispatch, ReconciliationFailedError, DRIFT_REGISTRY, } from "./state-reconciliation/index.js";
|
|
6
|
+
export { reconcileBeforeSpawn } from "./state-reconciliation/spawn-gate.js";
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Shared terminal rendering helpers for GSD extension TUI surfaces.
|
|
3
|
+
import { truncateToWidth, visibleWidth, wrapTextWithAnsi } from "@gsd/pi-tui";
|
|
4
|
+
export function safeLine(text, width, ellipsis = "…") {
|
|
5
|
+
if (width <= 0)
|
|
6
|
+
return "";
|
|
7
|
+
return truncateToWidth(text, width, ellipsis);
|
|
8
|
+
}
|
|
9
|
+
export function padRightVisible(text, width) {
|
|
10
|
+
if (width <= 0)
|
|
11
|
+
return "";
|
|
12
|
+
const truncated = safeLine(text, width);
|
|
13
|
+
const pad = Math.max(0, width - visibleWidth(truncated));
|
|
14
|
+
return truncated + " ".repeat(pad);
|
|
15
|
+
}
|
|
16
|
+
export function rightAlign(left, right, width) {
|
|
17
|
+
if (width <= 0)
|
|
18
|
+
return "";
|
|
19
|
+
if (!right)
|
|
20
|
+
return safeLine(left, width);
|
|
21
|
+
if (!left)
|
|
22
|
+
return safeLine(" ".repeat(Math.max(0, width - visibleWidth(right))) + right, width);
|
|
23
|
+
const gap = Math.max(1, width - visibleWidth(left) - visibleWidth(right));
|
|
24
|
+
return safeLine(left + " ".repeat(gap) + right, width);
|
|
25
|
+
}
|
|
26
|
+
export function wrapVisibleText(text, width) {
|
|
27
|
+
if (width <= 0)
|
|
28
|
+
return [text];
|
|
29
|
+
return wrapTextWithAnsi(text, width).map((line) => visibleWidth(line) > width ? truncateToWidth(line, width, "…") : line);
|
|
30
|
+
}
|
|
31
|
+
export function renderBar(theme, width, color = "muted") {
|
|
32
|
+
return safeLine(theme.fg(color, "─".repeat(Math.max(0, width))), width, "");
|
|
33
|
+
}
|
|
34
|
+
export function renderKeyHints(theme, hints, width) {
|
|
35
|
+
return safeLine(theme.fg("dim", hints.filter(Boolean).join(" │ ")), width);
|
|
36
|
+
}
|
|
37
|
+
export function renderProgressBar(theme, done, total, width, options = {}) {
|
|
38
|
+
const barWidth = Math.max(0, width);
|
|
39
|
+
const pct = total > 0 ? Math.max(0, Math.min(1, done / total)) : 0;
|
|
40
|
+
const filled = Math.round(pct * barWidth);
|
|
41
|
+
const filledChar = options.filledChar ?? "█";
|
|
42
|
+
const emptyChar = options.emptyChar ?? "░";
|
|
43
|
+
return (theme.fg(options.filledColor ?? "success", filledChar.repeat(filled)) +
|
|
44
|
+
theme.fg(options.emptyColor ?? "dim", emptyChar.repeat(barWidth - filled)));
|
|
45
|
+
}
|
|
46
|
+
export function statusGlyph(theme, level) {
|
|
47
|
+
switch (level) {
|
|
48
|
+
case "active": return theme.fg("success", "●");
|
|
49
|
+
case "success": return theme.fg("success", "✓");
|
|
50
|
+
case "warning": return theme.fg("warning", "!");
|
|
51
|
+
case "error": return theme.fg("error", "x");
|
|
52
|
+
case "idle":
|
|
53
|
+
default: return theme.fg("dim", "○");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
export function renderFrame(theme, inner, width, options = {}) {
|
|
57
|
+
if (width < 4)
|
|
58
|
+
return inner.map((line) => safeLine(line, width));
|
|
59
|
+
const borderColor = options.borderColor ?? "borderAccent";
|
|
60
|
+
const paddingX = Math.max(0, options.paddingX ?? 1);
|
|
61
|
+
const contentWidth = Math.max(0, width - 2 - paddingX * 2);
|
|
62
|
+
const border = (text) => theme.fg(borderColor, text);
|
|
63
|
+
const pad = " ".repeat(paddingX);
|
|
64
|
+
const lines = [border("╭" + "─".repeat(width - 2) + "╮")];
|
|
65
|
+
for (const line of inner) {
|
|
66
|
+
lines.push(border("│") +
|
|
67
|
+
pad +
|
|
68
|
+
padRightVisible(line, contentWidth) +
|
|
69
|
+
pad +
|
|
70
|
+
border("│"));
|
|
71
|
+
}
|
|
72
|
+
lines.push(border("╰" + "─".repeat(width - 2) + "╯"));
|
|
73
|
+
return lines.map((line) => safeLine(line, width, ""));
|
|
74
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Watch-mode terminal header and splash renderer for GSD project status.
|
|
3
3
|
import { execFileSync } from "node:child_process";
|
|
4
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
5
5
|
import { homedir } from "node:os";
|
|
@@ -7,25 +7,57 @@ import { join } from "node:path";
|
|
|
7
7
|
import { visibleWidth, truncateToWidth } from "@gsd/pi-tui";
|
|
8
8
|
import { loadEffectiveGSDPreferences } from "../preferences.js";
|
|
9
9
|
import { gsdHome } from "../gsd-home.js";
|
|
10
|
+
import { splashPalette } from "./splash-palette.js";
|
|
10
11
|
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
11
|
-
/**
|
|
12
|
-
* GSD ASCII logo — inlined here because the canonical src/logo.ts is outside
|
|
13
|
-
* the resources rootDir and cannot be imported directly.
|
|
14
|
-
*/
|
|
15
12
|
const GSD_LOGO = [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
" ██████╗ ███████╗██████╗ ",
|
|
14
|
+
" ██╔════╝ ██╔════╝██╔══██╗",
|
|
15
|
+
" ██║ ███╗███████╗██║ ██║",
|
|
16
|
+
" ██║ ██║╚════██║██║ ██║",
|
|
17
|
+
" ╚██████╔╝███████║██████╔╝",
|
|
18
|
+
" ╚═════╝ ╚══════╝╚═════╝ ",
|
|
22
19
|
];
|
|
23
|
-
/** Separator character for the horizontal divider line. */
|
|
24
|
-
const SEPARATOR_CHAR = "─";
|
|
25
|
-
/** Vertical bar between logo and info panel. */
|
|
26
|
-
const PANEL_DIVIDER = "│";
|
|
27
20
|
/** Label column width for Model/Provider/Directory/Branch rows. */
|
|
28
21
|
const LABEL_COL_WIDTH = 10;
|
|
22
|
+
const ANSI_RESET = "\x1b[0m";
|
|
23
|
+
const ANSI_BOLD = "\x1b[1m";
|
|
24
|
+
function rgb(hex) {
|
|
25
|
+
const cleaned = hex.replace("#", "");
|
|
26
|
+
const r = Number.parseInt(cleaned.slice(0, 2), 16);
|
|
27
|
+
const g = Number.parseInt(cleaned.slice(2, 4), 16);
|
|
28
|
+
const b = Number.parseInt(cleaned.slice(4, 6), 16);
|
|
29
|
+
return `\x1b[38;2;${r};${g};${b}m`;
|
|
30
|
+
}
|
|
31
|
+
const colors = {
|
|
32
|
+
accent: rgb(splashPalette.accent),
|
|
33
|
+
border: rgb(splashPalette.border),
|
|
34
|
+
muted: rgb(splashPalette.muted),
|
|
35
|
+
dim: rgb(splashPalette.dim),
|
|
36
|
+
text: rgb(splashPalette.text),
|
|
37
|
+
success: rgb(splashPalette.success),
|
|
38
|
+
};
|
|
39
|
+
function color(text, colorCode) {
|
|
40
|
+
return `${colorCode}${text}${ANSI_RESET}`;
|
|
41
|
+
}
|
|
42
|
+
function bold(text) {
|
|
43
|
+
return `${ANSI_BOLD}${text}${ANSI_RESET}`;
|
|
44
|
+
}
|
|
45
|
+
function padVisible(text, width) {
|
|
46
|
+
const clipped = truncateToWidth(text, Math.max(0, width), "");
|
|
47
|
+
return clipped + " ".repeat(Math.max(0, width - visibleWidth(clipped)));
|
|
48
|
+
}
|
|
49
|
+
function rightAlign(left, right, width) {
|
|
50
|
+
if (!right)
|
|
51
|
+
return truncateToWidth(left, width, "");
|
|
52
|
+
const gap = Math.max(1, width - visibleWidth(left) - visibleWidth(right));
|
|
53
|
+
return truncateToWidth(left + " ".repeat(gap) + right, width, "");
|
|
54
|
+
}
|
|
55
|
+
function frameLine(content, width) {
|
|
56
|
+
if (width < 3)
|
|
57
|
+
return truncateToWidth(content, Math.max(0, width), "");
|
|
58
|
+
const innerWidth = Math.max(0, width - 2);
|
|
59
|
+
return `${color("│", colors.border)}${padVisible(content, innerWidth)}${color("│", colors.border)}`;
|
|
60
|
+
}
|
|
29
61
|
// ─── Data Readers ─────────────────────────────────────────────────────────────
|
|
30
62
|
/**
|
|
31
63
|
* Read the configured execution model from GSD preferences.
|
|
@@ -147,12 +179,11 @@ export function gatherHeaderData(projectRoot) {
|
|
|
147
179
|
* Returns empty string if value is empty.
|
|
148
180
|
*/
|
|
149
181
|
function formatInfoLine(label, value, availableWidth) {
|
|
150
|
-
const
|
|
151
|
-
const
|
|
152
|
-
const padding = " ".repeat(Math.max(1, LABEL_COL_WIDTH - labelVis));
|
|
182
|
+
const labelText = bold(color(label, colors.text));
|
|
183
|
+
const padding = " ".repeat(Math.max(1, LABEL_COL_WIDTH - label.length));
|
|
153
184
|
const maxValueWidth = Math.max(1, availableWidth - LABEL_COL_WIDTH);
|
|
154
185
|
const truncValue = truncateToWidth(value, maxValueWidth, "…");
|
|
155
|
-
return
|
|
186
|
+
return labelText + padding + color(truncValue, colors.muted);
|
|
156
187
|
}
|
|
157
188
|
/**
|
|
158
189
|
* Format MCP server names as a dot-separated row with checkmarks.
|
|
@@ -164,7 +195,7 @@ export function formatMcpRow(servers, width) {
|
|
|
164
195
|
// Capitalize first letter of each server name
|
|
165
196
|
const items = servers.map(s => {
|
|
166
197
|
const cap = s.charAt(0).toUpperCase() + s.slice(1);
|
|
167
|
-
return `${cap}
|
|
198
|
+
return `${color(cap, colors.accent)} ${color("✓", colors.success)}`;
|
|
168
199
|
});
|
|
169
200
|
const full = items.join(" · ");
|
|
170
201
|
if (visibleWidth(full) <= width)
|
|
@@ -175,70 +206,62 @@ export function formatMcpRow(servers, width) {
|
|
|
175
206
|
/**
|
|
176
207
|
* Render the full header as an array of terminal-safe strings.
|
|
177
208
|
*
|
|
178
|
-
* Layout: GSD
|
|
179
|
-
*
|
|
209
|
+
* Layout: compact GSD mark on the left with a command-center status panel on
|
|
210
|
+
* the right. This keeps the splash visual while making the actionable command
|
|
211
|
+
* and workspace state easier to scan.
|
|
180
212
|
*/
|
|
181
213
|
export function renderHeaderLines(data, width) {
|
|
182
|
-
|
|
183
|
-
|
|
214
|
+
if (width < 40)
|
|
215
|
+
return renderStackedHeader(data, width);
|
|
216
|
+
const outerWidth = width;
|
|
217
|
+
const innerWidth = Math.max(0, outerWidth - 2);
|
|
184
218
|
const logoLines = GSD_LOGO;
|
|
185
|
-
const logoWidth = Math.max(...logoLines.map(
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
const infoPanelWidth = width - logoWidth - dividerOverhead;
|
|
190
|
-
// If terminal is too narrow for side-by-side, fall back to stacked layout
|
|
191
|
-
if (infoPanelWidth < 20) {
|
|
219
|
+
const logoWidth = Math.max(...logoLines.map((line) => visibleWidth(line)));
|
|
220
|
+
const gap = ` ${color("│", colors.dim)} `;
|
|
221
|
+
const panelWidth = innerWidth - logoWidth - visibleWidth(gap);
|
|
222
|
+
if (panelWidth < 44) {
|
|
192
223
|
return renderStackedHeader(data, width);
|
|
193
224
|
}
|
|
194
|
-
|
|
195
|
-
const
|
|
196
|
-
|
|
197
|
-
"",
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
225
|
+
const mcpRow = formatMcpRow(data.mcpServers, Math.max(1, panelWidth - 9)) || color("none configured", colors.dim);
|
|
226
|
+
const panelLines = [
|
|
227
|
+
rightAlign(`${color("GSD", colors.accent)} ${bold(color("Project Console", colors.text))}`, color("idle", colors.muted), panelWidth),
|
|
228
|
+
rightAlign(`${color("Project", colors.muted)} ${color(data.directory, colors.text)}`, `${color("Command", colors.muted)} ${color("/gsd start", colors.accent)}`, panelWidth),
|
|
229
|
+
rightAlign(`${color("Branch", colors.muted)} ${color(data.branch, colors.text)}`, `${color("Mode", colors.muted)} ${color("manual", colors.text)}`, panelWidth),
|
|
230
|
+
rightAlign(`${color("MCP", colors.muted)} ${mcpRow}`, `${color("Model", colors.muted)} ${color(data.model, colors.text)}`, panelWidth),
|
|
231
|
+
rightAlign(`${color("Provider", colors.muted)} ${color(data.provider, colors.text)}`, `${color("Workspace", colors.muted)} ${color(data.directory, colors.text)}`, panelWidth),
|
|
232
|
+
rightAlign(color("/gsd to begin", colors.accent), `${color("/gsd templates", colors.muted)} ${color("/gsd help", colors.muted)}`, panelWidth),
|
|
202
233
|
];
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const
|
|
208
|
-
|
|
209
|
-
const logoPad = " ".repeat(Math.max(0, logoWidth - visibleWidth(logoLine)));
|
|
210
|
-
lines.push(`${logoLine}${logoPad} ${PANEL_DIVIDER} ${infoLine}`);
|
|
211
|
-
}
|
|
212
|
-
// Blank line after logo+info block
|
|
213
|
-
lines.push("");
|
|
214
|
-
// MCP server row
|
|
215
|
-
const mcpRow = formatMcpRow(data.mcpServers, width);
|
|
216
|
-
if (mcpRow) {
|
|
217
|
-
lines.push(` ${mcpRow}`);
|
|
234
|
+
const lines = [
|
|
235
|
+
color("╭" + "─".repeat(Math.max(0, outerWidth - 2)) + "╮", colors.border),
|
|
236
|
+
];
|
|
237
|
+
for (let i = 0; i < logoLines.length; i++) {
|
|
238
|
+
const logo = padVisible(color(logoLines[i], colors.border), logoWidth);
|
|
239
|
+
lines.push(frameLine(`${logo}${gap}${panelLines[i] ?? ""}`, outerWidth));
|
|
218
240
|
}
|
|
219
|
-
|
|
220
|
-
lines.push(SEPARATOR_CHAR.repeat(width));
|
|
241
|
+
lines.push(color("╰" + "─".repeat(Math.max(0, outerWidth - 2)) + "╯", colors.border));
|
|
221
242
|
return lines;
|
|
222
243
|
}
|
|
223
244
|
/**
|
|
224
245
|
* Fallback stacked layout for narrow terminals (< 20 cols for info panel).
|
|
225
246
|
*/
|
|
226
247
|
function renderStackedHeader(data, width) {
|
|
227
|
-
const
|
|
248
|
+
const outerWidth = Math.max(0, width);
|
|
249
|
+
if (outerWidth < 3) {
|
|
250
|
+
return [color(truncateToWidth("GSD", outerWidth, ""), colors.accent)];
|
|
251
|
+
}
|
|
252
|
+
const lines = [color("╭" + "─".repeat(Math.max(0, outerWidth - 2)) + "╮", colors.border)];
|
|
228
253
|
// Title
|
|
229
|
-
lines.push(
|
|
230
|
-
lines.push("");
|
|
254
|
+
lines.push(frameLine(`${color("GSD", colors.accent)} ${bold(color("Project Console", colors.text))}`, outerWidth));
|
|
231
255
|
// Info
|
|
232
|
-
lines.push(formatInfoLine("
|
|
233
|
-
lines.push(formatInfoLine("
|
|
234
|
-
lines.push(formatInfoLine("
|
|
235
|
-
lines.push(formatInfoLine("
|
|
236
|
-
lines.push("");
|
|
256
|
+
lines.push(frameLine(formatInfoLine("Project", data.directory, outerWidth - 2), outerWidth));
|
|
257
|
+
lines.push(frameLine(formatInfoLine("Command", "/gsd start", outerWidth - 2), outerWidth));
|
|
258
|
+
lines.push(frameLine(formatInfoLine("Branch", data.branch, outerWidth - 2), outerWidth));
|
|
259
|
+
lines.push(frameLine(formatInfoLine("Model", data.model, outerWidth - 2), outerWidth));
|
|
237
260
|
// MCP
|
|
238
|
-
const mcpRow = formatMcpRow(data.mcpServers,
|
|
261
|
+
const mcpRow = formatMcpRow(data.mcpServers, Math.max(1, outerWidth - 7));
|
|
239
262
|
if (mcpRow)
|
|
240
|
-
lines.push(
|
|
241
|
-
|
|
242
|
-
lines.push(
|
|
263
|
+
lines.push(frameLine(`${color("MCP", colors.muted)} ${mcpRow}`, outerWidth));
|
|
264
|
+
lines.push(frameLine(`${color("/gsd to begin", colors.accent)} ${color("/gsd help", colors.muted)}`, outerWidth));
|
|
265
|
+
lines.push(color("╰" + "─".repeat(Math.max(0, outerWidth - 2)) + "╯", colors.border));
|
|
243
266
|
return lines;
|
|
244
267
|
}
|
|
@@ -266,7 +266,7 @@ export function getRequiredWorkflowToolsForGuidedUnit(unitType) {
|
|
|
266
266
|
case "execute-task":
|
|
267
267
|
return ["gsd_task_complete"];
|
|
268
268
|
case "complete-slice":
|
|
269
|
-
return ["gsd_slice_complete"];
|
|
269
|
+
return ["gsd_slice_complete", "gsd_task_reopen", "gsd_replan_slice"];
|
|
270
270
|
default:
|
|
271
271
|
return [];
|
|
272
272
|
}
|
|
@@ -294,7 +294,7 @@ export function getRequiredWorkflowToolsForAutoUnit(unitType) {
|
|
|
294
294
|
case "reactive-execute":
|
|
295
295
|
return ["gsd_task_complete"];
|
|
296
296
|
case "complete-slice":
|
|
297
|
-
return ["gsd_slice_complete"];
|
|
297
|
+
return ["gsd_slice_complete", "gsd_task_reopen", "gsd_replan_slice"];
|
|
298
298
|
case "replan-slice":
|
|
299
299
|
return ["gsd_replan_slice"];
|
|
300
300
|
case "reassess-roadmap":
|