gsd-pi 2.81.0 → 2.82.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -24
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/gsd/auto/loop.js +111 -8
- package/dist/resources/extensions/gsd/auto/phases.js +190 -97
- package/dist/resources/extensions/gsd/auto/run-unit.js +66 -3
- package/dist/resources/extensions/gsd/auto/session.js +9 -0
- package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +182 -178
- package/dist/resources/extensions/gsd/auto-dispatch.js +14 -11
- package/dist/resources/extensions/gsd/auto-post-unit.js +7 -1
- package/dist/resources/extensions/gsd/auto-recovery.js +6 -181
- package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
- package/dist/resources/extensions/gsd/auto-start.js +20 -23
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
- package/dist/resources/extensions/gsd/auto-verification.js +12 -6
- package/dist/resources/extensions/gsd/auto-worktree.js +8 -0
- package/dist/resources/extensions/gsd/auto.js +265 -76
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +13 -6
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +8 -2
- package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
- package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
- package/dist/resources/extensions/gsd/commands/handlers/parallel.js +9 -0
- package/dist/resources/extensions/gsd/git-service.js +2 -1
- package/dist/resources/extensions/gsd/gsd-db.js +7 -23
- package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
- package/dist/resources/extensions/gsd/health-widget.js +4 -10
- package/dist/resources/extensions/gsd/markdown-renderer.js +0 -95
- package/dist/resources/extensions/gsd/native-git-bridge.js +14 -14
- package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
- package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +14 -12
- package/dist/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
- package/dist/resources/extensions/gsd/prompts/discuss.md +20 -2
- package/dist/resources/extensions/gsd/recovery-classification.js +15 -1
- package/dist/resources/extensions/gsd/session-lock.js +40 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +131 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/merge-state.js +247 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/project-md.js +50 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/roadmap.js +87 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.js +50 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-render.js +124 -0
- package/dist/resources/extensions/gsd/state-reconciliation/drift/stale-worker.js +32 -0
- package/dist/resources/extensions/gsd/state-reconciliation/errors.js +41 -0
- package/dist/resources/extensions/gsd/state-reconciliation/index.js +99 -0
- package/dist/resources/extensions/gsd/state-reconciliation/registry.js +24 -0
- package/dist/resources/extensions/gsd/state-reconciliation/spawn-gate.js +43 -0
- package/dist/resources/extensions/gsd/state-reconciliation/types.js +3 -0
- package/dist/resources/extensions/gsd/state-reconciliation.js +5 -26
- package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
- package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
- package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
- package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +722 -316
- package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/welcome-screen.d.ts +0 -7
- package/dist/welcome-screen.js +60 -69
- package/package.json +1 -1
- package/packages/daemon/package.json +2 -2
- package/packages/mcp-server/package.json +2 -2
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +76 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +30 -29
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +10 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
- package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +0 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +86 -82
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +105 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +27 -26
- package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +9 -6
- package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +113 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +10 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +43 -42
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -14
- package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +84 -104
- package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
- package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +106 -1
- package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +27 -26
- package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +9 -6
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
- package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
- package/packages/pi-tui/dist/overlay-layout.js +9 -6
- package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
- package/packages/pi-tui/package.json +1 -1
- package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
- package/packages/pi-tui/src/overlay-layout.ts +10 -7
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/packages/rpc-client/package.json +1 -1
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
- package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
- package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/theme.js +105 -1
- package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
- package/pkg/dist/modes/interactive/theme/themes.js +27 -26
- package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/auto/loop-deps.ts +9 -5
- package/src/resources/extensions/gsd/auto/loop.ts +113 -9
- package/src/resources/extensions/gsd/auto/phases.ts +144 -19
- package/src/resources/extensions/gsd/auto/run-unit.ts +69 -4
- package/src/resources/extensions/gsd/auto/session.ts +10 -0
- package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +230 -183
- package/src/resources/extensions/gsd/auto-dispatch.ts +15 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +7 -1
- package/src/resources/extensions/gsd/auto-recovery.ts +7 -209
- package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
- package/src/resources/extensions/gsd/auto-start.ts +22 -22
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
- package/src/resources/extensions/gsd/auto-verification.ts +12 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +8 -0
- package/src/resources/extensions/gsd/auto.ts +295 -75
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +21 -6
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +6 -2
- package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
- package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
- package/src/resources/extensions/gsd/commands/handlers/parallel.ts +12 -0
- package/src/resources/extensions/gsd/git-service.ts +2 -0
- package/src/resources/extensions/gsd/gsd-db.ts +7 -23
- package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
- package/src/resources/extensions/gsd/health-widget.ts +6 -10
- package/src/resources/extensions/gsd/journal.ts +2 -0
- package/src/resources/extensions/gsd/markdown-renderer.ts +4 -95
- package/src/resources/extensions/gsd/native-git-bridge.ts +14 -13
- package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
- package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
- package/src/resources/extensions/gsd/prompts/complete-slice.md +14 -12
- package/src/resources/extensions/gsd/prompts/discuss-headless.md +20 -2
- package/src/resources/extensions/gsd/prompts/discuss.md +20 -2
- package/src/resources/extensions/gsd/recovery-classification.ts +18 -1
- package/src/resources/extensions/gsd/session-lock.ts +41 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +172 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/merge-state.ts +337 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/project-md.ts +69 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/roadmap.ts +109 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/sketch-flag.ts +68 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-render.ts +185 -0
- package/src/resources/extensions/gsd/state-reconciliation/drift/stale-worker.ts +46 -0
- package/src/resources/extensions/gsd/state-reconciliation/errors.ts +67 -0
- package/src/resources/extensions/gsd/state-reconciliation/index.ts +142 -0
- package/src/resources/extensions/gsd/state-reconciliation/registry.ts +27 -0
- package/src/resources/extensions/gsd/state-reconciliation/spawn-gate.ts +60 -0
- package/src/resources/extensions/gsd/state-reconciliation/types.ts +83 -0
- package/src/resources/extensions/gsd/state-reconciliation.ts +21 -53
- package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +99 -0
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +654 -176
- package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +291 -4
- package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +18 -0
- package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +28 -1
- package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +20 -2
- package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +26 -0
- package/src/resources/extensions/gsd/tests/integration/integration-proof.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -1
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +46 -11
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
- package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -217
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
- package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/progressive-planning.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +7 -3
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -58
- package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +952 -0
- package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +121 -1
- package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +158 -58
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +572 -118
- package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
- package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
- package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
- package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
- package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
- package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +1151 -524
- package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
- package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1544
- /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → S44UQTFCUdA44dkjfYt6S}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{drLMkgfHQ8lzS229_HWYR → S44UQTFCUdA44dkjfYt6S}/_ssgManifest.js +0 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Registers GSD keyboard shortcuts for dashboard, notifications, and parallel overlays.
|
|
1
3
|
import { existsSync } from "node:fs";
|
|
2
4
|
import { join } from "node:path";
|
|
3
5
|
import { Key } from "@gsd/pi-tui";
|
|
@@ -29,16 +31,10 @@ export function registerShortcuts(pi) {
|
|
|
29
31
|
});
|
|
30
32
|
};
|
|
31
33
|
const openNotificationsOverlay = async (ctx) => {
|
|
32
|
-
const { GSDNotificationOverlay } = await import("../notification-overlay.js");
|
|
34
|
+
const { GSDNotificationOverlay, notificationOverlayOptions } = await import("../notification-overlay.js");
|
|
33
35
|
await ctx.ui.custom((tui, theme, _kb, done) => new GSDNotificationOverlay(tui, theme, () => done(true)), {
|
|
34
36
|
overlay: true,
|
|
35
|
-
overlayOptions:
|
|
36
|
-
width: "80%",
|
|
37
|
-
minWidth: 60,
|
|
38
|
-
maxHeight: "88%",
|
|
39
|
-
anchor: "center",
|
|
40
|
-
backdrop: true,
|
|
41
|
-
},
|
|
37
|
+
overlayOptions: notificationOverlayOptions(),
|
|
42
38
|
});
|
|
43
39
|
};
|
|
44
40
|
const openParallelOverlay = async (ctx) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Handles /gsd notifications commands and opens the notification history overlay.
|
|
3
3
|
import { readNotifications, clearNotifications, getUnreadCount, suppressPersistence, unsuppressPersistence, } from "../../notification-store.js";
|
|
4
|
-
import { GSDNotificationOverlay } from "../../notification-overlay.js";
|
|
4
|
+
import { GSDNotificationOverlay, notificationOverlayOptions } from "../../notification-overlay.js";
|
|
5
5
|
const MAX_INLINE_ENTRIES = 40;
|
|
6
6
|
function severityIcon(severity) {
|
|
7
7
|
switch (severity) {
|
|
@@ -79,13 +79,7 @@ export async function handleNotificationsCommand(args, ctx, pi) {
|
|
|
79
79
|
try {
|
|
80
80
|
const result = await ctx.ui.custom((tui, theme, _kb, done) => new GSDNotificationOverlay(tui, theme, () => done(true)), {
|
|
81
81
|
overlay: true,
|
|
82
|
-
overlayOptions:
|
|
83
|
-
width: "80%",
|
|
84
|
-
minWidth: 60,
|
|
85
|
-
maxHeight: "88%",
|
|
86
|
-
anchor: "center",
|
|
87
|
-
backdrop: true,
|
|
88
|
-
},
|
|
82
|
+
overlayOptions: notificationOverlayOptions(),
|
|
89
83
|
});
|
|
90
84
|
if (result !== undefined) {
|
|
91
85
|
return true;
|
|
@@ -2,6 +2,7 @@ import { getOrchestratorState, getWorkerStatuses, isParallelActive, pauseWorker,
|
|
|
2
2
|
import { formatEligibilityReport } from "../../parallel-eligibility.js";
|
|
3
3
|
import { formatMergeResults, mergeAllCompleted, mergeCompletedMilestone } from "../../parallel-merge.js";
|
|
4
4
|
import { loadEffectiveGSDPreferences, resolveParallelConfig } from "../../preferences.js";
|
|
5
|
+
import { reconcileBeforeSpawn } from "../../state-reconciliation.js";
|
|
5
6
|
import { projectRoot } from "../context.js";
|
|
6
7
|
function emitParallelMessage(pi, content) {
|
|
7
8
|
pi.sendMessage({ customType: "gsd-parallel", content, display: true });
|
|
@@ -26,6 +27,14 @@ export async function handleParallelCommand(trimmed, _ctx, pi) {
|
|
|
26
27
|
emitParallelMessage(pi, `${report}\n\nNo milestones are eligible for parallel execution.`);
|
|
27
28
|
return true;
|
|
28
29
|
}
|
|
30
|
+
// ADR-017 #5707: reconcile before spawning so workers don't independently
|
|
31
|
+
// race on the same drift. Failures abort the spawn with an actionable
|
|
32
|
+
// user-visible message.
|
|
33
|
+
const gate = await reconcileBeforeSpawn(root);
|
|
34
|
+
if (!gate.ok) {
|
|
35
|
+
emitParallelMessage(pi, `${report}\n\nParallel orchestration aborted before spawn — ${gate.reason}`);
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
29
38
|
const result = await startParallel(root, candidates.eligible.map((candidate) => candidate.milestoneId), loaded?.preferences);
|
|
30
39
|
const lines = ["Parallel orchestration started.", `Workers: ${result.started.join(", ")}`];
|
|
31
40
|
if (result.errors.length > 0) {
|
|
@@ -18,7 +18,7 @@ import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
|
18
18
|
import { logWarning } from "./workflow-logger.js";
|
|
19
19
|
import { detectWorktreeName, } from "./worktree.js";
|
|
20
20
|
import { SLICE_BRANCH_RE, QUICK_BRANCH_RE, WORKFLOW_BRANCH_RE } from "./branch-patterns.js";
|
|
21
|
-
import { nativeGetCurrentBranch, nativeDetectMainBranch, nativeBranchExists, nativeHasChanges, nativeAddAllWithExclusions, nativeHasStagedChanges, nativeCommit, nativeRmCached, nativeUpdateRef, nativeAddPaths, nativeResetSoft, nativeCommitSubject, _resetHasChangesCache, } from "./native-git-bridge.js";
|
|
21
|
+
import { nativeGetCurrentBranch, nativeDetectMainBranch, nativeBranchExists, nativeHasChanges, nativeAddAllWithExclusions, nativeHasStagedChanges, nativeCommit, nativeRmCached, nativeUpdateRef, nativeAddPaths, nativeResetSoft, nativeCommitSubject, nativeIsIgnored, _resetHasChangesCache, } from "./native-git-bridge.js";
|
|
22
22
|
import { GSDError, GSD_MERGE_CONFLICT, GSD_GIT_ERROR } from "./errors.js";
|
|
23
23
|
import { getErrorMessage } from "./error-utils.js";
|
|
24
24
|
import { isInfrastructureError } from "./auto/infra-errors.js";
|
|
@@ -570,6 +570,7 @@ export class GitServiceImpl {
|
|
|
570
570
|
const normalized = keyFiles
|
|
571
571
|
.map(file => normalizeRepoRelativePath(this.basePath, file))
|
|
572
572
|
.filter((file) => file !== null)
|
|
573
|
+
.filter(file => !nativeIsIgnored(this.basePath, file))
|
|
573
574
|
.filter(file => !isExcludedScopedPath(file, allExclusions));
|
|
574
575
|
// Drop entries that don't exist on disk. The LLM occasionally lists files
|
|
575
576
|
// it intended to write but didn't (or names them with wrong casing/path).
|
|
@@ -977,32 +977,16 @@ export function setSliceSketchFlag(milestoneId, sliceId, isSketch) {
|
|
|
977
977
|
currentDb.prepare(`UPDATE slices SET is_sketch = :is_sketch WHERE milestone_id = :mid AND id = :sid`).run({ ":is_sketch": isSketch ? 1 : 0, ":mid": milestoneId, ":sid": sliceId });
|
|
978
978
|
}
|
|
979
979
|
/**
|
|
980
|
-
* ADR-
|
|
981
|
-
*
|
|
982
|
-
*
|
|
983
|
-
*
|
|
984
|
-
* to keep path logic in one place — do not hand-roll the path inside the callback.
|
|
985
|
-
*
|
|
986
|
-
* Recovers from two scenarios:
|
|
987
|
-
* 1. Crash between `gsd_plan_slice` write and the sketch flag flip.
|
|
988
|
-
* 2. Flag-OFF downgrade path: when `progressive_planning` is off, the dispatch
|
|
989
|
-
* rule routes sketch slices to plan-slice, which writes PLAN.md but leaves
|
|
990
|
-
* `is_sketch=1` — the next state derivation auto-heals it to 0 here.
|
|
991
|
-
*
|
|
992
|
-
* Not aggressive in practice: PLAN.md is only written via the DB-backed
|
|
993
|
-
* `gsd_plan_slice` tool (which also inserts tasks), so a "stale PLAN.md with
|
|
994
|
-
* is_sketch=1" is extremely unlikely to indicate anything other than the two
|
|
995
|
-
* recovery scenarios above.
|
|
980
|
+
* ADR-017 raw primitive: returns slice IDs in a milestone whose is_sketch flag
|
|
981
|
+
* is still 1. The stale-sketch-flag drift handler at
|
|
982
|
+
* `state-reconciliation/drift/sketch-flag.ts` composes this with PLAN.md
|
|
983
|
+
* existence checks to detect drift, then writes via `setSliceSketchFlag`.
|
|
996
984
|
*/
|
|
997
|
-
export function
|
|
985
|
+
export function getSketchedSliceIds(milestoneId) {
|
|
998
986
|
if (!currentDb)
|
|
999
|
-
return;
|
|
987
|
+
return [];
|
|
1000
988
|
const rows = currentDb.prepare(`SELECT id FROM slices WHERE milestone_id = :mid AND is_sketch = 1`).all({ ":mid": milestoneId });
|
|
1001
|
-
|
|
1002
|
-
if (hasPlanFile(row.id)) {
|
|
1003
|
-
setSliceSketchFlag(milestoneId, row.id, false);
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
989
|
+
return rows.map((r) => r.id);
|
|
1006
990
|
}
|
|
1007
991
|
export function upsertSlicePlanning(milestoneId, sliceId, planning) {
|
|
1008
992
|
if (!currentDb)
|
|
@@ -51,7 +51,7 @@ export function buildHealthLines(data, width) {
|
|
|
51
51
|
return [" GSD No project loaded — run /gsd to start"];
|
|
52
52
|
}
|
|
53
53
|
if (data.projectState === "initialized") {
|
|
54
|
-
return [" GSD Project
|
|
54
|
+
return [" GSD Project Initialized"];
|
|
55
55
|
}
|
|
56
56
|
const leftParts = [];
|
|
57
57
|
const totalIssues = data.environmentErrorCount + data.environmentWarningCount + (data.providerIssue ? 1 : 0);
|
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* Shows a compact 1-2 line summary: progress score, budget, provider key
|
|
5
|
-
* status, and doctor/environment issue count. Refreshes every 60 seconds.
|
|
6
|
-
* Quiet when everything is healthy; turns amber/red when issues arise.
|
|
7
|
-
*
|
|
8
|
-
* Widget key: "gsd-health", placement: "belowEditor"
|
|
9
|
-
*/
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Always-on ambient health signal rendered below the editor.
|
|
10
3
|
import { runProviderChecks, summariseProviderIssues } from "./doctor-providers.js";
|
|
11
4
|
import { runEnvironmentChecks } from "./doctor-environment.js";
|
|
12
5
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
@@ -14,6 +7,7 @@ import { nativeIsRepo, nativeLastCommitEpoch, nativeGetCurrentBranch, nativeComm
|
|
|
14
7
|
import { loadLedgerFromDisk, getProjectTotals } from "./metrics.js";
|
|
15
8
|
import { projectRoot } from "./commands/context.js";
|
|
16
9
|
import { buildHealthLines, detectHealthWidgetProjectState, } from "./health-widget-core.js";
|
|
10
|
+
export const HEALTH_WIDGET_ACTIVE_HINTS = " /gsd auto to run · /gsd status for overview · /gsd visualize to inspect · /gsd notifications for history · /gsd help";
|
|
17
11
|
// ── Data loader ────────────────────────────────────────────────────────────────
|
|
18
12
|
function loadHealthWidgetData(basePath) {
|
|
19
13
|
let budgetCeiling;
|
|
@@ -119,7 +113,7 @@ export function initHealthWidget(ctx) {
|
|
|
119
113
|
if (!cachedLines || cachedWidth !== width) {
|
|
120
114
|
cachedLines = buildHealthLines(data, width);
|
|
121
115
|
if (data.projectState === "active") {
|
|
122
|
-
cachedLines = [...cachedLines, _theme.fg("dim",
|
|
116
|
+
cachedLines = [...cachedLines, _theme.fg("dim", HEALTH_WIDGET_ACTIVE_HINTS)];
|
|
123
117
|
}
|
|
124
118
|
cachedWidth = width;
|
|
125
119
|
}
|
|
@@ -734,101 +734,6 @@ export function detectStaleRenders(basePath) {
|
|
|
734
734
|
}
|
|
735
735
|
return stale;
|
|
736
736
|
}
|
|
737
|
-
// ─── Stale Repair ─────────────────────────────────────────────────────────
|
|
738
|
-
/**
|
|
739
|
-
* Repair all stale renders detected by `detectStaleRenders()`.
|
|
740
|
-
*
|
|
741
|
-
* For each stale entry, calls the appropriate render function:
|
|
742
|
-
* - Roadmap checkbox mismatches → renderRoadmapCheckboxes()
|
|
743
|
-
* - Plan checkbox mismatches → renderPlanCheckboxes()
|
|
744
|
-
* - Missing task summaries → renderTaskSummary()
|
|
745
|
-
* - Missing slice summaries/UATs → renderSliceSummary()
|
|
746
|
-
*
|
|
747
|
-
* Idempotent: calling twice with no DB changes produces zero repairs on the second call.
|
|
748
|
-
*
|
|
749
|
-
* @returns the number of files repaired
|
|
750
|
-
*/
|
|
751
|
-
export async function repairStaleRenders(basePath) {
|
|
752
|
-
const staleEntries = detectStaleRenders(basePath);
|
|
753
|
-
if (staleEntries.length === 0)
|
|
754
|
-
return 0;
|
|
755
|
-
// Deduplicate: a single roadmap/plan file might appear multiple times
|
|
756
|
-
// (once per mismatched checkbox). We only need to re-render it once.
|
|
757
|
-
const repairedPaths = new Set();
|
|
758
|
-
let repairCount = 0;
|
|
759
|
-
for (const entry of staleEntries) {
|
|
760
|
-
if (repairedPaths.has(entry.path))
|
|
761
|
-
continue;
|
|
762
|
-
// Normalize path separators for cross-platform regex matching
|
|
763
|
-
const normPath = entry.path.replace(/\\/g, "/");
|
|
764
|
-
try {
|
|
765
|
-
// Determine repair action from the reason
|
|
766
|
-
if (entry.reason.includes("in roadmap")) {
|
|
767
|
-
// Roadmap checkbox mismatch — extract milestone ID from path
|
|
768
|
-
const milestoneMatch = normPath.match(/milestones\/([^/]+)\//);
|
|
769
|
-
if (milestoneMatch) {
|
|
770
|
-
const ok = await renderRoadmapCheckboxes(basePath, milestoneMatch[1]);
|
|
771
|
-
if (ok) {
|
|
772
|
-
repairedPaths.add(entry.path);
|
|
773
|
-
repairCount++;
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
}
|
|
777
|
-
else if (entry.reason.includes("in plan")) {
|
|
778
|
-
// Plan checkbox mismatch — extract milestone + slice IDs from path
|
|
779
|
-
const pathMatch = normPath.match(/milestones\/([^/]+)\/slices\/([^/]+)\//);
|
|
780
|
-
if (pathMatch) {
|
|
781
|
-
const ok = await renderPlanCheckboxes(basePath, pathMatch[1], pathMatch[2]);
|
|
782
|
-
if (ok) {
|
|
783
|
-
repairedPaths.add(entry.path);
|
|
784
|
-
repairCount++;
|
|
785
|
-
}
|
|
786
|
-
}
|
|
787
|
-
}
|
|
788
|
-
else if (entry.reason.includes("SUMMARY.md missing") && entry.reason.match(/^T\d+/)) {
|
|
789
|
-
// Missing task summary — extract IDs from path
|
|
790
|
-
const pathMatch = normPath.match(/milestones\/([^/]+)\/slices\/([^/]+)\/tasks\//);
|
|
791
|
-
const taskMatch = entry.reason.match(/^(T\d+)/);
|
|
792
|
-
if (pathMatch && taskMatch) {
|
|
793
|
-
const ok = await renderTaskSummary(basePath, pathMatch[1], pathMatch[2], taskMatch[1]);
|
|
794
|
-
if (ok) {
|
|
795
|
-
repairedPaths.add(entry.path);
|
|
796
|
-
repairCount++;
|
|
797
|
-
}
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
else if (entry.reason.includes("SUMMARY.md missing") && entry.reason.match(/^S\d+/)) {
|
|
801
|
-
// Missing slice summary — extract IDs from path
|
|
802
|
-
const pathMatch = normPath.match(/milestones\/([^/]+)\/slices\/([^/]+)\//);
|
|
803
|
-
if (pathMatch) {
|
|
804
|
-
const ok = await renderSliceSummary(basePath, pathMatch[1], pathMatch[2]);
|
|
805
|
-
if (ok) {
|
|
806
|
-
repairedPaths.add(entry.path);
|
|
807
|
-
repairCount++;
|
|
808
|
-
}
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
else if (entry.reason.includes("UAT.md missing")) {
|
|
812
|
-
// Missing slice UAT — renderSliceSummary handles both SUMMARY + UAT
|
|
813
|
-
const pathMatch = normPath.match(/milestones\/([^/]+)\/slices\/([^/]+)\//);
|
|
814
|
-
if (pathMatch) {
|
|
815
|
-
const ok = await renderSliceSummary(basePath, pathMatch[1], pathMatch[2]);
|
|
816
|
-
if (ok) {
|
|
817
|
-
repairedPaths.add(entry.path);
|
|
818
|
-
repairCount++;
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
catch (err) {
|
|
824
|
-
logWarning("renderer", `repair failed for ${entry.path}: ${err.message}`);
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
if (repairCount > 0) {
|
|
828
|
-
process.stderr.write(`markdown-renderer: repaired ${repairCount} stale render(s)\n`);
|
|
829
|
-
}
|
|
830
|
-
return repairCount;
|
|
831
|
-
}
|
|
832
737
|
export async function renderReplanFromDb(basePath, milestoneId, sliceId, replanData) {
|
|
833
738
|
const slicePath = resolveSlicePath(basePath, milestoneId, sliceId)
|
|
834
739
|
?? join(gsdRoot(basePath), "milestones", milestoneId, "slices", sliceId);
|
|
@@ -551,21 +551,21 @@ export function nativeAddAll(basePath) {
|
|
|
551
551
|
export function nativeAddTracked(basePath) {
|
|
552
552
|
gitFileExec(basePath, ["add", "-u"]);
|
|
553
553
|
}
|
|
554
|
-
function
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
// exit 1 means this form is not ignored; try the next variant
|
|
566
|
-
}
|
|
554
|
+
export function nativeIsIgnored(basePath, path) {
|
|
555
|
+
try {
|
|
556
|
+
execFileSync("git", ["check-ignore", "-q", "--", path], {
|
|
557
|
+
cwd: basePath,
|
|
558
|
+
stdio: "pipe",
|
|
559
|
+
env: GIT_NO_PROMPT_ENV,
|
|
560
|
+
});
|
|
561
|
+
return true;
|
|
562
|
+
}
|
|
563
|
+
catch {
|
|
564
|
+
return false;
|
|
567
565
|
}
|
|
568
|
-
|
|
566
|
+
}
|
|
567
|
+
function isDotGsdIgnored(basePath) {
|
|
568
|
+
return [".gsd", ".gsd/"].some(path => nativeIsIgnored(basePath, path));
|
|
569
569
|
}
|
|
570
570
|
/**
|
|
571
571
|
* Determine whether the project opts out of GSD-managed `.gitignore` via
|
|
@@ -1,11 +1,25 @@
|
|
|
1
|
-
// GSD
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
import { truncateToWidth, visibleWidth, wrapTextWithAnsi, matchesKey, Key } from "@gsd/pi-tui";
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Notification history overlay with severity filtering and width-safe TUI rendering.
|
|
3
|
+
import { truncateToWidth, visibleWidth, matchesKey, Key } from "@gsd/pi-tui";
|
|
5
4
|
import { readNotifications, markAllRead, clearNotifications, onNotificationStoreChange, } from "./notification-store.js";
|
|
6
5
|
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
7
|
-
import {
|
|
8
|
-
const FILTER_CYCLE = ["all", "error", "warning", "info"];
|
|
6
|
+
import { padRightVisible, renderFrame, renderKeyHints, rightAlign, wrapVisibleText, } from "./tui/render-kit.js";
|
|
7
|
+
const FILTER_CYCLE = ["all", "error", "warning", "success", "info"];
|
|
8
|
+
const OVERLAY_WIDTH = "58%";
|
|
9
|
+
const OVERLAY_MIN_WIDTH = 68;
|
|
10
|
+
const OVERLAY_MAX_HEIGHT_PERCENT = 52;
|
|
11
|
+
const OVERLAY_MARGIN = { top: 2, right: 2, bottom: 6, left: 2 };
|
|
12
|
+
export function notificationOverlayOptions() {
|
|
13
|
+
return {
|
|
14
|
+
width: OVERLAY_WIDTH,
|
|
15
|
+
minWidth: OVERLAY_MIN_WIDTH,
|
|
16
|
+
maxHeight: `${OVERLAY_MAX_HEIGHT_PERCENT}%`,
|
|
17
|
+
anchor: "top-center",
|
|
18
|
+
row: "24%",
|
|
19
|
+
margin: OVERLAY_MARGIN,
|
|
20
|
+
backdrop: true,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
9
23
|
function severityIcon(severity) {
|
|
10
24
|
switch (severity) {
|
|
11
25
|
case "error": return "✗";
|
|
@@ -15,15 +29,6 @@ function severityIcon(severity) {
|
|
|
15
29
|
default: return "●";
|
|
16
30
|
}
|
|
17
31
|
}
|
|
18
|
-
/** Column-aware word wrap using pi-tui's native wrapper (handles unicode/ANSI). */
|
|
19
|
-
function wrapText(text, maxWidth) {
|
|
20
|
-
if (maxWidth <= 0)
|
|
21
|
-
return [text];
|
|
22
|
-
const lines = wrapTextWithAnsi(text, maxWidth);
|
|
23
|
-
// Safety clamp: if any line still exceeds maxWidth (e.g. unbreakable long token),
|
|
24
|
-
// truncate it with an ellipsis so it cannot bleed past the box border.
|
|
25
|
-
return lines.map((l) => visibleWidth(l) > maxWidth ? truncateToWidth(l, maxWidth, "…") : l);
|
|
26
|
-
}
|
|
27
32
|
function formatTimestamp(ts) {
|
|
28
33
|
try {
|
|
29
34
|
const d = new Date(ts);
|
|
@@ -155,12 +160,15 @@ export class GSDNotificationOverlay {
|
|
|
155
160
|
return this.cachedLines;
|
|
156
161
|
}
|
|
157
162
|
const content = this.buildContentLines(width);
|
|
158
|
-
const
|
|
163
|
+
const terminalRows = process.stdout.rows || 32;
|
|
164
|
+
const availableRows = Math.max(1, terminalRows - OVERLAY_MARGIN.top - OVERLAY_MARGIN.bottom);
|
|
165
|
+
const overlayRows = Math.min(availableRows, Math.max(1, Math.floor((terminalRows * OVERLAY_MAX_HEIGHT_PERCENT) / 100)));
|
|
166
|
+
const maxVisibleRows = Math.max(5, overlayRows - 2);
|
|
159
167
|
const visibleContentRows = Math.min(content.length, maxVisibleRows);
|
|
160
168
|
const maxScroll = Math.max(0, content.length - visibleContentRows);
|
|
161
169
|
this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
|
|
162
170
|
const visibleContent = content.slice(this.scrollOffset, this.scrollOffset + visibleContentRows);
|
|
163
|
-
const lines = this.
|
|
171
|
+
const lines = renderFrame(this.theme, visibleContent, width);
|
|
164
172
|
this.cachedWidth = width;
|
|
165
173
|
this.cachedLines = lines;
|
|
166
174
|
return lines;
|
|
@@ -192,30 +200,14 @@ export class GSDNotificationOverlay {
|
|
|
192
200
|
this.tui.requestRender();
|
|
193
201
|
}
|
|
194
202
|
}
|
|
195
|
-
wrapInBox(inner, width) {
|
|
196
|
-
const th = this.theme;
|
|
197
|
-
const border = (s) => th.fg("borderAccent", s);
|
|
198
|
-
const innerWidth = width - 4;
|
|
199
|
-
const lines = [];
|
|
200
|
-
lines.push(border("╭" + "─".repeat(width - 2) + "╮"));
|
|
201
|
-
for (const line of inner) {
|
|
202
|
-
const truncated = truncateToWidth(line, innerWidth);
|
|
203
|
-
const padWidth = Math.max(0, innerWidth - visibleWidth(truncated));
|
|
204
|
-
lines.push(border("│") + " " + truncated + " ".repeat(padWidth) + " " + border("│"));
|
|
205
|
-
}
|
|
206
|
-
lines.push(border("╰" + "─".repeat(width - 2) + "╯"));
|
|
207
|
-
return lines;
|
|
208
|
-
}
|
|
209
203
|
buildContentLines(width) {
|
|
210
204
|
const th = this.theme;
|
|
211
|
-
const shellWidth = width - 4;
|
|
212
|
-
const contentWidth =
|
|
213
|
-
const sidePad = Math.max(0, Math.floor((shellWidth - contentWidth) / 2));
|
|
214
|
-
const leftMargin = " ".repeat(sidePad);
|
|
205
|
+
const shellWidth = Math.max(1, width - 4);
|
|
206
|
+
const contentWidth = shellWidth;
|
|
215
207
|
const lines = [];
|
|
216
208
|
const row = (content = "") => {
|
|
217
209
|
const truncated = truncateToWidth(content, contentWidth);
|
|
218
|
-
return
|
|
210
|
+
return padRightVisible(truncated, contentWidth);
|
|
219
211
|
};
|
|
220
212
|
const blank = () => row("");
|
|
221
213
|
const hr = () => row(th.fg("dim", "─".repeat(contentWidth)));
|
|
@@ -223,13 +215,16 @@ export class GSDNotificationOverlay {
|
|
|
223
215
|
const title = th.fg("accent", th.bold("Notifications"));
|
|
224
216
|
const filterLabel = this.filter === "all"
|
|
225
217
|
? th.fg("dim", "all")
|
|
226
|
-
: th.fg(this.filter === "error" ? "error"
|
|
218
|
+
: th.fg(this.filter === "error" ? "error"
|
|
219
|
+
: this.filter === "warning" ? "warning"
|
|
220
|
+
: this.filter === "success" ? "success"
|
|
221
|
+
: "dim", this.filter);
|
|
227
222
|
const count = `${this.filteredEntries.length} entries`;
|
|
228
|
-
lines.push(row(
|
|
223
|
+
lines.push(row(rightAlign(`${title} ${th.fg("dim", "filter:")} ${filterLabel}`, th.fg("dim", count), contentWidth)));
|
|
229
224
|
lines.push(hr());
|
|
230
225
|
// Controls
|
|
231
226
|
const closeShortcut = formattedShortcutPair("notifications");
|
|
232
|
-
lines.push(row(th
|
|
227
|
+
lines.push(row(renderKeyHints(th, ["↑/↓ scroll", "f filter", "c clear", `Esc/${closeShortcut} close`], contentWidth)));
|
|
233
228
|
lines.push(blank());
|
|
234
229
|
// Entries
|
|
235
230
|
const filtered = this.filteredEntries;
|
|
@@ -254,7 +249,7 @@ export class GSDNotificationOverlay {
|
|
|
254
249
|
const prefixWidth = visibleWidth(prefix);
|
|
255
250
|
const msgMaxWidth = Math.max(10, contentWidth - prefixWidth);
|
|
256
251
|
// Wrap long messages onto continuation lines indented to align with message start
|
|
257
|
-
const msgLines =
|
|
252
|
+
const msgLines = wrapVisibleText(entry.message, msgMaxWidth);
|
|
258
253
|
const indent = " ".repeat(prefixWidth);
|
|
259
254
|
for (let i = 0; i < msgLines.length; i++) {
|
|
260
255
|
if (i === 0) {
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
import { existsSync, readdirSync } from "node:fs";
|
|
8
8
|
import { join } from "node:path";
|
|
9
9
|
import { spawnSync } from "node:child_process";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
10
|
+
import { resolveGsdPathContract } from "./paths.js";
|
|
11
|
+
import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
12
|
+
import { buildWorktreeLifecycleDeps } from "./auto.js";
|
|
13
|
+
import { mergeMilestoneStandalone, } from "./worktree-lifecycle.js";
|
|
13
14
|
import { MergeConflictError } from "./git-service.js";
|
|
14
15
|
import { removeSessionStatus } from "./session-status-io.js";
|
|
15
16
|
import { getErrorMessage } from "./error-utils.js";
|
|
@@ -105,37 +106,42 @@ export function determineMergeOrder(workers, order = "sequential", basePath) {
|
|
|
105
106
|
}
|
|
106
107
|
/**
|
|
107
108
|
* Attempt to merge a single milestone's worktree back to main.
|
|
108
|
-
*
|
|
109
|
+
*
|
|
110
|
+
* Routes through `WorktreeLifecycle.mergeMilestoneStandalone` so parallel
|
|
111
|
+
* callers get the same projection-finalize / roadmap-fallback / secondary-
|
|
112
|
+
* teardown invariants as the single-loop path. Closes the parallel-merge
|
|
113
|
+
* bypass that ADR-016 names (issue #5618).
|
|
109
114
|
*/
|
|
110
115
|
export async function mergeCompletedMilestone(basePath, milestoneId) {
|
|
116
|
+
// Resolve the worktree path explicitly; parallel-merge has no AutoSession
|
|
117
|
+
// to read it from. Only use the worktree path when git actually knows
|
|
118
|
+
// about it (`getAutoWorktreePath` returns non-null). When the directory
|
|
119
|
+
// exists on disk but isn't a registered git worktree (e.g. a stale
|
|
120
|
+
// session-status marker dir), fall back to the project root and let the
|
|
121
|
+
// standalone's mode detection pick branch-mode or skipped — using the
|
|
122
|
+
// un-registered dir as `worktreeBasePath` would cause `getCurrentBranch`
|
|
123
|
+
// to fail with a "Worktree HEAD diverged" error.
|
|
124
|
+
const registeredWtPath = getAutoWorktreePath(basePath, milestoneId);
|
|
125
|
+
const worktreeBasePath = registeredWtPath ?? basePath;
|
|
126
|
+
let result;
|
|
111
127
|
try {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
return {
|
|
116
|
-
milestoneId,
|
|
117
|
-
success: false,
|
|
118
|
-
error: `No roadmap found for ${milestoneId}`,
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
const roadmapContent = await loadFile(roadmapPath);
|
|
122
|
-
if (!roadmapContent) {
|
|
123
|
-
return {
|
|
124
|
-
milestoneId,
|
|
125
|
-
success: false,
|
|
126
|
-
error: `Could not read roadmap for ${milestoneId}`,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
// Attempt the merge
|
|
130
|
-
const result = mergeMilestoneToMain(basePath, milestoneId, roadmapContent);
|
|
131
|
-
// Clean up parallel session status
|
|
132
|
-
removeSessionStatus(basePath, milestoneId);
|
|
133
|
-
return {
|
|
128
|
+
result = mergeMilestoneStandalone(buildWorktreeLifecycleDeps(), {
|
|
129
|
+
originalBasePath: basePath,
|
|
130
|
+
worktreeBasePath,
|
|
134
131
|
milestoneId,
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
132
|
+
// Parallel context never runs with degraded isolation — workers only
|
|
133
|
+
// exist when isolation succeeded. Pass `false` explicitly so the
|
|
134
|
+
// standalone's degraded-skip branch is not reached.
|
|
135
|
+
isolationDegraded: false,
|
|
136
|
+
notify: (msg, level) => {
|
|
137
|
+
// Surface user-visible messages from the standalone through the
|
|
138
|
+
// workflow logger so the parallel merge's progress is visible in
|
|
139
|
+
// the same channel as the rest of the parallel orchestration.
|
|
140
|
+
if (level === "error" || level === "warning") {
|
|
141
|
+
logWarning("parallel", `${milestoneId}: ${msg}`);
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
});
|
|
139
145
|
}
|
|
140
146
|
catch (err) {
|
|
141
147
|
if (err instanceof MergeConflictError) {
|
|
@@ -152,6 +158,23 @@ export async function mergeCompletedMilestone(basePath, milestoneId) {
|
|
|
152
158
|
error: getErrorMessage(err),
|
|
153
159
|
};
|
|
154
160
|
}
|
|
161
|
+
if (!result.merged) {
|
|
162
|
+
return {
|
|
163
|
+
milestoneId,
|
|
164
|
+
success: false,
|
|
165
|
+
error: result.mode === "skipped"
|
|
166
|
+
? `Merge skipped for ${milestoneId} (mode=none or isolation degraded).`
|
|
167
|
+
: `No roadmap for ${milestoneId} — milestone branch preserved for manual merge.`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// Clean up parallel session status — only on a real merge.
|
|
171
|
+
removeSessionStatus(basePath, milestoneId);
|
|
172
|
+
return {
|
|
173
|
+
milestoneId,
|
|
174
|
+
success: true,
|
|
175
|
+
commitMessage: result.commitMessage,
|
|
176
|
+
pushed: result.pushed,
|
|
177
|
+
};
|
|
155
178
|
}
|
|
156
179
|
/**
|
|
157
180
|
* Merge all completed milestones in sequence.
|