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,6 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Tests for /gsd notifications command handling and overlay launch behavior.
|
|
3
|
+
|
|
1
4
|
import test from "node:test";
|
|
2
5
|
import assert from "node:assert/strict";
|
|
3
6
|
import { join } from "node:path";
|
|
@@ -58,6 +61,47 @@ test("notifications command falls back to text output when overlay returns undef
|
|
|
58
61
|
assert.match(notices[0].message, /Recent notifications:/);
|
|
59
62
|
});
|
|
60
63
|
|
|
64
|
+
test("notifications command opens a compact bounded overlay", async (t) => {
|
|
65
|
+
const base = makeTempDir("overlay-options");
|
|
66
|
+
initNotificationStore(base);
|
|
67
|
+
appendNotification("Build complete", "success");
|
|
68
|
+
|
|
69
|
+
t.after(() => {
|
|
70
|
+
_resetNotificationStore();
|
|
71
|
+
cleanup(base);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
const notices: Array<{ message: string; level?: string }> = [];
|
|
75
|
+
let capturedOptions: any;
|
|
76
|
+
await handleNotificationsCommand(
|
|
77
|
+
"",
|
|
78
|
+
{
|
|
79
|
+
hasUI: true,
|
|
80
|
+
ui: {
|
|
81
|
+
custom: async (_factory: any, options: any) => {
|
|
82
|
+
capturedOptions = options;
|
|
83
|
+
return true;
|
|
84
|
+
},
|
|
85
|
+
notify: (message: string, level?: string) => {
|
|
86
|
+
notices.push({ message, level });
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
} as any,
|
|
90
|
+
{} as any,
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
assert.deepEqual(capturedOptions?.overlayOptions, {
|
|
94
|
+
width: "58%",
|
|
95
|
+
minWidth: 68,
|
|
96
|
+
maxHeight: "52%",
|
|
97
|
+
anchor: "top-center",
|
|
98
|
+
row: "24%",
|
|
99
|
+
margin: { top: 2, right: 2, bottom: 6, left: 2 },
|
|
100
|
+
backdrop: true,
|
|
101
|
+
});
|
|
102
|
+
assert.equal(notices.length, 0, "successful overlay should not emit text fallback");
|
|
103
|
+
});
|
|
104
|
+
|
|
61
105
|
test("notifications tail caps inline output and hints to open overlay", async (t) => {
|
|
62
106
|
const base = makeTempDir("tail-cap");
|
|
63
107
|
initNotificationStore(base);
|
|
@@ -33,43 +33,6 @@ import {
|
|
|
33
33
|
teardownAutoWorktree,
|
|
34
34
|
} from "../auto-worktree.ts";
|
|
35
35
|
import { normalizeWorktreePathForCompare } from "../worktree-root.ts";
|
|
36
|
-
import {
|
|
37
|
-
WorktreeLifecycle,
|
|
38
|
-
type WorktreeLifecycleDeps,
|
|
39
|
-
type NotifyCtx,
|
|
40
|
-
} from "../worktree-lifecycle.ts";
|
|
41
|
-
import { WorktreeStateProjection } from "../worktree-state-projection.ts";
|
|
42
|
-
import { resolveWorktreeProjectRoot } from "../worktree-root.ts";
|
|
43
|
-
import { AutoSession } from "../auto/session.ts";
|
|
44
|
-
|
|
45
|
-
// Test-local: LegacyTestDeps had three fields Lifecycle does not need
|
|
46
|
-
// (shouldUseWorktreeIsolation, syncWorktreeStateBack, captureIntegrationBranch).
|
|
47
|
-
// Permit them in test fixtures so existing override patterns keep working —
|
|
48
|
-
// Lifecycle ignores the extras via structural typing.
|
|
49
|
-
type LegacyTestDeps = WorktreeLifecycleDeps & {
|
|
50
|
-
shouldUseWorktreeIsolation?: () => boolean;
|
|
51
|
-
syncWorktreeStateBack?: (
|
|
52
|
-
mainBasePath: string,
|
|
53
|
-
worktreePath: string,
|
|
54
|
-
milestoneId: string,
|
|
55
|
-
) => { synced: string[] };
|
|
56
|
-
captureIntegrationBranch?: (basePath: string, mid: string | undefined) => void;
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
/** Shim factory preserving the legacy WorktreeResolver throw shape for tests. */
|
|
60
|
-
function makeResolver(s: AutoSession, deps: LegacyTestDeps) {
|
|
61
|
-
const lifecycle = new WorktreeLifecycle(s, deps);
|
|
62
|
-
return {
|
|
63
|
-
get workPath(): string { return s.basePath; },
|
|
64
|
-
get projectRoot(): string {
|
|
65
|
-
return resolveWorktreeProjectRoot(s.basePath, s.originalBasePath);
|
|
66
|
-
},
|
|
67
|
-
mergeAndExit: (mid: string, ctx: NotifyCtx) => {
|
|
68
|
-
const r = lifecycle.exitMilestone(mid, { merge: true }, ctx);
|
|
69
|
-
if (!r.ok && r.cause instanceof Error) throw r.cause;
|
|
70
|
-
},
|
|
71
|
-
};
|
|
72
|
-
}
|
|
73
36
|
|
|
74
37
|
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
75
38
|
|
|
@@ -91,97 +54,6 @@ function createTempRepo(t: { after: (fn: () => void) => void }): string {
|
|
|
91
54
|
return dir;
|
|
92
55
|
}
|
|
93
56
|
|
|
94
|
-
function makeSession(overrides?: Partial<{ basePath: string; originalBasePath: string }>): AutoSession {
|
|
95
|
-
const s = new AutoSession();
|
|
96
|
-
s.basePath = overrides?.basePath ?? "/project";
|
|
97
|
-
s.originalBasePath = overrides?.originalBasePath ?? "/project";
|
|
98
|
-
return s;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
interface CallLog { fn: string; args: unknown[] }
|
|
102
|
-
|
|
103
|
-
function makeDeps(overrides?: Partial<LegacyTestDeps>): LegacyTestDeps & { calls: CallLog[] } {
|
|
104
|
-
const calls: CallLog[] = [];
|
|
105
|
-
|
|
106
|
-
const deps: LegacyTestDeps & { calls: CallLog[] } = {
|
|
107
|
-
calls,
|
|
108
|
-
isInAutoWorktree: (basePath: string) => {
|
|
109
|
-
calls.push({ fn: "isInAutoWorktree", args: [basePath] });
|
|
110
|
-
return basePath.includes("worktrees");
|
|
111
|
-
},
|
|
112
|
-
shouldUseWorktreeIsolation: () => true,
|
|
113
|
-
getIsolationMode: () => "worktree",
|
|
114
|
-
mergeMilestoneToMain: (basePath: string, milestoneId: string, roadmapContent: string) => {
|
|
115
|
-
calls.push({ fn: "mergeMilestoneToMain", args: [basePath, milestoneId, roadmapContent] });
|
|
116
|
-
return { pushed: false, codeFilesChanged: true };
|
|
117
|
-
},
|
|
118
|
-
syncWorktreeStateBack: (mainBasePath: string, worktreePath: string, milestoneId: string) => {
|
|
119
|
-
calls.push({ fn: "syncWorktreeStateBack", args: [mainBasePath, worktreePath, milestoneId] });
|
|
120
|
-
return { synced: [] };
|
|
121
|
-
},
|
|
122
|
-
teardownAutoWorktree: (basePath: string, milestoneId: string, opts?: { preserveBranch?: boolean }) => {
|
|
123
|
-
calls.push({ fn: "teardownAutoWorktree", args: [basePath, milestoneId, opts] });
|
|
124
|
-
},
|
|
125
|
-
createAutoWorktree: (basePath: string, milestoneId: string) => {
|
|
126
|
-
calls.push({ fn: "createAutoWorktree", args: [basePath, milestoneId] });
|
|
127
|
-
return `${basePath}/.gsd/worktrees/${milestoneId}`;
|
|
128
|
-
},
|
|
129
|
-
enterAutoWorktree: (basePath: string, milestoneId: string) => {
|
|
130
|
-
calls.push({ fn: "enterAutoWorktree", args: [basePath, milestoneId] });
|
|
131
|
-
return `${basePath}/.gsd/worktrees/${milestoneId}`;
|
|
132
|
-
},
|
|
133
|
-
getAutoWorktreePath: (basePath: string, milestoneId: string) => {
|
|
134
|
-
calls.push({ fn: "getAutoWorktreePath", args: [basePath, milestoneId] });
|
|
135
|
-
return null;
|
|
136
|
-
},
|
|
137
|
-
autoCommitCurrentBranch: (basePath: string, reason: string, milestoneId: string) => {
|
|
138
|
-
calls.push({ fn: "autoCommitCurrentBranch", args: [basePath, reason, milestoneId] });
|
|
139
|
-
},
|
|
140
|
-
getCurrentBranch: (basePath: string) => {
|
|
141
|
-
calls.push({ fn: "getCurrentBranch", args: [basePath] });
|
|
142
|
-
return "main";
|
|
143
|
-
},
|
|
144
|
-
checkoutBranch: (basePath: string, branch: string) => {
|
|
145
|
-
calls.push({ fn: "checkoutBranch", args: [basePath, branch] });
|
|
146
|
-
},
|
|
147
|
-
autoWorktreeBranch: (milestoneId: string) => `milestone/${milestoneId}`,
|
|
148
|
-
resolveMilestoneFile: (basePath: string, milestoneId: string, fileType: string) => {
|
|
149
|
-
calls.push({ fn: "resolveMilestoneFile", args: [basePath, milestoneId, fileType] });
|
|
150
|
-
return null;
|
|
151
|
-
},
|
|
152
|
-
readFileSync: (path: string, _enc: string) => {
|
|
153
|
-
calls.push({ fn: "readFileSync", args: [path] });
|
|
154
|
-
return "# Roadmap\n";
|
|
155
|
-
},
|
|
156
|
-
GitServiceImpl: class {
|
|
157
|
-
constructor(_basePath: string, _gitConfig: unknown) {}
|
|
158
|
-
} as unknown as LegacyTestDeps["GitServiceImpl"],
|
|
159
|
-
loadEffectiveGSDPreferences: () => ({ preferences: { git: {} } }),
|
|
160
|
-
invalidateAllCaches: () => { calls.push({ fn: "invalidateAllCaches", args: [] }); },
|
|
161
|
-
captureIntegrationBranch: (_basePath: string, _mid: string | undefined) => {},
|
|
162
|
-
enterBranchModeForMilestone: (_basePath: string, _milestoneId: string) => {},
|
|
163
|
-
worktreeProjection: new WorktreeStateProjection(),
|
|
164
|
-
...overrides,
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
if (overrides) {
|
|
168
|
-
for (const [key, val] of Object.entries(overrides)) {
|
|
169
|
-
if (key !== "calls") (deps as unknown as Record<string, unknown>)[key] = val;
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
return deps;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function makeNotifyCtx(): NotifyCtx & { messages: Array<{ msg: string; level?: string }> } {
|
|
176
|
-
const messages: Array<{ msg: string; level?: string }> = [];
|
|
177
|
-
return {
|
|
178
|
-
messages,
|
|
179
|
-
notify: (msg: string, level?: "info" | "warning" | "error" | "success") => {
|
|
180
|
-
messages.push({ msg, level });
|
|
181
|
-
},
|
|
182
|
-
};
|
|
183
|
-
}
|
|
184
|
-
|
|
185
57
|
// ─── Suite 1: getAutoWorktreeOriginalBase() returns realpath-canonical path ──
|
|
186
58
|
|
|
187
59
|
describe("getAutoWorktreeOriginalBase() is realpath-normalised", () => {
|
|
@@ -273,92 +145,15 @@ describe("normalizeWorktreePathForCompare equalises canonical vs non-canonical f
|
|
|
273
145
|
// resolveMilestoneFile call against the "worktree" path that is actually the
|
|
274
146
|
// same directory). The new code correctly skips the fallback.
|
|
275
147
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
const calls: CallLog[] = [];
|
|
289
|
-
const deps = makeDeps({
|
|
290
|
-
// isInAutoWorktree: basePath has trailing slash but is NOT a worktree
|
|
291
|
-
isInAutoWorktree: (basePath: string) => {
|
|
292
|
-
calls.push({ fn: "isInAutoWorktree", args: [basePath] });
|
|
293
|
-
return false;
|
|
294
|
-
},
|
|
295
|
-
// resolveMilestoneFile always returns null (no roadmap found)
|
|
296
|
-
resolveMilestoneFile: (basePath: string, milestoneId: string, fileType: string) => {
|
|
297
|
-
calls.push({ fn: "resolveMilestoneFile", args: [basePath, milestoneId, fileType] });
|
|
298
|
-
return null;
|
|
299
|
-
},
|
|
300
|
-
teardownAutoWorktree: (basePath: string, milestoneId: string, opts?: { preserveBranch?: boolean }) => {
|
|
301
|
-
calls.push({ fn: "teardownAutoWorktree", args: [basePath, milestoneId, opts] });
|
|
302
|
-
},
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
// Override calls ref so we can inspect it directly
|
|
306
|
-
(deps as unknown as { calls: CallLog[] }).calls = calls;
|
|
307
|
-
|
|
308
|
-
const resolver = makeResolver(s, deps);
|
|
309
|
-
const ctx = makeNotifyCtx();
|
|
310
|
-
|
|
311
|
-
// mergeAndExit → _mergeWorktreeMode
|
|
312
|
-
// originalBase = s.originalBasePath = canonicalBase
|
|
313
|
-
// s.basePath = trailingSlashBase — physically same as canonicalBase
|
|
314
|
-
// Post-fix: isSamePath(trailingSlashBase, canonicalBase) is true
|
|
315
|
-
// → roadmap fallback branch is skipped (resolveMilestoneFile called once)
|
|
316
|
-
// Pre-fix (bug): trailingSlashBase !== canonicalBase → fallback entered
|
|
317
|
-
// → resolveMilestoneFile called twice
|
|
318
|
-
|
|
319
|
-
resolver.mergeAndExit("M001", ctx);
|
|
320
|
-
|
|
321
|
-
const rmfCalls = calls.filter(c => c.fn === "resolveMilestoneFile");
|
|
322
|
-
assert.strictEqual(rmfCalls.length, 1,
|
|
323
|
-
"resolveMilestoneFile must be called exactly once — fallback should be skipped when " +
|
|
324
|
-
"s.basePath is the same physical path as originalBase (isSamePath fix)");
|
|
325
|
-
});
|
|
326
|
-
|
|
327
|
-
test("with genuinely different basePath (inside worktree): resolveMilestoneFile called twice", () => {
|
|
328
|
-
// originalBase is the project root
|
|
329
|
-
const projectRoot = "/tmp/m5-test-project";
|
|
330
|
-
// s.basePath is inside a worktree — a physically different path
|
|
331
|
-
const worktreePath = projectRoot + "/.gsd/worktrees/M002";
|
|
332
|
-
|
|
333
|
-
const s = makeSession({
|
|
334
|
-
basePath: worktreePath,
|
|
335
|
-
originalBasePath: projectRoot,
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
const calls: CallLog[] = [];
|
|
339
|
-
const deps = makeDeps({
|
|
340
|
-
isInAutoWorktree: (basePath: string) => {
|
|
341
|
-
calls.push({ fn: "isInAutoWorktree", args: [basePath] });
|
|
342
|
-
return basePath.includes("worktrees");
|
|
343
|
-
},
|
|
344
|
-
resolveMilestoneFile: (basePath: string, milestoneId: string, fileType: string) => {
|
|
345
|
-
calls.push({ fn: "resolveMilestoneFile", args: [basePath, milestoneId, fileType] });
|
|
346
|
-
return null; // no roadmap in either location
|
|
347
|
-
},
|
|
348
|
-
teardownAutoWorktree: (basePath: string, milestoneId: string, opts?: { preserveBranch?: boolean }) => {
|
|
349
|
-
calls.push({ fn: "teardownAutoWorktree", args: [basePath, milestoneId, opts] });
|
|
350
|
-
},
|
|
351
|
-
});
|
|
352
|
-
(deps as unknown as { calls: CallLog[] }).calls = calls;
|
|
353
|
-
|
|
354
|
-
const resolver = makeResolver(s, deps);
|
|
355
|
-
const ctx = makeNotifyCtx();
|
|
356
|
-
|
|
357
|
-
resolver.mergeAndExit("M002", ctx);
|
|
358
|
-
|
|
359
|
-
const rmfCalls = calls.filter(c => c.fn === "resolveMilestoneFile");
|
|
360
|
-
assert.strictEqual(rmfCalls.length, 2,
|
|
361
|
-
"resolveMilestoneFile must be called twice when basePath is a genuine worktree path " +
|
|
362
|
-
"(fallback should run for different physical paths)");
|
|
363
|
-
});
|
|
364
|
-
});
|
|
148
|
+
// ADR-016 phase 2 / C2 + C3 (#5625, #5626): the prior two tests in this
|
|
149
|
+
// suite asserted call counts on `deps.resolveMilestoneFile` /
|
|
150
|
+
// `deps.isInAutoWorktree` / `deps.teardownAutoWorktree` to verify that the
|
|
151
|
+
// roadmap-fallback branch was skipped when basePath was a non-canonical
|
|
152
|
+
// form of originalBase (trailing slash). After C2/C3 those fields are
|
|
153
|
+
// inlined into worktree-lifecycle.ts as direct imports — the mocks no
|
|
154
|
+
// longer fire and the call-count assertions test nothing meaningful. The
|
|
155
|
+
// underlying invariant (isSamePathPhysical normalises trailing slashes,
|
|
156
|
+
// canonical/non-canonical pairs, and case differences) is preserved
|
|
157
|
+
// inside worktree-lifecycle.ts and covered indirectly by the merge-area
|
|
158
|
+
// integration tests, which exercise real worktree merges where the
|
|
159
|
+
// fallback choice matters.
|
|
@@ -1,11 +1,19 @@
|
|
|
1
|
+
// Project/App: GSD-2
|
|
2
|
+
// File Purpose: Regression tests for parallel monitor overlay rendering and input handling.
|
|
3
|
+
|
|
1
4
|
import { describe, it } from "node:test";
|
|
2
|
-
import assert from "node:assert";
|
|
5
|
+
import assert from "node:assert/strict";
|
|
6
|
+
|
|
7
|
+
import { visibleWidth } from "@gsd/pi-tui";
|
|
3
8
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
+
function assertLinesFit(lines: string[], width: number): void {
|
|
10
|
+
for (const line of lines) {
|
|
11
|
+
assert.ok(
|
|
12
|
+
visibleWidth(line) <= width,
|
|
13
|
+
`line exceeds width ${width}: ${visibleWidth(line)} "${line}"`,
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
9
17
|
|
|
10
18
|
describe("parallel-monitor-overlay", () => {
|
|
11
19
|
it("progressBar generates correct width", async () => {
|
|
@@ -37,6 +45,7 @@ describe("parallel-monitor-overlay", () => {
|
|
|
37
45
|
const lines = overlay.render(80);
|
|
38
46
|
assert.ok(Array.isArray(lines), "render should return an array");
|
|
39
47
|
assert.ok(lines.length > 0, "render should return at least one line");
|
|
48
|
+
assertLinesFit(lines, 80);
|
|
40
49
|
|
|
41
50
|
// Should contain header text
|
|
42
51
|
const joined = lines.join("\n");
|
|
@@ -79,4 +88,27 @@ describe("parallel-monitor-overlay", () => {
|
|
|
79
88
|
assert.equal((overlay as any).scrollOffset, 0, "empty overlays clamp scroll to zero");
|
|
80
89
|
overlay.dispose();
|
|
81
90
|
});
|
|
91
|
+
|
|
92
|
+
it("ParallelMonitorOverlay empty state fits narrow and wide widths", async () => {
|
|
93
|
+
const mod = await import("../parallel-monitor-overlay.js");
|
|
94
|
+
|
|
95
|
+
const mockTui = { requestRender: () => {} };
|
|
96
|
+
const mockTheme = {
|
|
97
|
+
fg: (_color: string, text: string) => text,
|
|
98
|
+
bold: (text: string) => text,
|
|
99
|
+
};
|
|
100
|
+
const overlay = new mod.ParallelMonitorOverlay(
|
|
101
|
+
mockTui,
|
|
102
|
+
mockTheme as any,
|
|
103
|
+
() => {},
|
|
104
|
+
"/nonexistent/path",
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
for (const width of [40, 80, 120]) {
|
|
108
|
+
assertLinesFit(overlay.render(width), width);
|
|
109
|
+
overlay.invalidate();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
overlay.dispose();
|
|
113
|
+
});
|
|
82
114
|
});
|
|
@@ -250,14 +250,14 @@ describe("Post-execution blocking failure retry bypass", () => {
|
|
|
250
250
|
const s = makeMockSession(tempDir, { type: "execute-task", id: "M001/S01/T01" });
|
|
251
251
|
|
|
252
252
|
// Pre-set some retry state
|
|
253
|
-
s.verificationRetryCount.set("M001/S01/T01", 2);
|
|
253
|
+
s.verificationRetryCount.set("execute-task:M001/S01/T01", 2);
|
|
254
254
|
|
|
255
255
|
const vctx: VerificationContext = { s, ctx, pi };
|
|
256
256
|
const result = await runPostUnitVerification(vctx, pauseAutoMock);
|
|
257
257
|
|
|
258
258
|
// On success, retry count should be cleared
|
|
259
259
|
assert.equal(result, "continue");
|
|
260
|
-
assert.equal(s.verificationRetryCount.has("M001/S01/T01"), false);
|
|
260
|
+
assert.equal(s.verificationRetryCount.has("execute-task:M001/S01/T01"), false);
|
|
261
261
|
});
|
|
262
262
|
|
|
263
263
|
test("post-exec failure notification mentions cross-task consistency", async () => {
|
|
@@ -14,9 +14,9 @@ import {
|
|
|
14
14
|
insertMilestone,
|
|
15
15
|
insertSlice,
|
|
16
16
|
setSliceSketchFlag,
|
|
17
|
-
autoHealSketchFlags,
|
|
18
17
|
getSlice,
|
|
19
18
|
} from "../gsd-db.ts";
|
|
19
|
+
import { autoHealSketchFlags } from "../state-reconciliation/drift/sketch-flag.ts";
|
|
20
20
|
import { deriveStateFromDb } from "../state.ts";
|
|
21
21
|
import { resolveDispatch } from "../auto-dispatch.ts";
|
|
22
22
|
import type { DispatchContext } from "../auto-dispatch.ts";
|
|
@@ -64,6 +64,16 @@ test("discuss prompt allows implementation questions when they materially matter
|
|
|
64
64
|
assert.doesNotMatch(prompt, /Questions must be about the experience, not the implementation/i);
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
+
test("discuss prompt ends milestone planning with next-step handoff", () => {
|
|
68
|
+
const prompt = readPrompt("discuss");
|
|
69
|
+
assert.match(prompt, /Next steps:/);
|
|
70
|
+
assert.match(prompt, /\/gsd auto/);
|
|
71
|
+
assert.match(prompt, /\/gsd status/);
|
|
72
|
+
assert.match(prompt, /\/gsd visualize/);
|
|
73
|
+
assert.match(prompt, /\/gsd notifications/);
|
|
74
|
+
assert.doesNotMatch(prompt, /nothing else\. Auto-mode will start automatically/);
|
|
75
|
+
});
|
|
76
|
+
|
|
67
77
|
test("guided discussion prompts avoid wrap-up prompts after every round", () => {
|
|
68
78
|
const milestonePrompt = readPrompt("guided-discuss-milestone");
|
|
69
79
|
const slicePrompt = readPrompt("guided-discuss-slice");
|
|
@@ -217,6 +227,17 @@ test("complete-slice prompt does not instruct LLM to toggle checkboxes manually"
|
|
|
217
227
|
assert.doesNotMatch(prompt, /change \[ \] to \[x\]/);
|
|
218
228
|
});
|
|
219
229
|
|
|
230
|
+
test("complete-slice prompt keeps source fixes in execution units", () => {
|
|
231
|
+
const prompt = readPrompt("complete-slice");
|
|
232
|
+
assert.match(prompt, /Do not use direct `bash` for verification commands/i);
|
|
233
|
+
assert.match(prompt, /do \*\*not\*\* edit source files in this unit/i);
|
|
234
|
+
assert.match(prompt, /do \*\*not\*\* call `gsd_slice_complete`/i);
|
|
235
|
+
assert.match(prompt, /gsd_task_reopen/);
|
|
236
|
+
assert.match(prompt, /gsd_replan_slice/);
|
|
237
|
+
assert.match(prompt, /needs execution follow-up/i);
|
|
238
|
+
assert.doesNotMatch(prompt, /Fix failures before marking done/i);
|
|
239
|
+
});
|
|
240
|
+
|
|
220
241
|
test("complete-slice prompt instructs writing summary and UAT files before tool call", () => {
|
|
221
242
|
const prompt = readPrompt("complete-slice");
|
|
222
243
|
assert.match(prompt, /\{\{sliceSummaryPath\}\}/);
|
|
@@ -363,7 +384,9 @@ test("execute-task prompt uses camelCase parameter names matching TypeBox schema
|
|
|
363
384
|
test("complete-slice prompt uses camelCase parameter names matching TypeBox schema", () => {
|
|
364
385
|
const prompt = readPrompt("complete-slice");
|
|
365
386
|
// The gsd_complete_slice tool schema uses camelCase: milestoneId, sliceId
|
|
366
|
-
const toolCallLine = prompt.split("\n").find((l) =>
|
|
387
|
+
const toolCallLine = prompt.split("\n").find((l) =>
|
|
388
|
+
(/gsd_complete_slice/.test(l) || /gsd_slice_complete/.test(l)) && /milestoneId/.test(l) && /sliceId/.test(l)
|
|
389
|
+
);
|
|
367
390
|
assert.ok(toolCallLine, "prompt must contain a gsd_complete_slice or gsd_slice_complete tool call line");
|
|
368
391
|
assert.doesNotMatch(toolCallLine!, /milestone_id/, "must use milestoneId, not milestone_id");
|
|
369
392
|
assert.doesNotMatch(toolCallLine!, /slice_id/, "must use sliceId, not slice_id");
|
|
@@ -10,7 +10,11 @@ import { join } from "node:path";
|
|
|
10
10
|
import { tmpdir } from "node:os";
|
|
11
11
|
import { randomUUID } from "node:crypto";
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
// ADR-016 phase 2 / B3 (#5621): the legacy `resolvePausedResumeBasePath`
|
|
14
|
+
// helper was retired and folded into `WorktreeLifecycle.resumeFromPausedSession`.
|
|
15
|
+
// The pure path-resolution function lives in `worktree-lifecycle.ts` for tests
|
|
16
|
+
// that exercise the path-resolution invariant without constructing a session.
|
|
17
|
+
import { resolvePausedResumeBasePath } from "../worktree-lifecycle.ts";
|
|
14
18
|
|
|
15
19
|
function makeTmpBase(): string {
|
|
16
20
|
const base = join(tmpdir(), `gsd-resume-wt-${randomUUID()}`);
|
|
@@ -59,7 +63,7 @@ test("resume base path uses paused-session worktreePath when the worktree exists
|
|
|
59
63
|
try {
|
|
60
64
|
setupWorktreeOnDisk(wt);
|
|
61
65
|
assert.equal(
|
|
62
|
-
|
|
66
|
+
resolvePausedResumeBasePath(base, wt),
|
|
63
67
|
wt,
|
|
64
68
|
);
|
|
65
69
|
} finally {
|
|
@@ -72,7 +76,7 @@ test("resume base path falls back to project root when paused worktree is missin
|
|
|
72
76
|
const wt = makeWorktreePath(base, "M001-test");
|
|
73
77
|
try {
|
|
74
78
|
assert.equal(
|
|
75
|
-
|
|
79
|
+
resolvePausedResumeBasePath(base, wt),
|
|
76
80
|
base,
|
|
77
81
|
);
|
|
78
82
|
} finally {
|
|
@@ -42,16 +42,19 @@ test("State Reconciliation invalidates cache and returns reconciled state", asyn
|
|
|
42
42
|
assert.equal(result.ok && result.stateSnapshot, state);
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
test("State Reconciliation
|
|
45
|
+
test("State Reconciliation surfaces terminal blockers in result (ADR-017)", async () => {
|
|
46
|
+
// Under ADR-017, blockers are terminal but do not throw — they ride along
|
|
47
|
+
// in the result so the orchestrator adapter can map them to ok=false.
|
|
46
48
|
const result = await reconcileBeforeDispatch("/project", {
|
|
47
49
|
invalidateStateCache() {},
|
|
48
50
|
async deriveState() {
|
|
49
51
|
return makeState({ phase: "blocked", blockers: ["slice lock missing"] });
|
|
50
52
|
},
|
|
53
|
+
registry: [],
|
|
51
54
|
});
|
|
52
55
|
|
|
53
|
-
assert.equal(result.ok,
|
|
54
|
-
assert.
|
|
56
|
+
assert.equal(result.ok, true);
|
|
57
|
+
assert.deepEqual(result.blockers, ["slice lock missing"]);
|
|
55
58
|
});
|
|
56
59
|
|
|
57
60
|
test("Tool Contract compiles known Unit prompt and tool policy", () => {
|
|
@@ -188,6 +188,30 @@ test("empty-content aborted during session-switch is silently ignored", () => {
|
|
|
188
188
|
assert.equal(cancelledWith, null);
|
|
189
189
|
});
|
|
190
190
|
|
|
191
|
+
test("completed assistant content with aborted stopReason during session-switch is ignored", () => {
|
|
192
|
+
// newSession() can abort the just-finished provider stream while the last
|
|
193
|
+
// assistant message still carries the completed unit summary. That is a
|
|
194
|
+
// session-transition artifact, not a cancellation for the next unit.
|
|
195
|
+
let cancelledWith: unknown = null;
|
|
196
|
+
const resolveCancelled = (ctx: ErrorContext) => {
|
|
197
|
+
cancelledWith = ctx;
|
|
198
|
+
return true;
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
_handleSessionSwitchAgentEnd(
|
|
202
|
+
{
|
|
203
|
+
stopReason: "aborted",
|
|
204
|
+
content: [{
|
|
205
|
+
type: "text",
|
|
206
|
+
text: "Implemented T01 and verified the slice task is complete.",
|
|
207
|
+
}],
|
|
208
|
+
},
|
|
209
|
+
resolveCancelled,
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
assert.equal(cancelledWith, null);
|
|
213
|
+
});
|
|
214
|
+
|
|
191
215
|
test("non-abort errors during session-switch are not propagated through this helper", () => {
|
|
192
216
|
// Real provider errors (rate-limit, network, unsupported-model) are handled
|
|
193
217
|
// by the post-switch retry pipeline — not by the in-flight switch handler.
|