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,56 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Visual contract tests for the recommended indented assistant message rail design.
|
|
3
|
+
|
|
4
|
+
import { describe, test } from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import stripAnsi from "strip-ansi";
|
|
7
|
+
import type { AssistantMessage } from "@gsd/pi-ai";
|
|
8
|
+
|
|
9
|
+
import { initTheme } from "../../theme/theme.js";
|
|
10
|
+
import { AssistantMessageComponent } from "../assistant-message.js";
|
|
11
|
+
import { formatTimestamp } from "../timestamp.js";
|
|
12
|
+
|
|
13
|
+
initTheme("dark", false);
|
|
14
|
+
|
|
15
|
+
describe("AssistantMessageComponent recommended rail design", () => {
|
|
16
|
+
test("renders assistant content with a lightly indented left rail", () => {
|
|
17
|
+
const message = {
|
|
18
|
+
id: "m1",
|
|
19
|
+
role: "assistant",
|
|
20
|
+
provider: "test",
|
|
21
|
+
model: "gpt-test",
|
|
22
|
+
timestamp: 1,
|
|
23
|
+
content: [{ type: "text", text: "I will update the renderer and run verification." }],
|
|
24
|
+
} as unknown as AssistantMessage;
|
|
25
|
+
|
|
26
|
+
const component = new AssistantMessageComponent(message, true);
|
|
27
|
+
const raw = component.render(80);
|
|
28
|
+
const plain = raw.map((line) => stripAnsi(line));
|
|
29
|
+
const joined = plain.join("\n");
|
|
30
|
+
|
|
31
|
+
assert.ok(plain.some((line) => line.startsWith(" ┃ ")), `expected indented rail-prefixed lines:\n${joined}`);
|
|
32
|
+
assert.ok(raw.some((line) => line.includes("\x1b[48;")), `expected faint assistant block background:\n${raw.join("\n")}`);
|
|
33
|
+
assert.match(joined, /^\s*┃\s*$/m, "assistant block should include vertical padding rows");
|
|
34
|
+
assert.match(joined, /GSD/);
|
|
35
|
+
assert.match(joined, /gpt-test/);
|
|
36
|
+
assert.match(joined, /update the renderer/);
|
|
37
|
+
assert.doesNotMatch(joined, /^┃/m, "assistant rail should be slightly indented from the left edge");
|
|
38
|
+
assert.doesNotMatch(joined, /^╭/m, "assistant messages should not use rounded card borders");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("renders metadata for a zero timestamp", () => {
|
|
42
|
+
const message = {
|
|
43
|
+
id: "m1",
|
|
44
|
+
role: "assistant",
|
|
45
|
+
provider: "test",
|
|
46
|
+
model: "gpt-test",
|
|
47
|
+
timestamp: 0,
|
|
48
|
+
content: [{ type: "text", text: "Finished." }],
|
|
49
|
+
} as unknown as AssistantMessage;
|
|
50
|
+
|
|
51
|
+
const component = new AssistantMessageComponent(message, true);
|
|
52
|
+
const joined = component.render(80).map((line) => stripAnsi(line)).join("\n");
|
|
53
|
+
|
|
54
|
+
assert.match(joined, new RegExp(formatTimestamp(0)));
|
|
55
|
+
});
|
|
56
|
+
});
|
package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
// GSD-2
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Tests for interactive terminal tool execution rendering.
|
|
2
3
|
import { describe, test } from "node:test";
|
|
3
4
|
import assert from "node:assert/strict";
|
|
4
5
|
import stripAnsi from "strip-ansi";
|
|
@@ -60,6 +61,23 @@ describe("ToolExecutionComponent", () => {
|
|
|
60
61
|
assert.match(rendered, /running · \d+(ms|s)/);
|
|
61
62
|
});
|
|
62
63
|
|
|
64
|
+
test("does not duplicate running generic tool labels before args", () => {
|
|
65
|
+
const rendered = renderToolCollapsed(
|
|
66
|
+
"Agent",
|
|
67
|
+
{
|
|
68
|
+
description: "Scout habit tracker codebase",
|
|
69
|
+
subagent_type: "Explore",
|
|
70
|
+
prompt: "Read these files and give me a concise summary of each.",
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
const labelMatches = rendered.match(/Agent/g) ?? [];
|
|
75
|
+
assert.equal(labelMatches.length, 1, `expected only the card title to contain Agent:\n${rendered}`);
|
|
76
|
+
assert.doesNotMatch(rendered, /description="Scout habit tracker codebase"/);
|
|
77
|
+
assert.doesNotMatch(rendered, /subagent_type="Explore"/);
|
|
78
|
+
assert.match(rendered, /running · \d+(ms|s)/);
|
|
79
|
+
});
|
|
80
|
+
|
|
63
81
|
test("renders framed header with failed status for failed tool result", () => {
|
|
64
82
|
const rendered = renderTool(
|
|
65
83
|
"mcp__demo__do_thing",
|
|
@@ -87,6 +105,19 @@ describe("ToolExecutionComponent", () => {
|
|
|
87
105
|
assert.doesNotMatch(rendered, /ok=true/);
|
|
88
106
|
});
|
|
89
107
|
|
|
108
|
+
test("does not duplicate generic tool labels in collapsed cards", () => {
|
|
109
|
+
const rendered = renderToolCollapsed(
|
|
110
|
+
"TodoWrite",
|
|
111
|
+
{ todos: [{ content: "Ship it", status: "pending" }] },
|
|
112
|
+
{ content: [{ type: "text", text: "TodoWrite" }], isError: false },
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
const labelMatches = rendered.match(/TodoWrite/g) ?? [];
|
|
116
|
+
assert.equal(labelMatches.length, 1, `expected only the card title to contain TodoWrite:\n${rendered}`);
|
|
117
|
+
assert.match(rendered, /output hidden/);
|
|
118
|
+
assert.match(rendered, /ctrl\+o expand/);
|
|
119
|
+
});
|
|
120
|
+
|
|
90
121
|
test("exposes phase metadata for successful low-signal tool rows", () => {
|
|
91
122
|
const component = new ToolExecutionComponent(
|
|
92
123
|
"gsd_requirement_update",
|
|
@@ -132,8 +163,41 @@ describe("ToolExecutionComponent", () => {
|
|
|
132
163
|
},
|
|
133
164
|
);
|
|
134
165
|
|
|
135
|
-
assert.match(rendered, /
|
|
166
|
+
assert.match(rendered, /Read/);
|
|
167
|
+
assert.match(rendered, /src\/Inspector\.tsx:4-12/);
|
|
136
168
|
assert.doesNotMatch(rendered, /source/);
|
|
169
|
+
assert.doesNotMatch(rendered, /output hidden\n\s*│\s*ctrl\+o expand/);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
test("renders compact capitalized read rows from file_path args", () => {
|
|
173
|
+
const rendered = renderToolCollapsed(
|
|
174
|
+
"Read",
|
|
175
|
+
{ file_path: "~/Github/gsd-2/src/resources/extensions/gsd/health-widget-core.ts" },
|
|
176
|
+
{ content: [{ type: "text", text: "hidden body output" }], isError: false },
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
assert.match(rendered, /Read/);
|
|
180
|
+
assert.match(rendered, /health-widget-core\.ts/);
|
|
181
|
+
assert.doesNotMatch(rendered, /hidden body output/);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("renders compact read rows from direct result details path", () => {
|
|
185
|
+
const rendered = renderToolCollapsed(
|
|
186
|
+
"read",
|
|
187
|
+
{},
|
|
188
|
+
{
|
|
189
|
+
content: [{ type: "text", text: "hidden body output" }],
|
|
190
|
+
isError: false,
|
|
191
|
+
details: {
|
|
192
|
+
path: "/tmp/project/src/resources/extensions/gsd/health-widget-core.ts",
|
|
193
|
+
range: { start: 1, end: 12 },
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
);
|
|
197
|
+
|
|
198
|
+
assert.match(rendered, /Read/);
|
|
199
|
+
assert.match(rendered, /health-widget-core\.ts:1-12/);
|
|
200
|
+
assert.doesNotMatch(rendered, /hidden body output/);
|
|
137
201
|
});
|
|
138
202
|
|
|
139
203
|
test("renders compact edit rows with target metadata", () => {
|
|
@@ -155,10 +219,21 @@ describe("ToolExecutionComponent", () => {
|
|
|
155
219
|
},
|
|
156
220
|
);
|
|
157
221
|
|
|
158
|
-
assert.match(rendered, /
|
|
222
|
+
assert.match(rendered, /Edit/);
|
|
223
|
+
assert.match(rendered, /src\/Inspector\.tsx:42/);
|
|
159
224
|
assert.doesNotMatch(rendered, /Updated src\/Inspector\.tsx/);
|
|
160
225
|
});
|
|
161
226
|
|
|
227
|
+
test("renders running edit rows with title and target on the top line", () => {
|
|
228
|
+
const rendered = renderToolCollapsed("edit", { path: "src/Inspector.tsx" });
|
|
229
|
+
|
|
230
|
+
const labelMatches = rendered.match(/Edit/g) ?? [];
|
|
231
|
+
assert.equal(labelMatches.length, 1, `expected tool name only in the card title:\n${rendered}`);
|
|
232
|
+
assert.match(rendered, /src\/Inspector\.tsx/);
|
|
233
|
+
assert.match(rendered, /Edit src\/Inspector\.tsx/);
|
|
234
|
+
assert.match(rendered, /running · \d+(ms|s)/);
|
|
235
|
+
});
|
|
236
|
+
|
|
162
237
|
test("renders compact write rows with target metadata", () => {
|
|
163
238
|
const rendered = renderToolCollapsed(
|
|
164
239
|
"write",
|
|
@@ -177,10 +252,36 @@ describe("ToolExecutionComponent", () => {
|
|
|
177
252
|
},
|
|
178
253
|
);
|
|
179
254
|
|
|
180
|
-
assert.match(rendered, /
|
|
255
|
+
assert.match(rendered, /Write/);
|
|
256
|
+
assert.match(rendered, /src\/output\.ts/);
|
|
181
257
|
assert.doesNotMatch(rendered, /Successfully wrote/);
|
|
182
258
|
});
|
|
183
259
|
|
|
260
|
+
test("omits default cwd placeholders for collapsed search tools", () => {
|
|
261
|
+
const rendered = renderToolCollapsed(
|
|
262
|
+
"Grep",
|
|
263
|
+
{},
|
|
264
|
+
{ content: [{ type: "text", text: "hidden body output" }], isError: false },
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
assert.match(rendered, /Grep/);
|
|
268
|
+
assert.doesNotMatch(rendered, /^│\.\s+│/m, `expected no placeholder cwd body:\n${rendered}`);
|
|
269
|
+
assert.match(rendered, /output hidden/);
|
|
270
|
+
assert.doesNotMatch(rendered, /hidden body output/);
|
|
271
|
+
assert.doesNotMatch(rendered, /^│\s+output hidden/m, `expected compact footer text on the top row:\n${rendered}`);
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
test("keeps meaningful collapsed search targets", () => {
|
|
275
|
+
const rendered = renderToolCollapsed(
|
|
276
|
+
"Grep",
|
|
277
|
+
{ pattern: "Project Initialized", path: "src/resources/extensions/gsd", glob: "*.ts" },
|
|
278
|
+
{ content: [{ type: "text", text: "hidden body output" }], isError: false },
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
assert.match(rendered, /Project Initialized in src\/resources\/extensions\/gsd \(\*\.ts\)/);
|
|
282
|
+
assert.doesNotMatch(rendered, /hidden body output/);
|
|
283
|
+
});
|
|
284
|
+
|
|
184
285
|
test("renders compact bash rows with command preview", () => {
|
|
185
286
|
const rendered = renderToolCollapsed(
|
|
186
287
|
"bash",
|
|
@@ -188,7 +289,8 @@ describe("ToolExecutionComponent", () => {
|
|
|
188
289
|
{ content: [{ type: "text", text: "ok" }], isError: false, details: { cwd: "/tmp/project" } },
|
|
189
290
|
);
|
|
190
291
|
|
|
191
|
-
assert.match(rendered,
|
|
292
|
+
assert.match(rendered, /\$ npm run typecheck -- --watch false/);
|
|
293
|
+
assert.doesNotMatch(rendered, /├/, "collapsed command cards should not include internal divider lines");
|
|
192
294
|
assert.doesNotMatch(rendered, /\bok\b/);
|
|
193
295
|
});
|
|
194
296
|
|
|
@@ -339,7 +441,7 @@ describe("ToolExecutionComponent", () => {
|
|
|
339
441
|
assert.doesNotMatch(rendered, /gsd_requirement_update/);
|
|
340
442
|
});
|
|
341
443
|
|
|
342
|
-
test("
|
|
444
|
+
test("collapsed generic running tools hide primitive args", () => {
|
|
343
445
|
const longPath = "/Users/alice/.gsd/projects/4dce7b775013/worktrees/slice-S03-some-long-path-that-exceeds-limit";
|
|
344
446
|
const rendered = renderToolCollapsed("gsd_slice_complete", {
|
|
345
447
|
sliceId: "S03",
|
|
@@ -347,9 +449,11 @@ describe("ToolExecutionComponent", () => {
|
|
|
347
449
|
worktree: longPath,
|
|
348
450
|
});
|
|
349
451
|
|
|
350
|
-
assert.match(rendered, /
|
|
351
|
-
assert.match(rendered, /
|
|
352
|
-
assert.
|
|
452
|
+
assert.match(rendered, /Slice Complete/);
|
|
453
|
+
assert.match(rendered, /running · \d+(ms|s)/);
|
|
454
|
+
assert.doesNotMatch(rendered, /sliceId="S03"/);
|
|
455
|
+
assert.doesNotMatch(rendered, /milestoneId="M001"/);
|
|
456
|
+
assert.doesNotMatch(rendered, /worktree=/);
|
|
353
457
|
assert.doesNotMatch(rendered, /"sliceId":\s*"S03"/);
|
|
354
458
|
});
|
|
355
459
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Visual contract tests for left-edge user chat rails.
|
|
3
|
+
|
|
4
|
+
import { describe, test } from "node:test";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
import { stripVTControlCharacters } from "node:util";
|
|
7
|
+
import type { AssistantMessage } from "@gsd/pi-ai";
|
|
8
|
+
|
|
9
|
+
import { initTheme } from "../../theme/theme.js";
|
|
10
|
+
import { AssistantMessageComponent } from "../assistant-message.js";
|
|
11
|
+
import { UserMessageComponent } from "../user-message.js";
|
|
12
|
+
|
|
13
|
+
initTheme("dark", false);
|
|
14
|
+
|
|
15
|
+
describe("UserMessageComponent chat rail design", () => {
|
|
16
|
+
test("renders user messages against the left edge", () => {
|
|
17
|
+
const component = new UserMessageComponent("Can we make the transcript feel like chat?", undefined, 1, "date-time-iso");
|
|
18
|
+
const raw = component.render(100);
|
|
19
|
+
const plain = raw.map((line) => stripVTControlCharacters(line));
|
|
20
|
+
const joined = plain.join("\n");
|
|
21
|
+
|
|
22
|
+
assert.ok(plain.some((line) => /^┃ You/.test(line)), `expected left-edge user rail header:\n${joined}`);
|
|
23
|
+
assert.ok(plain.some((line) => /^┃ Can we make the transcript feel like chat\?/.test(line)), `expected left-edge user rail body:\n${joined}`);
|
|
24
|
+
assert.ok(raw.some((line) => line.includes("\x1b[48;")), `expected faint user block background:\n${raw.join("\n")}`);
|
|
25
|
+
assert.match(joined, /^┃\s*$/m, "user block should include vertical padding rows");
|
|
26
|
+
assert.match(joined, /feel like chat/);
|
|
27
|
+
assert.doesNotMatch(joined, /[╭╮╰╯]/, "user rail should not use boxed bubble corners");
|
|
28
|
+
assert.doesNotMatch(joined, /^ ┃ You/m, "user rail should not be indented like GSD messages");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("uses a different faint background than GSD messages", () => {
|
|
32
|
+
const user = new UserMessageComponent("Use a distinct user color.");
|
|
33
|
+
const assistant = new AssistantMessageComponent({
|
|
34
|
+
id: "m1",
|
|
35
|
+
role: "assistant",
|
|
36
|
+
provider: "test",
|
|
37
|
+
model: "gpt-test",
|
|
38
|
+
content: [{ type: "text", text: "GSD message." }],
|
|
39
|
+
} as unknown as AssistantMessage);
|
|
40
|
+
|
|
41
|
+
const userBg = user.render(100).join("\n").match(/\x1b\[48;[^m]+m/)?.[0];
|
|
42
|
+
const assistantBg = assistant.render(100).join("\n").match(/\x1b\[48;[^m]+m/)?.[0];
|
|
43
|
+
|
|
44
|
+
assert.ok(userBg, "expected user message background color");
|
|
45
|
+
assert.ok(assistantBg, "expected assistant message background color");
|
|
46
|
+
assert.notEqual(userBg, assistantBg, "user and GSD message backgrounds should be distinct");
|
|
47
|
+
});
|
|
48
|
+
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Runtime tests for adaptive command-center terminal layout rendering.
|
|
2
3
|
|
|
3
4
|
import assert from "node:assert/strict";
|
|
4
5
|
import { describe, it, before } from "node:test";
|
|
@@ -15,7 +16,7 @@ function render(component: AdaptiveLayoutComponent, width: number): string {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
describe("AdaptiveLayoutComponent", () => {
|
|
18
|
-
it("renders workflow command center
|
|
19
|
+
it("renders a rounded workflow command center on wide terminals", () => {
|
|
19
20
|
const component = new AdaptiveLayoutComponent(() => ({
|
|
20
21
|
override: "workflow",
|
|
21
22
|
activeToolCount: 2,
|
|
@@ -26,8 +27,13 @@ describe("AdaptiveLayoutComponent", () => {
|
|
|
26
27
|
|
|
27
28
|
const output = render(component, 132);
|
|
28
29
|
assert.match(output, /GSD Command Center/);
|
|
29
|
-
assert.match(output, /
|
|
30
|
+
assert.match(output, /workflow · ready/);
|
|
30
31
|
assert.match(output, /2 running/);
|
|
32
|
+
assert.match(output, /watch tool output/);
|
|
33
|
+
assert.doesNotMatch(output, /signals/);
|
|
34
|
+
assert.doesNotMatch(output, /inspector/);
|
|
35
|
+
assert.doesNotMatch(output, /\bauto\b/i);
|
|
36
|
+
assert.match(output, /^╭─+╮/m);
|
|
31
37
|
});
|
|
32
38
|
|
|
33
39
|
it("falls back to a single compact row for narrow workflow terminals", () => {
|
|
@@ -41,6 +47,7 @@ describe("AdaptiveLayoutComponent", () => {
|
|
|
41
47
|
const output = render(component, 68);
|
|
42
48
|
assert.match(output, /GSD compact/);
|
|
43
49
|
assert.doesNotMatch(output, /signals/);
|
|
50
|
+
assert.doesNotMatch(output, /\bauto\b/i);
|
|
44
51
|
});
|
|
45
52
|
|
|
46
53
|
it("renders blocking failure context in debug mode", () => {
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Adaptive command-center dashboard for the interactive TUI.
|
|
2
3
|
|
|
3
|
-
import { style, truncateToWidth,
|
|
4
|
+
import { style, truncateToWidth, type Component } from "@gsd/pi-tui";
|
|
4
5
|
import type { TuiAdaptiveMode, TuiMode } from "../tui-mode.js";
|
|
5
6
|
import { resolveTuiMode } from "../tui-mode.js";
|
|
6
7
|
import { theme, type ThemeColor } from "../theme/theme.js";
|
|
8
|
+
import { alignRight, breakpoint, keyValue, roundedPanel } from "./tui-style-kit.js";
|
|
7
9
|
|
|
8
10
|
export interface AdaptiveLayoutState {
|
|
9
11
|
override: TuiAdaptiveMode;
|
|
@@ -41,34 +43,44 @@ export class AdaptiveLayoutComponent implements Component {
|
|
|
41
43
|
}
|
|
42
44
|
|
|
43
45
|
private renderWorkflow(width: number, state: AdaptiveLayoutState): string[] {
|
|
44
|
-
if (width <
|
|
46
|
+
if (width < 72) return this.renderCompact(width, "workflow", state);
|
|
45
47
|
|
|
46
|
-
const leftWidth = Math.max(44, Math.floor(width * 0.56));
|
|
47
|
-
const rightWidth = Math.max(32, width - leftWidth - 2);
|
|
48
48
|
const phase = state.gsdPhase ?? "Ready";
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
[
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
49
|
+
const tools = state.activeToolCount > 0 ? `${state.activeToolCount} running` : "idle";
|
|
50
|
+
const next = state.activeToolCount > 0 ? "watch tool output" : "continue from prompt";
|
|
51
|
+
const modeLabel = state.override === "auto" ? "workflow" : state.override;
|
|
52
|
+
const bp = breakpoint(width);
|
|
53
|
+
|
|
54
|
+
const rows = bp === "regular"
|
|
55
|
+
? [
|
|
56
|
+
keyValue("Status", phase, "modeWorkflow"),
|
|
57
|
+
keyValue("Tools", tools, state.activeToolCount > 0 ? "toolRunning" : "toolMuted"),
|
|
58
|
+
keyValue("Session", state.sessionName ?? "current", "text"),
|
|
59
|
+
keyValue("Next", next, "surfaceAccent"),
|
|
60
|
+
]
|
|
61
|
+
: [
|
|
62
|
+
alignRight(
|
|
63
|
+
keyValue("Status", phase, "modeWorkflow"),
|
|
64
|
+
keyValue("Tools", tools, state.activeToolCount > 0 ? "toolRunning" : "toolMuted"),
|
|
65
|
+
Math.max(1, width - 2),
|
|
66
|
+
),
|
|
67
|
+
alignRight(
|
|
68
|
+
keyValue("Session", state.sessionName ?? "current", "text"),
|
|
69
|
+
keyValue("Path", this.basename(state.cwd), "text"),
|
|
70
|
+
Math.max(1, width - 2),
|
|
71
|
+
),
|
|
72
|
+
alignRight(
|
|
73
|
+
keyValue("Next", next, "surfaceAccent"),
|
|
74
|
+
keyValue("Mode", modeLabel, "modeWorkflow"),
|
|
75
|
+
Math.max(1, width - 2),
|
|
76
|
+
),
|
|
77
|
+
];
|
|
78
|
+
|
|
79
|
+
return roundedPanel(rows, width, {
|
|
80
|
+
title: "GSD Command Center",
|
|
81
|
+
rightTitle: `${modeLabel} · ${state.lastError ? "blocked" : "ready"}`,
|
|
82
|
+
tone: state.lastError ? "error" : "default",
|
|
83
|
+
});
|
|
72
84
|
}
|
|
73
85
|
|
|
74
86
|
private renderValidation(width: number, state: AdaptiveLayoutState): string[] {
|
|
@@ -140,21 +152,10 @@ export class AdaptiveLayoutComponent implements Component {
|
|
|
140
152
|
return `${theme.fg("surfaceMuted", `${label.padEnd(8)} `)}${theme.fg(color, value)}`;
|
|
141
153
|
}
|
|
142
154
|
|
|
143
|
-
private columns(left: string[], right: string[], leftWidth: number): string[] {
|
|
144
|
-
const rows = Math.max(left.length, right.length);
|
|
145
|
-
const output: string[] = [];
|
|
146
|
-
for (let i = 0; i < rows; i++) {
|
|
147
|
-
const leftLine = left[i] ?? "";
|
|
148
|
-
const rightLine = right[i] ?? "";
|
|
149
|
-
const gap = " ".repeat(Math.max(2, leftWidth - visibleWidth(leftLine) + 2));
|
|
150
|
-
output.push(`${leftLine}${gap}${rightLine}`);
|
|
151
|
-
}
|
|
152
|
-
return output;
|
|
153
|
-
}
|
|
154
|
-
|
|
155
155
|
private basename(cwd: string): string {
|
|
156
|
-
const trimmed = cwd.replace(
|
|
157
|
-
|
|
156
|
+
const trimmed = cwd.replace(/[\\/]+$/, "");
|
|
157
|
+
if (!trimmed) return cwd.includes("\\") ? "\\" : "/";
|
|
158
|
+
const slash = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
|
|
158
159
|
return slash === -1 ? trimmed : trimmed.slice(slash + 1);
|
|
159
160
|
}
|
|
160
161
|
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
//
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Assistant message rail renderer for interactive terminal sessions.
|
|
2
3
|
import type { AssistantMessage } from "@gsd/pi-ai";
|
|
3
4
|
import { Container, Markdown, type MarkdownTheme, Spacer, Text } from "@gsd/pi-tui";
|
|
4
5
|
import { getMarkdownTheme, theme } from "../theme/theme.js";
|
|
5
6
|
import { type TimestampFormat } from "./timestamp.js";
|
|
6
|
-
import {
|
|
7
|
+
import { formatTimestamp } from "./timestamp.js";
|
|
8
|
+
import { renderAssistantRail } from "./transcript-design.js";
|
|
7
9
|
|
|
8
10
|
export interface ContentRange {
|
|
9
11
|
startIndex: number;
|
|
@@ -163,19 +165,17 @@ export class AssistantMessageComponent extends Container {
|
|
|
163
165
|
|
|
164
166
|
override render(width: number): string[] {
|
|
165
167
|
const frameWidth = Math.max(20, width);
|
|
166
|
-
const contentWidth = Math.max(1, frameWidth -
|
|
168
|
+
const contentWidth = Math.max(1, frameWidth - 2);
|
|
167
169
|
const lines = super.render(contentWidth);
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
timestamp: this.lastMessage?.timestamp,
|
|
173
|
-
timestampFormat: this.timestampFormat,
|
|
174
|
-
showTimestamp: this.showMetadata,
|
|
175
|
-
});
|
|
176
|
-
if (framed.length === 0) {
|
|
177
|
-
return framed;
|
|
170
|
+
const metaParts = [];
|
|
171
|
+
if (this.lastMessage?.model) metaParts.push(this.lastMessage.model);
|
|
172
|
+
if (this.showMetadata && this.lastMessage?.timestamp != null) {
|
|
173
|
+
metaParts.push(formatTimestamp(this.lastMessage.timestamp, this.timestampFormat));
|
|
178
174
|
}
|
|
179
|
-
|
|
175
|
+
const rendered = renderAssistantRail(lines, frameWidth, {
|
|
176
|
+
label: "GSD",
|
|
177
|
+
meta: metaParts.length > 0 ? `· ${metaParts.join(" · ")}` : undefined,
|
|
178
|
+
});
|
|
179
|
+
return rendered.length > 0 ? ["", ...rendered] : rendered;
|
|
180
180
|
}
|
|
181
181
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*/
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Interactive terminal bash execution renderer with streaming output and recommended command cards.
|
|
4
3
|
|
|
5
4
|
import { Container, Loader, Spacer, Text, type TUI } from "@gsd/pi-tui";
|
|
6
5
|
import stripAnsi from "strip-ansi";
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
import { theme } from "../theme/theme.js";
|
|
14
13
|
import { DynamicBorder } from "./dynamic-border.js";
|
|
15
14
|
import { editorKey, keyHint } from "./keybinding-hints.js";
|
|
15
|
+
import { renderCommandCard, renderTranscriptCard, type StatusTone } from "./transcript-design.js";
|
|
16
16
|
import { truncateToVisualLines } from "./visual-truncate.js";
|
|
17
17
|
|
|
18
18
|
// Preview line limit when not expanded (matches tool execution behavior)
|
|
@@ -120,6 +120,67 @@ export class BashExecutionComponent extends Container {
|
|
|
120
120
|
this.updateDisplay();
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
+
override render(width: number): string[] {
|
|
124
|
+
const frameWidth = Math.max(20, width);
|
|
125
|
+
const elapsedStatus =
|
|
126
|
+
this.status === "running"
|
|
127
|
+
? "running"
|
|
128
|
+
: this.status === "complete"
|
|
129
|
+
? "success"
|
|
130
|
+
: this.status === "cancelled"
|
|
131
|
+
? "cancelled"
|
|
132
|
+
: `failed${this.exitCode !== undefined ? ` · exit ${this.exitCode}` : ""}`;
|
|
133
|
+
const tone: StatusTone =
|
|
134
|
+
this.status === "running"
|
|
135
|
+
? "running"
|
|
136
|
+
: this.status === "complete"
|
|
137
|
+
? "success"
|
|
138
|
+
: this.status === "cancelled"
|
|
139
|
+
? "warning"
|
|
140
|
+
: "error";
|
|
141
|
+
|
|
142
|
+
if (!this.expanded && this.status !== "error") {
|
|
143
|
+
return [
|
|
144
|
+
"",
|
|
145
|
+
...renderCommandCard(this.command.replace(/\s+/g, " ").trim(), frameWidth, {
|
|
146
|
+
status: elapsedStatus,
|
|
147
|
+
tone,
|
|
148
|
+
}),
|
|
149
|
+
];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const output = this.outputLines.join("\n");
|
|
153
|
+
const contextTruncation = truncateTail(output, {
|
|
154
|
+
maxLines: DEFAULT_MAX_LINES,
|
|
155
|
+
maxBytes: DEFAULT_MAX_BYTES,
|
|
156
|
+
});
|
|
157
|
+
const truncationResult = this.truncationResult ?? contextTruncation;
|
|
158
|
+
const fullOutputPath = this.fullOutputPath;
|
|
159
|
+
const availableLines = contextTruncation.content ? contextTruncation.content.split("\n") : [];
|
|
160
|
+
const preview = this.expanded ? availableLines : availableLines.slice(-PREVIEW_LINES);
|
|
161
|
+
const hidden = Math.max(0, availableLines.length - preview.length);
|
|
162
|
+
const truncationWarning =
|
|
163
|
+
(truncationResult.truncated || contextTruncation.truncated) && fullOutputPath
|
|
164
|
+
? [theme.fg("warning", `Output truncated. Full output: ${fullOutputPath}`)]
|
|
165
|
+
: [];
|
|
166
|
+
const body = [
|
|
167
|
+
theme.fg("toolTitle", `$ ${this.command}`),
|
|
168
|
+
...preview.map((line) => theme.fg("toolOutput", line)),
|
|
169
|
+
...(hidden > 0 ? [theme.fg("muted", `... ${hidden} earlier lines`)] : []),
|
|
170
|
+
...truncationWarning,
|
|
171
|
+
];
|
|
172
|
+
return [
|
|
173
|
+
"",
|
|
174
|
+
...renderTranscriptCard(body, frameWidth, {
|
|
175
|
+
title: "command",
|
|
176
|
+
right: elapsedStatus,
|
|
177
|
+
tone,
|
|
178
|
+
footerLeft: this.expanded ? "output expanded" : "output preview",
|
|
179
|
+
footerRight: this.expanded ? "ctrl+o collapse" : "ctrl+o expand",
|
|
180
|
+
}),
|
|
181
|
+
];
|
|
182
|
+
}
|
|
183
|
+
|
|
123
184
|
private updateDisplay(): void {
|
|
124
185
|
// Apply truncation for LLM context limits (same limits as bash tool)
|
|
125
186
|
const fullOutput = this.outputLines.join("\n");
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as Diff from "diff";
|
|
2
|
-
import { theme } from "../theme/theme.js";
|
|
2
|
+
import { getLanguageFromPath, highlightCode, theme } from "../theme/theme.js";
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Parse diff line to extract prefix, line number, and content.
|
|
@@ -66,19 +66,25 @@ function renderIntraLineDiff(oldContent: string, newContent: string): { removedL
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
export interface RenderDiffOptions {
|
|
69
|
-
/** File path
|
|
69
|
+
/** File path used to choose syntax highlighting for changed content. */
|
|
70
70
|
filePath?: string;
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
function syntaxLine(content: string, lang: string | undefined): string {
|
|
74
|
+
if (!lang) return content;
|
|
75
|
+
return highlightCode(content, lang)[0] ?? content;
|
|
76
|
+
}
|
|
77
|
+
|
|
73
78
|
/**
|
|
74
79
|
* Render a diff string with colored lines and intra-line change highlighting.
|
|
75
80
|
* - Context lines: dim/gray
|
|
76
81
|
* - Removed lines: red, with inverse on changed tokens
|
|
77
82
|
* - Added lines: green, with inverse on changed tokens
|
|
78
83
|
*/
|
|
79
|
-
export function renderDiff(diffText: string,
|
|
84
|
+
export function renderDiff(diffText: string, options: RenderDiffOptions = {}): string {
|
|
80
85
|
const lines = diffText.split("\n");
|
|
81
86
|
const result: string[] = [];
|
|
87
|
+
const lang = options.filePath ? getLanguageFromPath(options.filePath) : undefined;
|
|
82
88
|
|
|
83
89
|
let i = 0;
|
|
84
90
|
while (i < lines.length) {
|
|
@@ -126,19 +132,19 @@ export function renderDiff(diffText: string, _options: RenderDiffOptions = {}):
|
|
|
126
132
|
} else {
|
|
127
133
|
// Show all removed lines first, then all added lines
|
|
128
134
|
for (const removed of removedLines) {
|
|
129
|
-
result.push(theme.fg("toolDiffRemoved", `-${removed.lineNum} ${replaceTabs(removed.content)}`)
|
|
135
|
+
result.push(`${theme.fg("toolDiffRemoved", `-${removed.lineNum} `)}${syntaxLine(replaceTabs(removed.content), lang)}`);
|
|
130
136
|
}
|
|
131
137
|
for (const added of addedLines) {
|
|
132
|
-
result.push(theme.fg("toolDiffAdded", `+${added.lineNum} ${replaceTabs(added.content)}`)
|
|
138
|
+
result.push(`${theme.fg("toolDiffAdded", `+${added.lineNum} `)}${syntaxLine(replaceTabs(added.content), lang)}`);
|
|
133
139
|
}
|
|
134
140
|
}
|
|
135
141
|
} else if (parsed.prefix === "+") {
|
|
136
142
|
// Standalone added line
|
|
137
|
-
result.push(theme.fg("toolDiffAdded", `+${parsed.lineNum} ${replaceTabs(parsed.content)}`)
|
|
143
|
+
result.push(`${theme.fg("toolDiffAdded", `+${parsed.lineNum} `)}${syntaxLine(replaceTabs(parsed.content), lang)}`);
|
|
138
144
|
i++;
|
|
139
145
|
} else {
|
|
140
146
|
// Context line
|
|
141
|
-
result.push(theme.fg("toolDiffContext", ` ${parsed.lineNum} ${replaceTabs(parsed.content)}`)
|
|
147
|
+
result.push(`${theme.fg("toolDiffContext", ` ${parsed.lineNum} `)}${syntaxLine(replaceTabs(parsed.content), lang)}`);
|
|
142
148
|
i++;
|
|
143
149
|
}
|
|
144
150
|
}
|