gsd-pi 2.65.0 → 2.66.0-dev.e159299
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/dist/mcp-server.js +6 -2
- package/dist/resources/extensions/browser-tools/capture.js +20 -1
- package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
- package/dist/resources/extensions/gsd/auto/finalize-timeout.js +2 -0
- package/dist/resources/extensions/gsd/auto/loop.js +2 -2
- package/dist/resources/extensions/gsd/auto/phases.js +48 -5
- package/dist/resources/extensions/gsd/auto/run-unit.js +13 -2
- package/dist/resources/extensions/gsd/auto/session.js +4 -0
- package/dist/resources/extensions/gsd/auto/types.js +2 -0
- package/dist/resources/extensions/gsd/auto-dashboard.js +2 -1
- package/dist/resources/extensions/gsd/auto-dispatch.js +99 -9
- package/dist/resources/extensions/gsd/auto-model-selection.js +7 -5
- package/dist/resources/extensions/gsd/auto-post-unit.js +17 -6
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -0
- package/dist/resources/extensions/gsd/auto-recovery.js +40 -22
- package/dist/resources/extensions/gsd/auto-start.js +175 -12
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +10 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +29 -7
- package/dist/resources/extensions/gsd/auto.js +21 -15
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -4
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -0
- package/dist/resources/extensions/gsd/bootstrap/query-tools.js +6 -4
- package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -3
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -1
- package/dist/resources/extensions/gsd/bootstrap/write-gate.js +31 -1
- package/dist/resources/extensions/gsd/commands/context.js +8 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +23 -2
- package/dist/resources/extensions/gsd/commands-extensions.js +1 -1
- package/dist/resources/extensions/gsd/config-overlay.js +312 -0
- package/dist/resources/extensions/gsd/db-writer.js +13 -3
- package/dist/resources/extensions/gsd/detection.js +1 -1
- package/dist/resources/extensions/gsd/dispatch-guard.js +2 -1
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/dist/resources/extensions/gsd/doctor.js +2 -1
- package/dist/resources/extensions/gsd/files.js +17 -0
- package/dist/resources/extensions/gsd/gitignore.js +1 -0
- package/dist/resources/extensions/gsd/gsd-db.js +47 -4
- package/dist/resources/extensions/gsd/guided-flow.js +220 -29
- package/dist/resources/extensions/gsd/index.js +1 -1
- package/dist/resources/extensions/gsd/json-persistence.js +5 -2
- package/dist/resources/extensions/gsd/md-importer.js +14 -7
- package/dist/resources/extensions/gsd/notification-overlay.js +1 -1
- package/dist/resources/extensions/gsd/notification-widget.js +2 -1
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +1 -1
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +17 -11
- package/dist/resources/extensions/gsd/pre-execution-checks.js +26 -5
- package/dist/resources/extensions/gsd/preferences-types.js +3 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +45 -1
- package/dist/resources/extensions/gsd/preferences.js +9 -2
- package/dist/resources/extensions/gsd/preparation.js +1092 -0
- package/dist/resources/extensions/gsd/prompt-validation.js +67 -0
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
- package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +6 -1
- package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
- package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
- package/dist/resources/extensions/gsd/prompts/queue.md +2 -0
- package/dist/resources/extensions/gsd/prompts/rethink.md +2 -1
- package/dist/resources/extensions/gsd/prompts/system.md +2 -2
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
- package/dist/resources/extensions/gsd/quick.js +19 -15
- package/dist/resources/extensions/gsd/reactive-graph.js +12 -0
- package/dist/resources/extensions/gsd/roadmap-slices.js +24 -5
- package/dist/resources/extensions/gsd/safety/content-validator.js +3 -3
- package/dist/resources/extensions/gsd/session-lock.js +23 -1
- package/dist/resources/extensions/gsd/state.js +115 -28
- package/dist/resources/extensions/gsd/templates/context-enhanced.md +138 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +15 -3
- package/dist/resources/extensions/gsd/tools/complete-slice.js +27 -6
- package/dist/resources/extensions/gsd/tools/complete-task.js +31 -7
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -5
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +5 -2
- package/dist/resources/extensions/gsd/tools/reopen-milestone.js +119 -0
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +30 -0
- package/dist/resources/extensions/gsd/tools/reopen-task.js +18 -0
- package/dist/resources/extensions/gsd/triage-resolution.js +33 -16
- package/dist/resources/extensions/gsd/undo.js +3 -2
- package/dist/resources/extensions/gsd/workflow-events.js +1 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
- package/dist/resources/extensions/gsd/workflow-projections.js +7 -9
- package/dist/resources/extensions/gsd/workflow-reconcile.js +100 -9
- package/dist/resources/extensions/gsd/workflow-templates.js +11 -2
- package/dist/resources/extensions/gsd/worktree-manager.js +5 -2
- package/dist/resources/extensions/gsd/worktree.js +9 -0
- package/dist/resources/extensions/shared/interview-ui.js +1 -1
- package/dist/resources/extensions/subagent/agents.js +19 -5
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
- package/dist/web/standalone/.next/build-manifest.json +4 -4
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- 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/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- 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 +3 -3
- 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/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
- 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 +3 -3
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/page.js +2 -2
- package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/6502.8874bcae249c02e1.js +9 -0
- package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-0c485498795110d6.js +1 -0
- package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-a1c1e452c6b32d04.js → webpack-9fed74684e1c5bb1.js} +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
- package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
- package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
- package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
- package/dist/web/standalone/server.js +1 -1
- package/package.json +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.js +30 -19
- package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js +51 -0
- package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +9 -9
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +10 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
- 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 +20 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +15 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +18 -0
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -0
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/retry-handler.test.ts +80 -0
- package/packages/pi-coding-agent/src/core/retry-handler.ts +37 -25
- package/packages/pi-coding-agent/src/core/sdk.ts +9 -9
- package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +20 -4
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +27 -0
- package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +16 -1
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +5 -0
- package/packages/pi-tui/dist/components/image.d.ts +2 -0
- package/packages/pi-tui/dist/components/image.d.ts.map +1 -1
- package/packages/pi-tui/dist/components/image.js +4 -0
- package/packages/pi-tui/dist/components/image.js.map +1 -1
- package/packages/pi-tui/dist/components/image.test.d.ts +6 -0
- package/packages/pi-tui/dist/components/image.test.d.ts.map +1 -0
- package/packages/pi-tui/dist/components/image.test.js +32 -0
- package/packages/pi-tui/dist/components/image.test.js.map +1 -0
- package/packages/pi-tui/dist/tui.d.ts.map +1 -1
- package/packages/pi-tui/dist/tui.js +3 -1
- package/packages/pi-tui/dist/tui.js.map +1 -1
- package/packages/pi-tui/src/components/image.test.ts +36 -0
- package/packages/pi-tui/src/components/image.ts +5 -0
- package/packages/pi-tui/src/tui.ts +3 -1
- package/pkg/package.json +1 -1
- package/src/resources/extensions/browser-tools/capture.ts +19 -1
- package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
- package/src/resources/extensions/gsd/auto/finalize-timeout.ts +3 -0
- package/src/resources/extensions/gsd/auto/loop.ts +2 -2
- package/src/resources/extensions/gsd/auto/phases.ts +68 -3
- package/src/resources/extensions/gsd/auto/run-unit.ts +12 -2
- package/src/resources/extensions/gsd/auto/session.ts +4 -0
- package/src/resources/extensions/gsd/auto/types.ts +5 -0
- package/src/resources/extensions/gsd/auto-dashboard.ts +2 -1
- package/src/resources/extensions/gsd/auto-dispatch.ts +110 -9
- package/src/resources/extensions/gsd/auto-model-selection.ts +7 -5
- package/src/resources/extensions/gsd/auto-post-unit.ts +16 -6
- package/src/resources/extensions/gsd/auto-prompts.ts +31 -0
- package/src/resources/extensions/gsd/auto-recovery.ts +29 -23
- package/src/resources/extensions/gsd/auto-start.ts +188 -10
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +10 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +28 -7
- package/src/resources/extensions/gsd/auto.ts +19 -8
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -4
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -0
- package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -4
- package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +11 -3
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -1
- package/src/resources/extensions/gsd/bootstrap/write-gate.ts +36 -1
- package/src/resources/extensions/gsd/commands/context.ts +7 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +26 -2
- package/src/resources/extensions/gsd/commands-extensions.ts +1 -1
- package/src/resources/extensions/gsd/config-overlay.ts +331 -0
- package/src/resources/extensions/gsd/db-writer.ts +11 -3
- package/src/resources/extensions/gsd/detection.ts +1 -1
- package/src/resources/extensions/gsd/dispatch-guard.ts +2 -1
- package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -0
- package/src/resources/extensions/gsd/doctor.ts +2 -1
- package/src/resources/extensions/gsd/files.ts +19 -0
- package/src/resources/extensions/gsd/gitignore.ts +1 -0
- package/src/resources/extensions/gsd/gsd-db.ts +46 -4
- package/src/resources/extensions/gsd/guided-flow.ts +254 -30
- package/src/resources/extensions/gsd/index.ts +1 -0
- package/src/resources/extensions/gsd/json-persistence.ts +6 -3
- package/src/resources/extensions/gsd/md-importer.ts +13 -6
- package/src/resources/extensions/gsd/notification-overlay.ts +1 -1
- package/src/resources/extensions/gsd/notification-widget.ts +2 -1
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +1 -1
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +19 -11
- package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -7
- package/src/resources/extensions/gsd/preferences-types.ts +25 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +45 -1
- package/src/resources/extensions/gsd/preferences.ts +9 -2
- package/src/resources/extensions/gsd/preparation.ts +1419 -0
- package/src/resources/extensions/gsd/prompt-validation.ts +88 -0
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
- package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +2 -0
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +6 -1
- package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
- package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
- package/src/resources/extensions/gsd/prompts/queue.md +2 -0
- package/src/resources/extensions/gsd/prompts/rethink.md +2 -1
- package/src/resources/extensions/gsd/prompts/system.md +2 -2
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
- package/src/resources/extensions/gsd/quick.ts +20 -15
- package/src/resources/extensions/gsd/reactive-graph.ts +18 -0
- package/src/resources/extensions/gsd/roadmap-slices.ts +21 -5
- package/src/resources/extensions/gsd/safety/content-validator.ts +3 -3
- package/src/resources/extensions/gsd/session-lock.ts +17 -1
- package/src/resources/extensions/gsd/state.ts +115 -26
- package/src/resources/extensions/gsd/templates/context-enhanced.md +138 -0
- package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +223 -0
- package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +33 -2
- package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +41 -0
- package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/defer-milestone-stamp.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -3
- package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +37 -0
- package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/format-shortcut.test.ts +69 -0
- package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +42 -0
- package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +11 -9
- package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +28 -30
- package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +53 -0
- package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +525 -0
- package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +62 -0
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +11 -10
- package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +189 -0
- package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +77 -0
- package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +55 -0
- package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +68 -0
- package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +284 -20
- package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/preparation.test.ts +1211 -0
- package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +53 -0
- package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +83 -0
- package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +669 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -4
- package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +107 -0
- package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +45 -0
- package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +4 -5
- package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +56 -0
- package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/skipped-validation-completion.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +36 -0
- package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +147 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +13 -0
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +21 -0
- package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +6 -7
- package/src/resources/extensions/gsd/tests/status-db-open.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +1 -0
- package/src/resources/extensions/gsd/tests/subagent-agent-discovery.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/symlink-extension-discovery.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +29 -1
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +3 -4
- package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/wave1-critical-regressions.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/wave2-events-regressions.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/wave3-session-regressions.test.ts +47 -0
- package/src/resources/extensions/gsd/tests/wave4-write-safety-regressions.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/wave5-consistency-regressions.test.ts +165 -0
- package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +48 -0
- package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +6 -3
- package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +38 -0
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +16 -0
- package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +16 -17
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +13 -9
- package/src/resources/extensions/gsd/tests/worktree.test.ts +26 -9
- package/src/resources/extensions/gsd/tests/write-gate.test.ts +127 -2
- package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +13 -3
- package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -6
- package/src/resources/extensions/gsd/tools/complete-task.ts +29 -7
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +11 -9
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +5 -2
- package/src/resources/extensions/gsd/tools/reopen-milestone.ts +152 -0
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +27 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +17 -0
- package/src/resources/extensions/gsd/triage-resolution.ts +37 -17
- package/src/resources/extensions/gsd/types.ts +4 -0
- package/src/resources/extensions/gsd/undo.ts +3 -2
- package/src/resources/extensions/gsd/workflow-events.ts +5 -3
- package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
- package/src/resources/extensions/gsd/workflow-projections.ts +7 -8
- package/src/resources/extensions/gsd/workflow-reconcile.ts +109 -8
- package/src/resources/extensions/gsd/workflow-templates.ts +11 -2
- package/src/resources/extensions/gsd/worktree-manager.ts +4 -2
- package/src/resources/extensions/gsd/worktree.ts +10 -0
- package/src/resources/extensions/shared/interview-ui.ts +1 -1
- package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +8 -10
- package/src/resources/extensions/subagent/agents.ts +30 -6
- package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.js +0 -1
- package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
- package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
- /package/dist/web/standalone/.next/static/{MRM3OSYIAa4HMDqVGQ9nt → h8aBiLMFjb__ogynY08cm}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{MRM3OSYIAa4HMDqVGQ9nt → h8aBiLMFjb__ogynY08cm}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for #3461: createAutoWorktree must use git.main_branch
|
|
3
|
+
* preference when META.json integration branch is absent.
|
|
4
|
+
*/
|
|
5
|
+
import { test } from "node:test";
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
|
|
10
|
+
test("auto-worktree.ts includes main_branch preference in startPoint fallback (#3461)", () => {
|
|
11
|
+
const src = readFileSync(
|
|
12
|
+
join(import.meta.dirname, "..", "auto-worktree.ts"),
|
|
13
|
+
"utf-8",
|
|
14
|
+
);
|
|
15
|
+
// The fix adds gitPrefs?.main_branch to the startPoint fallback chain
|
|
16
|
+
assert.ok(
|
|
17
|
+
src.includes("gitPrefs?.main_branch") || src.includes("prefs.main_branch"),
|
|
18
|
+
"createAutoWorktree must check git.main_branch preference before falling back to nativeDetectMainBranch",
|
|
19
|
+
);
|
|
20
|
+
});
|
|
@@ -221,7 +221,8 @@ describe('worktree-sync-milestones', async () => {
|
|
|
221
221
|
|
|
222
222
|
try {
|
|
223
223
|
// Build worktree milestone structure with slice-level and task-level files
|
|
224
|
-
|
|
224
|
+
// Use M002 as the milestone to sync, M001 as the "current" being merged (skipped)
|
|
225
|
+
const wtSliceDir = join(wtBase, '.gsd', 'milestones', 'M002', 'slices', 'S01');
|
|
225
226
|
const wtTasksDir = join(wtSliceDir, 'tasks');
|
|
226
227
|
mkdirSync(wtTasksDir, { recursive: true });
|
|
227
228
|
writeFileSync(join(wtSliceDir, 'S01-SUMMARY.md'), '# S01 Summary');
|
|
@@ -229,11 +230,12 @@ describe('worktree-sync-milestones', async () => {
|
|
|
229
230
|
writeFileSync(join(wtTasksDir, 'T02-SUMMARY.md'), '# T02 Summary');
|
|
230
231
|
|
|
231
232
|
// Main project root starts with only the milestone directory (no slices yet)
|
|
232
|
-
mkdirSync(join(mainBase, '.gsd', 'milestones', '
|
|
233
|
+
mkdirSync(join(mainBase, '.gsd', 'milestones', 'M002'), { recursive: true });
|
|
233
234
|
|
|
235
|
+
// Pass M001 as milestoneId (the one being merged/skipped), M002 should still sync
|
|
234
236
|
const { synced } = syncWorktreeStateBack(mainBase, wtBase, 'M001');
|
|
235
237
|
|
|
236
|
-
const mainSliceDir = join(mainBase, '.gsd', 'milestones', '
|
|
238
|
+
const mainSliceDir = join(mainBase, '.gsd', 'milestones', 'M002', 'slices', 'S01');
|
|
237
239
|
const mainTasksDir = join(mainSliceDir, 'tasks');
|
|
238
240
|
|
|
239
241
|
assert.ok(
|
|
@@ -341,16 +343,16 @@ describe('worktree-sync-milestones', async () => {
|
|
|
341
343
|
'M002 missing in main before sync',
|
|
342
344
|
);
|
|
343
345
|
|
|
344
|
-
// Sync with milestoneId = M001 (the current milestone)
|
|
346
|
+
// Sync with milestoneId = M001 (the current milestone being merged — skipped)
|
|
345
347
|
const { synced } = syncWorktreeStateBack(mainBase, wtBase, 'M001');
|
|
346
348
|
|
|
347
|
-
// M001 should be
|
|
349
|
+
// M001 should be SKIPPED (current milestone being merged — #3641)
|
|
348
350
|
assert.ok(
|
|
349
|
-
existsSync(join(mainBase, '.gsd', 'milestones', 'M001', 'M001-SUMMARY.md')),
|
|
350
|
-
'M001 SUMMARY synced to
|
|
351
|
+
!existsSync(join(mainBase, '.gsd', 'milestones', 'M001', 'M001-SUMMARY.md')),
|
|
352
|
+
'M001 SUMMARY NOT synced (current milestone skipped to prevent merge conflicts)',
|
|
351
353
|
);
|
|
352
354
|
|
|
353
|
-
// M002 should
|
|
355
|
+
// M002 should be synced (other milestone — not skipped)
|
|
354
356
|
assert.ok(
|
|
355
357
|
existsSync(join(mainBase, '.gsd', 'milestones', 'M002-abc123', 'M002-abc123-CONTEXT.md')),
|
|
356
358
|
'M002 CONTEXT synced to main (next-milestone fix)',
|
|
@@ -407,20 +409,17 @@ describe('worktree-sync-milestones', async () => {
|
|
|
407
409
|
writeFileSync(join(wtBase, '.gsd', 'REQUIREMENTS.md'), '# Requirements\n## R001-R089\n## R090 — SCIM\n## R091 — WebAuthn');
|
|
408
410
|
writeFileSync(join(wtBase, '.gsd', 'PROJECT.md'), '# Project\nMilestones: M001-M007');
|
|
409
411
|
|
|
410
|
-
// Sync with milestoneId = M006 (the completing milestone)
|
|
412
|
+
// Sync with milestoneId = M006 (the completing milestone — skipped by sync)
|
|
411
413
|
const { synced } = syncWorktreeStateBack(mainBase, wtBase, 'M006-589wvh');
|
|
412
414
|
|
|
413
|
-
//
|
|
414
|
-
|
|
415
|
-
existsSync(join(mainBase, '.gsd', 'milestones', 'M006-589wvh', 'M006-589wvh-SUMMARY.md')),
|
|
416
|
-
'M006 SUMMARY synced',
|
|
417
|
-
);
|
|
415
|
+
// M006 is the current milestone being merged — it should be SKIPPED (#3641)
|
|
416
|
+
// Its files are already in the milestone branch and would conflict with squash merge.
|
|
418
417
|
assert.ok(
|
|
419
|
-
existsSync(join(mainBase, '.gsd', 'milestones', 'M006-589wvh', '
|
|
420
|
-
'M006
|
|
418
|
+
!existsSync(join(mainBase, '.gsd', 'milestones', 'M006-589wvh', 'M006-589wvh-SUMMARY.md')),
|
|
419
|
+
'M006 SUMMARY NOT synced (current milestone skipped)',
|
|
421
420
|
);
|
|
422
421
|
|
|
423
|
-
// Verify M007 artifacts synced (the critical fix)
|
|
422
|
+
// Verify M007 artifacts synced (the critical fix — other milestones still sync)
|
|
424
423
|
assert.ok(
|
|
425
424
|
existsSync(join(mainBase, '.gsd', 'milestones', 'M007-wortc8', 'M007-wortc8-CONTEXT.md')),
|
|
426
425
|
'M007 CONTEXT synced to main (next-milestone)',
|
|
@@ -47,7 +47,8 @@ function writeFile(dir: string, relativePath: string, content: string): void {
|
|
|
47
47
|
test("syncWorktreeStateBack copies task summaries from tasks/ subdirectory (#1678)", () => {
|
|
48
48
|
const mainBase = makeTempDir("main");
|
|
49
49
|
const wtBase = makeTempDir("wt");
|
|
50
|
-
const
|
|
50
|
+
const currentMid = "M000"; // milestone being merged (skipped by sync)
|
|
51
|
+
const mid = "M001"; // other milestone that should be synced
|
|
51
52
|
|
|
52
53
|
try {
|
|
53
54
|
// Set up worktree with milestone, slice, and task files
|
|
@@ -64,8 +65,8 @@ test("syncWorktreeStateBack copies task summaries from tasks/ subdirectory (#167
|
|
|
64
65
|
// Set up main with empty .gsd
|
|
65
66
|
mkdirSync(join(mainBase, ".gsd"), { recursive: true });
|
|
66
67
|
|
|
67
|
-
// Run sync
|
|
68
|
-
const result = syncWorktreeStateBack(mainBase, wtBase,
|
|
68
|
+
// Run sync — currentMid is skipped, mid (M001) should be synced
|
|
69
|
+
const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
|
|
69
70
|
|
|
70
71
|
// Verify milestone-level files synced
|
|
71
72
|
assert.ok(
|
|
@@ -126,7 +127,8 @@ test("syncWorktreeStateBack copies task summaries from tasks/ subdirectory (#167
|
|
|
126
127
|
test("syncWorktreeStateBack handles multiple slices with tasks (#1678)", () => {
|
|
127
128
|
const mainBase = makeTempDir("main");
|
|
128
129
|
const wtBase = makeTempDir("wt");
|
|
129
|
-
const
|
|
130
|
+
const currentMid = "M000"; // milestone being merged (skipped)
|
|
131
|
+
const mid = "M002"; // other milestone that should be synced
|
|
130
132
|
|
|
131
133
|
try {
|
|
132
134
|
// Set up two slices with tasks
|
|
@@ -139,7 +141,7 @@ test("syncWorktreeStateBack handles multiple slices with tasks (#1678)", () => {
|
|
|
139
141
|
|
|
140
142
|
mkdirSync(join(mainBase, ".gsd"), { recursive: true });
|
|
141
143
|
|
|
142
|
-
const result = syncWorktreeStateBack(mainBase, wtBase,
|
|
144
|
+
const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
|
|
143
145
|
|
|
144
146
|
// All task summaries from both slices should be synced
|
|
145
147
|
assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`)));
|
|
@@ -160,7 +162,8 @@ test("syncWorktreeStateBack handles multiple slices with tasks (#1678)", () => {
|
|
|
160
162
|
test("syncWorktreeStateBack handles slices without tasks/ directory", () => {
|
|
161
163
|
const mainBase = makeTempDir("main");
|
|
162
164
|
const wtBase = makeTempDir("wt");
|
|
163
|
-
const
|
|
165
|
+
const currentMid = "M000"; // milestone being merged (skipped)
|
|
166
|
+
const mid = "M003"; // other milestone that should be synced
|
|
164
167
|
|
|
165
168
|
try {
|
|
166
169
|
// Slice with no tasks/ subdirectory (legitimate case: pre-planning)
|
|
@@ -168,7 +171,7 @@ test("syncWorktreeStateBack handles slices without tasks/ directory", () => {
|
|
|
168
171
|
|
|
169
172
|
mkdirSync(join(mainBase, ".gsd"), { recursive: true });
|
|
170
173
|
|
|
171
|
-
const result = syncWorktreeStateBack(mainBase, wtBase,
|
|
174
|
+
const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
|
|
172
175
|
|
|
173
176
|
// Should sync the slice file without errors
|
|
174
177
|
assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/S01-RESEARCH.md`)));
|
|
@@ -183,7 +186,8 @@ test("syncWorktreeStateBack handles slices without tasks/ directory", () => {
|
|
|
183
186
|
test("syncWorktreeStateBack ignores non-md files in tasks/", () => {
|
|
184
187
|
const mainBase = makeTempDir("main");
|
|
185
188
|
const wtBase = makeTempDir("wt");
|
|
186
|
-
const
|
|
189
|
+
const currentMid = "M000"; // milestone being merged (skipped)
|
|
190
|
+
const mid = "M004"; // other milestone that should be synced
|
|
187
191
|
|
|
188
192
|
try {
|
|
189
193
|
writeFile(wtBase, `.gsd/milestones/${mid}/slices/S01/S01-PLAN.md`, "# Plan\n");
|
|
@@ -194,7 +198,7 @@ test("syncWorktreeStateBack ignores non-md files in tasks/", () => {
|
|
|
194
198
|
|
|
195
199
|
mkdirSync(join(mainBase, ".gsd"), { recursive: true });
|
|
196
200
|
|
|
197
|
-
const result = syncWorktreeStateBack(mainBase, wtBase,
|
|
201
|
+
const result = syncWorktreeStateBack(mainBase, wtBase, currentMid);
|
|
198
202
|
|
|
199
203
|
// Only .md files should be synced
|
|
200
204
|
assert.ok(existsSync(join(mainBase, `.gsd/milestones/${mid}/slices/S01/tasks/T01-SUMMARY.md`)));
|
|
@@ -14,9 +14,11 @@ import {
|
|
|
14
14
|
resolveProjectRoot,
|
|
15
15
|
setActiveMilestoneId,
|
|
16
16
|
SLICE_BRANCH_RE,
|
|
17
|
+
_resetServiceCache,
|
|
17
18
|
} from "../worktree.ts";
|
|
18
19
|
import { readIntegrationBranch } from "../git-service.ts";
|
|
19
20
|
import { _resetHasChangesCache } from "../native-git-bridge.ts";
|
|
21
|
+
import { _clearGsdRootCache } from "../paths.ts";
|
|
20
22
|
import { describe, test } from 'node:test';
|
|
21
23
|
import assert from 'node:assert/strict';
|
|
22
24
|
|
|
@@ -165,15 +167,30 @@ describe('worktree', async () => {
|
|
|
165
167
|
run("git checkout -b my-feature", repo);
|
|
166
168
|
captureIntegrationBranch(repo, "M001");
|
|
167
169
|
|
|
168
|
-
//
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
170
|
+
// Isolate from user's global preferences (which may have git.main_branch set).
|
|
171
|
+
// Reset caches so getService() creates a fresh instance with empty preferences.
|
|
172
|
+
const originalHome = process.env.HOME;
|
|
173
|
+
const fakeHome = mkdtempSync(join(tmpdir(), "gsd-fake-home-"));
|
|
174
|
+
process.env.HOME = fakeHome;
|
|
175
|
+
_clearGsdRootCache();
|
|
176
|
+
_resetServiceCache();
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
// Without milestone set, getMainBranch returns "main"
|
|
180
|
+
setActiveMilestoneId(repo, null);
|
|
181
|
+
assert.deepStrictEqual(getMainBranch(repo), "main",
|
|
182
|
+
"getMainBranch returns main without milestone set");
|
|
183
|
+
|
|
184
|
+
// With milestone set, getMainBranch returns feature branch
|
|
185
|
+
setActiveMilestoneId(repo, "M001");
|
|
186
|
+
assert.deepStrictEqual(getMainBranch(repo), "my-feature",
|
|
187
|
+
"getMainBranch returns integration branch with milestone set");
|
|
188
|
+
} finally {
|
|
189
|
+
process.env.HOME = originalHome;
|
|
190
|
+
_clearGsdRootCache();
|
|
191
|
+
_resetServiceCache();
|
|
192
|
+
rmSync(fakeHome, { recursive: true, force: true });
|
|
193
|
+
}
|
|
177
194
|
|
|
178
195
|
rmSync(repo, { recursive: true, force: true });
|
|
179
196
|
}
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import test from 'node:test';
|
|
13
13
|
import assert from 'node:assert/strict';
|
|
14
14
|
import {
|
|
15
|
+
isDepthConfirmationAnswer,
|
|
15
16
|
shouldBlockContextWrite,
|
|
16
17
|
isDepthVerified,
|
|
17
18
|
isQueuePhaseActive,
|
|
@@ -117,9 +118,9 @@ test('write-gate: regex does not match slice context files (S01-CONTEXT.md)', ()
|
|
|
117
118
|
assert.strictEqual(result.block, false, 'S01-CONTEXT.md should not be blocked');
|
|
118
119
|
});
|
|
119
120
|
|
|
120
|
-
// ─── Scenario 7: Error message contains actionable instruction ──
|
|
121
|
+
// ─── Scenario 7: Error message contains actionable instruction and anti-bypass language ──
|
|
121
122
|
|
|
122
|
-
test('write-gate: blocked reason contains depth_verification keyword', () => {
|
|
123
|
+
test('write-gate: blocked reason contains depth_verification keyword and anti-bypass language', () => {
|
|
123
124
|
const result = shouldBlockContextWrite(
|
|
124
125
|
'write',
|
|
125
126
|
'.gsd/milestones/M999/M999-CONTEXT.md',
|
|
@@ -129,6 +130,8 @@ test('write-gate: blocked reason contains depth_verification keyword', () => {
|
|
|
129
130
|
assert.strictEqual(result.block, true);
|
|
130
131
|
assert.ok(result.reason!.includes('depth_verification'), 'reason should mention depth_verification question id');
|
|
131
132
|
assert.ok(result.reason!.includes('ask_user_questions'), 'reason should mention ask_user_questions tool');
|
|
133
|
+
assert.ok(result.reason!.includes('MUST NOT'), 'reason should include anti-bypass language');
|
|
134
|
+
assert.ok(result.reason!.includes('(Recommended)'), 'reason should specify the required confirmation option');
|
|
132
135
|
});
|
|
133
136
|
|
|
134
137
|
// ─── Scenario 8: Queue mode blocks CONTEXT.md write without depth verification ──
|
|
@@ -191,3 +194,125 @@ test('write-gate: markDepthVerified unblocks queue-mode writes when milestoneId
|
|
|
191
194
|
|
|
192
195
|
clearDiscussionFlowState();
|
|
193
196
|
});
|
|
197
|
+
|
|
198
|
+
// ─── Standard options fixture used across depth confirmation tests ──
|
|
199
|
+
|
|
200
|
+
const STANDARD_OPTIONS = [
|
|
201
|
+
{ label: 'Yes, you got it (Recommended)' },
|
|
202
|
+
{ label: 'Not quite — let me clarify' },
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
// ─── Scenario 11: accepts first option (confirmation) with structural validation ──
|
|
206
|
+
|
|
207
|
+
test('write-gate: isDepthConfirmationAnswer accepts first option with options present', () => {
|
|
208
|
+
assert.strictEqual(
|
|
209
|
+
isDepthConfirmationAnswer('Yes, you got it (Recommended)', STANDARD_OPTIONS),
|
|
210
|
+
true,
|
|
211
|
+
'should accept exact match of first option label',
|
|
212
|
+
);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// ─── Scenario 12: rejects second option (decline) ──
|
|
216
|
+
|
|
217
|
+
test('write-gate: isDepthConfirmationAnswer rejects decline option', () => {
|
|
218
|
+
assert.strictEqual(
|
|
219
|
+
isDepthConfirmationAnswer('Not quite — let me clarify', STANDARD_OPTIONS),
|
|
220
|
+
false,
|
|
221
|
+
'should reject the clarification option',
|
|
222
|
+
);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
// ─── Scenario 13: rejects "None of the above" ──
|
|
226
|
+
|
|
227
|
+
test('write-gate: isDepthConfirmationAnswer rejects None of the above', () => {
|
|
228
|
+
assert.strictEqual(
|
|
229
|
+
isDepthConfirmationAnswer('None of the above', STANDARD_OPTIONS),
|
|
230
|
+
false,
|
|
231
|
+
'should reject None of the above',
|
|
232
|
+
);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
// ─── Scenario 14: rejects garbage/empty input ──
|
|
236
|
+
|
|
237
|
+
test('write-gate: isDepthConfirmationAnswer rejects garbage and edge cases', () => {
|
|
238
|
+
assert.strictEqual(isDepthConfirmationAnswer('discord', STANDARD_OPTIONS), false, 'garbage string');
|
|
239
|
+
assert.strictEqual(isDepthConfirmationAnswer('', STANDARD_OPTIONS), false, 'empty string');
|
|
240
|
+
assert.strictEqual(isDepthConfirmationAnswer(undefined, STANDARD_OPTIONS), false, 'undefined');
|
|
241
|
+
assert.strictEqual(isDepthConfirmationAnswer(null, STANDARD_OPTIONS), false, 'null');
|
|
242
|
+
assert.strictEqual(isDepthConfirmationAnswer(42, STANDARD_OPTIONS), false, 'number');
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
// ─── Scenario 15: handles array-wrapped selection ──
|
|
246
|
+
|
|
247
|
+
test('write-gate: isDepthConfirmationAnswer handles array-wrapped selected value', () => {
|
|
248
|
+
assert.strictEqual(
|
|
249
|
+
isDepthConfirmationAnswer(['Yes, you got it (Recommended)'], STANDARD_OPTIONS),
|
|
250
|
+
true,
|
|
251
|
+
'should accept array-wrapped confirmation',
|
|
252
|
+
);
|
|
253
|
+
assert.strictEqual(
|
|
254
|
+
isDepthConfirmationAnswer(['Not quite — let me clarify'], STANDARD_OPTIONS),
|
|
255
|
+
false,
|
|
256
|
+
'should reject array-wrapped decline',
|
|
257
|
+
);
|
|
258
|
+
assert.strictEqual(
|
|
259
|
+
isDepthConfirmationAnswer([], STANDARD_OPTIONS),
|
|
260
|
+
false,
|
|
261
|
+
'should reject empty array',
|
|
262
|
+
);
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
// ─── Scenario 16: rejects free-form "Other" text that contains "(Recommended)" ──
|
|
266
|
+
|
|
267
|
+
test('write-gate: isDepthConfirmationAnswer rejects free-form text containing Recommended', () => {
|
|
268
|
+
assert.strictEqual(
|
|
269
|
+
isDepthConfirmationAnswer('I think this is fine (Recommended)', STANDARD_OPTIONS),
|
|
270
|
+
false,
|
|
271
|
+
'free-form text with (Recommended) substring must not unlock gate',
|
|
272
|
+
);
|
|
273
|
+
assert.strictEqual(
|
|
274
|
+
isDepthConfirmationAnswer('(Recommended)', STANDARD_OPTIONS),
|
|
275
|
+
false,
|
|
276
|
+
'bare (Recommended) string must not unlock gate',
|
|
277
|
+
);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
// ─── Scenario 17: works with changed label text (decoupled from specific copy) ──
|
|
281
|
+
|
|
282
|
+
test('write-gate: isDepthConfirmationAnswer works with different label text', () => {
|
|
283
|
+
const customOptions = [
|
|
284
|
+
{ label: 'Looks good, proceed' },
|
|
285
|
+
{ label: 'Needs more discussion' },
|
|
286
|
+
];
|
|
287
|
+
assert.strictEqual(
|
|
288
|
+
isDepthConfirmationAnswer('Looks good, proceed', customOptions),
|
|
289
|
+
true,
|
|
290
|
+
'should accept first option regardless of label text',
|
|
291
|
+
);
|
|
292
|
+
assert.strictEqual(
|
|
293
|
+
isDepthConfirmationAnswer('Needs more discussion', customOptions),
|
|
294
|
+
false,
|
|
295
|
+
'should reject second option',
|
|
296
|
+
);
|
|
297
|
+
// Old label should NOT work with new options
|
|
298
|
+
assert.strictEqual(
|
|
299
|
+
isDepthConfirmationAnswer('Yes, you got it (Recommended)', customOptions),
|
|
300
|
+
false,
|
|
301
|
+
'old label text should not match new options',
|
|
302
|
+
);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
// ─── Scenario 18: fallback when options not available ──
|
|
306
|
+
|
|
307
|
+
test('write-gate: isDepthConfirmationAnswer falls back to (Recommended) match without options', () => {
|
|
308
|
+
assert.strictEqual(
|
|
309
|
+
isDepthConfirmationAnswer('Yes, you got it (Recommended)'),
|
|
310
|
+
true,
|
|
311
|
+
'should accept via fallback when no options provided',
|
|
312
|
+
);
|
|
313
|
+
assert.strictEqual(
|
|
314
|
+
isDepthConfirmationAnswer('Not quite — let me clarify'),
|
|
315
|
+
false,
|
|
316
|
+
'should reject non-Recommended via fallback',
|
|
317
|
+
);
|
|
318
|
+
});
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for #3441: guided flow must treat a roadmap with zero
|
|
3
|
+
* parseable slices the same as no roadmap — offer "Create roadmap" not "Go auto".
|
|
4
|
+
*/
|
|
5
|
+
import { test } from "node:test";
|
|
6
|
+
import assert from "node:assert/strict";
|
|
7
|
+
import { readFileSync } from "node:fs";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
|
|
10
|
+
test("guided-flow checks roadmap slice count before offering auto (#3441)", () => {
|
|
11
|
+
const src = readFileSync(
|
|
12
|
+
join(import.meta.dirname, "..", "guided-flow.ts"),
|
|
13
|
+
"utf-8",
|
|
14
|
+
);
|
|
15
|
+
assert.ok(
|
|
16
|
+
src.includes("roadmapHasSlices") || src.includes("parseRoadmapSlices"),
|
|
17
|
+
"Guided flow must parse roadmap for slices before deciding which options to show",
|
|
18
|
+
);
|
|
19
|
+
});
|
|
@@ -23,7 +23,7 @@ import { invalidateStateCache } from "../state.js";
|
|
|
23
23
|
import { renderAllProjections, stripIdPrefix } from "../workflow-projections.js";
|
|
24
24
|
import { writeManifest } from "../workflow-manifest.js";
|
|
25
25
|
import { appendEvent } from "../workflow-events.js";
|
|
26
|
-
import { logWarning } from "../workflow-logger.js";
|
|
26
|
+
import { logWarning, logError } from "../workflow-logger.js";
|
|
27
27
|
|
|
28
28
|
export interface CompleteMilestoneParams {
|
|
29
29
|
milestoneId: string;
|
|
@@ -218,9 +218,19 @@ export async function handleCompleteMilestone(
|
|
|
218
218
|
clearParseCache();
|
|
219
219
|
|
|
220
220
|
// ── Post-mutation hook: projections, manifest, event log ───────────────
|
|
221
|
+
// Separate try/catch per step so a projection failure doesn't prevent
|
|
222
|
+
// the event log entry (critical for worktree reconciliation).
|
|
221
223
|
try {
|
|
222
224
|
await renderAllProjections(basePath, params.milestoneId);
|
|
225
|
+
} catch (projErr) {
|
|
226
|
+
logWarning("tool", `complete-milestone projection warning: ${(projErr as Error).message}`);
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
223
229
|
writeManifest(basePath);
|
|
230
|
+
} catch (mfErr) {
|
|
231
|
+
logWarning("tool", `complete-milestone manifest warning: ${(mfErr as Error).message}`);
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
224
234
|
appendEvent(basePath, {
|
|
225
235
|
cmd: "complete-milestone",
|
|
226
236
|
params: { milestoneId: params.milestoneId },
|
|
@@ -229,8 +239,8 @@ export async function handleCompleteMilestone(
|
|
|
229
239
|
actor_name: params.actorName,
|
|
230
240
|
trigger_reason: params.triggerReason,
|
|
231
241
|
});
|
|
232
|
-
} catch (
|
|
233
|
-
|
|
242
|
+
} catch (eventErr) {
|
|
243
|
+
logError("tool", `complete-milestone event log FAILED — completion invisible to reconciliation`, { error: (eventErr as Error).message });
|
|
234
244
|
}
|
|
235
245
|
|
|
236
246
|
return {
|
|
@@ -30,7 +30,7 @@ import { renderRoadmapCheckboxes } from "../markdown-renderer.js";
|
|
|
30
30
|
import { renderAllProjections } from "../workflow-projections.js";
|
|
31
31
|
import { writeManifest } from "../workflow-manifest.js";
|
|
32
32
|
import { appendEvent } from "../workflow-events.js";
|
|
33
|
-
import { logWarning } from "../workflow-logger.js";
|
|
33
|
+
import { logWarning, logError } from "../workflow-logger.js";
|
|
34
34
|
|
|
35
35
|
export interface CompleteSliceResult {
|
|
36
36
|
sliceId: string;
|
|
@@ -233,8 +233,18 @@ export async function handleCompleteSlice(
|
|
|
233
233
|
return { error: ownershipErr };
|
|
234
234
|
}
|
|
235
235
|
|
|
236
|
+
// ── Verification content gate (#3580) ──────────────────────────────────
|
|
237
|
+
// Reject completion when the provided verification/UAT clearly indicates
|
|
238
|
+
// the slice is blocked or failed. Prevents prompt regressions from
|
|
239
|
+
// silently advancing blocked slices.
|
|
240
|
+
const BLOCKED_SIGNALS = /\b(status:\s*blocked|verification_result:\s*failed|slice is blocked|cannot complete|verification failed)\b/i;
|
|
241
|
+
if (BLOCKED_SIGNALS.test(params.verification || "") || BLOCKED_SIGNALS.test(params.uatContent || "")) {
|
|
242
|
+
return { error: `slice verification indicates blocked/failed state — do not complete a slice that has not passed verification. Address the blockers and re-verify first.` };
|
|
243
|
+
}
|
|
244
|
+
|
|
236
245
|
// ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
|
|
237
246
|
const completedAt = new Date().toISOString();
|
|
247
|
+
const originalSliceStatus = getSlice(params.milestoneId, params.sliceId)?.status ?? "pending";
|
|
238
248
|
let guardError: string | null = null;
|
|
239
249
|
|
|
240
250
|
transaction(() => {
|
|
@@ -268,8 +278,8 @@ export async function handleCompleteSlice(
|
|
|
268
278
|
}
|
|
269
279
|
|
|
270
280
|
// All guards passed — perform writes
|
|
271
|
-
insertMilestone({ id: params.milestoneId });
|
|
272
|
-
insertSlice({ id: params.sliceId, milestoneId: params.milestoneId });
|
|
281
|
+
insertMilestone({ id: params.milestoneId, title: params.milestoneId });
|
|
282
|
+
insertSlice({ id: params.sliceId, milestoneId: params.milestoneId, title: params.sliceId });
|
|
273
283
|
updateSliceStatus(params.milestoneId, params.sliceId, "complete", completedAt);
|
|
274
284
|
});
|
|
275
285
|
|
|
@@ -312,7 +322,7 @@ export async function handleCompleteSlice(
|
|
|
312
322
|
} catch (renderErr) {
|
|
313
323
|
// Disk render failed — roll back DB status so state stays consistent
|
|
314
324
|
logWarning("tool", `complete_slice — disk render failed for ${params.milestoneId}/${params.sliceId}, rolling back DB status`, { error: (renderErr as Error).message });
|
|
315
|
-
updateSliceStatus(params.milestoneId, params.sliceId,
|
|
325
|
+
updateSliceStatus(params.milestoneId, params.sliceId, originalSliceStatus);
|
|
316
326
|
invalidateStateCache();
|
|
317
327
|
return { error: `disk render failed: ${(renderErr as Error).message}` };
|
|
318
328
|
}
|
|
@@ -326,9 +336,19 @@ export async function handleCompleteSlice(
|
|
|
326
336
|
clearParseCache();
|
|
327
337
|
|
|
328
338
|
// ── Post-mutation hook: projections, manifest, event log ───────────────
|
|
339
|
+
// Separate try/catch per step so a projection failure doesn't prevent
|
|
340
|
+
// the event log entry (critical for worktree reconciliation).
|
|
329
341
|
try {
|
|
330
342
|
await renderAllProjections(basePath, params.milestoneId);
|
|
343
|
+
} catch (projErr) {
|
|
344
|
+
logWarning("tool", `complete-slice projection warning for ${params.milestoneId}/${params.sliceId}: ${(projErr as Error).message}`);
|
|
345
|
+
}
|
|
346
|
+
try {
|
|
331
347
|
writeManifest(basePath);
|
|
348
|
+
} catch (mfErr) {
|
|
349
|
+
logWarning("tool", `complete-slice manifest warning: ${(mfErr as Error).message}`);
|
|
350
|
+
}
|
|
351
|
+
try {
|
|
332
352
|
appendEvent(basePath, {
|
|
333
353
|
cmd: "complete-slice",
|
|
334
354
|
params: { milestoneId: params.milestoneId, sliceId: params.sliceId },
|
|
@@ -337,8 +357,8 @@ export async function handleCompleteSlice(
|
|
|
337
357
|
actor_name: params.actorName,
|
|
338
358
|
trigger_reason: params.triggerReason,
|
|
339
359
|
});
|
|
340
|
-
} catch (
|
|
341
|
-
|
|
360
|
+
} catch (eventErr) {
|
|
361
|
+
logError("tool", `complete-slice event log FAILED — completion invisible to reconciliation`, { error: (eventErr as Error).message });
|
|
342
362
|
}
|
|
343
363
|
|
|
344
364
|
return {
|
|
@@ -33,7 +33,7 @@ import { renderPlanCheckboxes } from "../markdown-renderer.js";
|
|
|
33
33
|
import { renderAllProjections, renderSummaryContent } from "../workflow-projections.js";
|
|
34
34
|
import { writeManifest } from "../workflow-manifest.js";
|
|
35
35
|
import { appendEvent } from "../workflow-events.js";
|
|
36
|
-
import { logWarning } from "../workflow-logger.js";
|
|
36
|
+
import { logWarning, logError } from "../workflow-logger.js";
|
|
37
37
|
|
|
38
38
|
export interface CompleteTaskResult {
|
|
39
39
|
taskId: string;
|
|
@@ -44,6 +44,18 @@ export interface CompleteTaskResult {
|
|
|
44
44
|
|
|
45
45
|
import type { TaskRow } from "../gsd-db.js";
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Normalize a list parameter that may arrive as a string (newline-delimited
|
|
49
|
+
* bullet list from the LLM) into a string array (#3361).
|
|
50
|
+
*/
|
|
51
|
+
function normalizeListParam(value: unknown): string[] {
|
|
52
|
+
if (Array.isArray(value)) return value.map(String);
|
|
53
|
+
if (typeof value === "string" && value.trim()) {
|
|
54
|
+
return value.split(/\n/).map(s => s.replace(/^[\s\-*•]+/, "").trim()).filter(Boolean);
|
|
55
|
+
}
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
|
|
47
59
|
/**
|
|
48
60
|
* Build a TaskRow-shaped object from CompleteTaskParams so the unified
|
|
49
61
|
* renderSummaryContent() can be used at completion time (#2720).
|
|
@@ -63,8 +75,8 @@ function paramsToTaskRow(params: CompleteTaskParams, completedAt: string): TaskR
|
|
|
63
75
|
blocker_discovered: params.blockerDiscovered ?? false,
|
|
64
76
|
deviations: params.deviations ?? "",
|
|
65
77
|
known_issues: params.knownIssues ?? "",
|
|
66
|
-
key_files: params.keyFiles
|
|
67
|
-
key_decisions: params.keyDecisions
|
|
78
|
+
key_files: normalizeListParam(params.keyFiles),
|
|
79
|
+
key_decisions: normalizeListParam(params.keyDecisions),
|
|
68
80
|
full_summary_md: "",
|
|
69
81
|
description: "",
|
|
70
82
|
estimate: "",
|
|
@@ -140,8 +152,8 @@ export async function handleCompleteTask(
|
|
|
140
152
|
}
|
|
141
153
|
|
|
142
154
|
// All guards passed — perform writes
|
|
143
|
-
insertMilestone({ id: params.milestoneId });
|
|
144
|
-
insertSlice({ id: params.sliceId, milestoneId: params.milestoneId });
|
|
155
|
+
insertMilestone({ id: params.milestoneId, title: params.milestoneId });
|
|
156
|
+
insertSlice({ id: params.sliceId, milestoneId: params.milestoneId, title: params.sliceId });
|
|
145
157
|
insertTask({
|
|
146
158
|
id: params.taskId,
|
|
147
159
|
sliceId: params.sliceId,
|
|
@@ -230,9 +242,19 @@ export async function handleCompleteTask(
|
|
|
230
242
|
clearParseCache();
|
|
231
243
|
|
|
232
244
|
// ── Post-mutation hook: projections, manifest, event log ───────────────
|
|
245
|
+
// Separate try/catch per step so a projection failure doesn't prevent
|
|
246
|
+
// the event log entry (critical for worktree reconciliation).
|
|
233
247
|
try {
|
|
234
248
|
await renderAllProjections(basePath, params.milestoneId);
|
|
249
|
+
} catch (projErr) {
|
|
250
|
+
logWarning("tool", `complete-task projection warning: ${(projErr as Error).message}`);
|
|
251
|
+
}
|
|
252
|
+
try {
|
|
235
253
|
writeManifest(basePath);
|
|
254
|
+
} catch (mfErr) {
|
|
255
|
+
logWarning("tool", `complete-task manifest warning: ${(mfErr as Error).message}`);
|
|
256
|
+
}
|
|
257
|
+
try {
|
|
236
258
|
appendEvent(basePath, {
|
|
237
259
|
cmd: "complete-task",
|
|
238
260
|
params: { milestoneId: params.milestoneId, sliceId: params.sliceId, taskId: params.taskId },
|
|
@@ -241,8 +263,8 @@ export async function handleCompleteTask(
|
|
|
241
263
|
actor_name: params.actorName,
|
|
242
264
|
trigger_reason: params.triggerReason,
|
|
243
265
|
});
|
|
244
|
-
} catch (
|
|
245
|
-
|
|
266
|
+
} catch (eventErr) {
|
|
267
|
+
logError("tool", `complete-task event log FAILED — completion invisible to reconciliation`, { error: (eventErr as Error).message });
|
|
246
268
|
}
|
|
247
269
|
|
|
248
270
|
return {
|
|
@@ -48,13 +48,13 @@ export interface PlanMilestoneParams {
|
|
|
48
48
|
keyRisks?: Array<{ risk: string; whyItMatters: string }>;
|
|
49
49
|
/** @optional — defaults to [] when omitted */
|
|
50
50
|
proofStrategy?: Array<{ riskOrUnknown: string; retireIn: string; whatWillBeProven: string }>;
|
|
51
|
-
/** @optional — defaults to "
|
|
51
|
+
/** @optional — defaults to "" when omitted */
|
|
52
52
|
verificationContract?: string;
|
|
53
|
-
/** @optional — defaults to "
|
|
53
|
+
/** @optional — defaults to "" when omitted */
|
|
54
54
|
verificationIntegration?: string;
|
|
55
|
-
/** @optional — defaults to "
|
|
55
|
+
/** @optional — defaults to "" when omitted */
|
|
56
56
|
verificationOperational?: string;
|
|
57
|
-
/** @optional — defaults to "
|
|
57
|
+
/** @optional — defaults to "" when omitted */
|
|
58
58
|
verificationUat?: string;
|
|
59
59
|
/** @optional — defaults to [] when omitted */
|
|
60
60
|
definitionOfDone?: string[];
|
|
@@ -168,10 +168,10 @@ function validateParams(params: PlanMilestoneParams): PlanMilestoneParams {
|
|
|
168
168
|
successCriteria: params.successCriteria ? validateStringArray(params.successCriteria, "successCriteria") : [],
|
|
169
169
|
keyRisks: params.keyRisks ? validateRiskEntries(params.keyRisks) : [],
|
|
170
170
|
proofStrategy: params.proofStrategy ? validateProofStrategy(params.proofStrategy) : [],
|
|
171
|
-
verificationContract: params.verificationContract ?? "
|
|
172
|
-
verificationIntegration: params.verificationIntegration ?? "
|
|
173
|
-
verificationOperational: params.verificationOperational ?? "
|
|
174
|
-
verificationUat: params.verificationUat ?? "
|
|
171
|
+
verificationContract: params.verificationContract ?? "",
|
|
172
|
+
verificationIntegration: params.verificationIntegration ?? "",
|
|
173
|
+
verificationOperational: params.verificationOperational ?? "",
|
|
174
|
+
verificationUat: params.verificationUat ?? "",
|
|
175
175
|
definitionOfDone: params.definitionOfDone ? validateStringArray(params.definitionOfDone, "definitionOfDone") : [],
|
|
176
176
|
requirementCoverage: params.requirementCoverage ?? "Not provided.",
|
|
177
177
|
boundaryMapMarkdown: params.boundaryMapMarkdown ?? "Not provided.",
|
|
@@ -256,7 +256,8 @@ export async function handlePlanMilestone(
|
|
|
256
256
|
boundaryMapMarkdown: params.boundaryMapMarkdown,
|
|
257
257
|
});
|
|
258
258
|
|
|
259
|
-
for (
|
|
259
|
+
for (let i = 0; i < params.slices.length; i++) {
|
|
260
|
+
const slice = params.slices[i]!;
|
|
260
261
|
// Preserve completed/done status on re-plan (#2558).
|
|
261
262
|
// Without this, a re-plan after milestone transition would reset
|
|
262
263
|
// already-completed slices back to "pending".
|
|
@@ -272,6 +273,7 @@ export async function handlePlanMilestone(
|
|
|
272
273
|
risk: slice.risk,
|
|
273
274
|
depends: slice.depends,
|
|
274
275
|
demo: slice.demo,
|
|
276
|
+
sequence: i + 1, // Preserve agent-ordered sequence (#3356)
|
|
275
277
|
});
|
|
276
278
|
upsertSlicePlanning(params.milestoneId, slice.sliceId, {
|
|
277
279
|
goal: slice.goal,
|