gsd-pi 2.44.0 → 2.45.0-dev.6b9da3e
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 +30 -12
- package/dist/resources/extensions/gsd/activity-log.js +7 -0
- package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
- package/dist/resources/extensions/gsd/auto/phases.js +37 -36
- package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
- package/dist/resources/extensions/gsd/auto-start.js +31 -2
- package/dist/resources/extensions/gsd/auto-timers.js +57 -3
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +9 -6
- package/dist/resources/extensions/gsd/auto.js +30 -3
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +156 -0
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
- package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
- package/dist/resources/extensions/gsd/commands/handlers/core.js +2 -0
- package/dist/resources/extensions/gsd/commands/handlers/ops.js +10 -0
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
- package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
- package/dist/resources/extensions/gsd/db-writer.js +34 -16
- package/dist/resources/extensions/gsd/doctor.js +8 -0
- package/dist/resources/extensions/gsd/git-service.js +8 -3
- package/dist/resources/extensions/gsd/gsd-db.js +12 -1
- package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
- package/dist/resources/extensions/gsd/preferences.js +9 -1
- package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
- package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/dist/resources/extensions/gsd/prompts/rethink.md +78 -0
- package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
- package/dist/resources/extensions/gsd/repo-identity.js +45 -7
- package/dist/resources/extensions/gsd/rethink.js +115 -0
- package/dist/resources/extensions/gsd/state.js +41 -3
- package/dist/resources/extensions/gsd/tools/plan-slice.js +1 -0
- package/dist/resources/extensions/gsd/tools/plan-task.js +1 -0
- package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -0
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
- package/dist/resources/extensions/gsd/worktree-manager.js +32 -2
- package/dist/resources/extensions/gsd/worktree-resolver.js +6 -0
- package/dist/resources/extensions/mcp-client/index.js +14 -0
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
- 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 +2 -2
- 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 +5 -5
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +5 -5
- 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 +4 -4
- 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 +2 -2
- 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/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/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 +5 -5
- 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 +6 -6
- 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 +6 -6
- 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 +4 -4
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- 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 +8 -8
- package/dist/web/standalone/.next/server/chunks/229.js +1 -1
- package/dist/web/standalone/.next/server/chunks/471.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/4024.11ca5c01938e5948.js +9 -0
- package/dist/web/standalone/.next/static/chunks/{3721.bf31263de6d5fa46.js → 485.243af25f0cdf50d6.js} +2 -2
- 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-6654a8cca61a3d1c.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-0a4cd455ec4197d2.js +1 -0
- package/dist/web/standalone/.next/static/css/dd4ae3f58ac9b600.css +1 -0
- 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/native/dist/stream-process/index.js +2 -2
- package/packages/native/src/__tests__/stream-process.test.mjs +34 -0
- package/packages/native/src/stream-process/index.ts +2 -2
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
- package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
- package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
- package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
- package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts +11 -0
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +20 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
- package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
- package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
- package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
- package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +17 -0
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -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 +8 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
- package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +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 +4 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
- 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 +13 -2
- package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.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 +7 -3
- package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
- package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
- package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
- package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
- package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
- package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
- package/packages/pi-coding-agent/src/core/model-registry.ts +21 -1
- package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
- package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
- package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
- package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
- package/packages/pi-coding-agent/src/main.ts +19 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
- package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
- package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
- package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
- package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
- package/pkg/package.json +1 -1
- package/src/resources/extensions/gsd/activity-log.ts +1 -0
- package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
- package/src/resources/extensions/gsd/auto/phases.ts +46 -48
- package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
- package/src/resources/extensions/gsd/auto-start.ts +39 -2
- package/src/resources/extensions/gsd/auto-timers.ts +64 -3
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +9 -6
- package/src/resources/extensions/gsd/auto.ts +37 -3
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +148 -0
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
- package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
- package/src/resources/extensions/gsd/commands/handlers/core.ts +2 -0
- package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
- package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
- package/src/resources/extensions/gsd/db-writer.ts +39 -17
- package/src/resources/extensions/gsd/doctor.ts +7 -1
- package/src/resources/extensions/gsd/git-service.ts +6 -2
- package/src/resources/extensions/gsd/gsd-db.ts +16 -1
- package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
- package/src/resources/extensions/gsd/preferences.ts +11 -1
- package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
- package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
- package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
- package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
- package/src/resources/extensions/gsd/prompts/rethink.md +78 -0
- package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
- package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
- package/src/resources/extensions/gsd/repo-identity.ts +46 -7
- package/src/resources/extensions/gsd/rethink.ts +154 -0
- package/src/resources/extensions/gsd/state.ts +41 -1
- package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
- package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
- package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
- package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
- package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
- package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
- package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
- package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
- package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
- package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
- package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
- package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
- package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
- package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
- package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
- package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
- package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
- package/src/resources/extensions/gsd/tests/db-writer.test.ts +465 -416
- package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
- package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
- package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +121 -0
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +210 -181
- package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
- package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
- package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
- package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
- package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
- package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
- package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
- package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
- package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
- package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
- package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
- package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
- package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
- package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
- package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
- package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
- package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
- package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
- package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
- package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
- package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
- package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
- package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
- package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
- package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
- package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
- package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
- package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
- package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
- package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
- package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
- package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
- package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +121 -0
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
- package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
- package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
- package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
- package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
- package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
- package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
- package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
- package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
- package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
- package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
- package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
- package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
- package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
- package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
- package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
- package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
- package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
- package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
- package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
- package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
- package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
- package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
- package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
- package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
- package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
- package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
- package/src/resources/extensions/gsd/tests/preferences.test.ts +27 -0
- package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +11 -7
- package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
- package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
- package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
- package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
- package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
- package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
- package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +176 -0
- package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
- package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
- package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
- package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
- package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
- package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
- package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
- package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
- package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
- package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
- package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
- package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
- package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
- package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +108 -0
- package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
- package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
- package/src/resources/extensions/gsd/tests/tool-naming.test.ts +10 -11
- package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
- package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
- package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
- package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
- package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
- package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
- package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
- package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
- package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
- package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
- package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
- package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
- package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
- package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +65 -0
- package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
- package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
- package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
- package/src/resources/extensions/gsd/tools/plan-task.ts +2 -0
- package/src/resources/extensions/gsd/tools/replan-slice.ts +3 -0
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
- package/src/resources/extensions/gsd/worktree-manager.ts +43 -2
- package/src/resources/extensions/gsd/worktree-resolver.ts +7 -0
- package/src/resources/extensions/mcp-client/index.ts +20 -0
- package/dist/web/standalone/.next/static/chunks/4024.0de81b543b28b9fe.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/page-7e9530a7122506c5.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/chunks/webpack-9014b5adb127a98a.js +0 -1
- package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +0 -1
- /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → rzO54ZboyINyEt7cVM_uS}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → rzO54ZboyINyEt7cVM_uS}/_ssgManifest.js +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { describe, test, afterEach } from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
2
3
|
import * as fs from 'node:fs';
|
|
3
4
|
import * as path from 'node:path';
|
|
4
5
|
import * as os from 'node:os';
|
|
@@ -17,8 +18,6 @@ import {
|
|
|
17
18
|
import { handleCompleteSlice } from '../tools/complete-slice.ts';
|
|
18
19
|
import type { CompleteSliceParams } from '../types.ts';
|
|
19
20
|
|
|
20
|
-
const { assertEq, assertTrue, assertMatch, report } = createTestContext();
|
|
21
|
-
|
|
22
21
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
23
22
|
// Helpers
|
|
24
23
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -115,296 +114,262 @@ Run the test suite and verify all assertions pass.
|
|
|
115
114
|
}
|
|
116
115
|
|
|
117
116
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
118
|
-
//
|
|
119
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
120
|
-
|
|
121
|
-
console.log('\n=== complete-slice: schema v6 migration ===');
|
|
122
|
-
{
|
|
123
|
-
const dbPath = tempDbPath();
|
|
124
|
-
openDatabase(dbPath);
|
|
125
|
-
|
|
126
|
-
const adapter = _getAdapter()!;
|
|
127
|
-
|
|
128
|
-
// Verify schema version is current (v10 after M001 planning migrations)
|
|
129
|
-
const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
|
|
130
|
-
assertEq(versionRow?.['v'], 10, 'schema version should be 10');
|
|
131
|
-
|
|
132
|
-
// Verify slices table has full_summary_md and full_uat_md columns
|
|
133
|
-
const cols = adapter.prepare("PRAGMA table_info(slices)").all();
|
|
134
|
-
const colNames = cols.map(c => c['name'] as string);
|
|
135
|
-
assertTrue(colNames.includes('full_summary_md'), 'slices table should have full_summary_md column');
|
|
136
|
-
assertTrue(colNames.includes('full_uat_md'), 'slices table should have full_uat_md column');
|
|
137
|
-
|
|
138
|
-
cleanup(dbPath);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
142
|
-
// complete-slice: getSlice/updateSliceStatus accessors
|
|
143
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
144
|
-
|
|
145
|
-
console.log('\n=== complete-slice: getSlice/updateSliceStatus accessors ===');
|
|
146
|
-
{
|
|
147
|
-
const dbPath = tempDbPath();
|
|
148
|
-
openDatabase(dbPath);
|
|
149
|
-
|
|
150
|
-
// Insert milestone and slice
|
|
151
|
-
insertMilestone({ id: 'M001' });
|
|
152
|
-
insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice', risk: 'high' });
|
|
153
|
-
|
|
154
|
-
// getSlice returns correct row
|
|
155
|
-
const slice = getSlice('M001', 'S01');
|
|
156
|
-
assertTrue(slice !== null, 'getSlice should return non-null for existing slice');
|
|
157
|
-
assertEq(slice!.id, 'S01', 'slice id');
|
|
158
|
-
assertEq(slice!.milestone_id, 'M001', 'slice milestone_id');
|
|
159
|
-
assertEq(slice!.title, 'Test Slice', 'slice title');
|
|
160
|
-
assertEq(slice!.risk, 'high', 'slice risk');
|
|
161
|
-
assertEq(slice!.status, 'pending', 'slice default status should be pending');
|
|
162
|
-
assertEq(slice!.completed_at, null, 'slice completed_at should be null initially');
|
|
163
|
-
assertEq(slice!.full_summary_md, '', 'slice full_summary_md should be empty initially');
|
|
164
|
-
assertEq(slice!.full_uat_md, '', 'slice full_uat_md should be empty initially');
|
|
165
|
-
|
|
166
|
-
// getSlice returns null for non-existent
|
|
167
|
-
const noSlice = getSlice('M001', 'S99');
|
|
168
|
-
assertEq(noSlice, null, 'non-existent slice should return null');
|
|
169
|
-
|
|
170
|
-
// updateSliceStatus changes status and completed_at
|
|
171
|
-
const now = new Date().toISOString();
|
|
172
|
-
updateSliceStatus('M001', 'S01', 'complete', now);
|
|
173
|
-
const updated = getSlice('M001', 'S01');
|
|
174
|
-
assertEq(updated!.status, 'complete', 'slice status should be updated to complete');
|
|
175
|
-
assertEq(updated!.completed_at, now, 'slice completed_at should be set');
|
|
176
|
-
|
|
177
|
-
cleanup(dbPath);
|
|
178
|
-
}
|
|
179
|
-
|
|
117
|
+
// Tests
|
|
180
118
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
181
|
-
// complete-slice: Handler happy path
|
|
182
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
183
|
-
|
|
184
|
-
console.log('\n=== complete-slice: handler happy path ===');
|
|
185
|
-
{
|
|
186
|
-
const dbPath = tempDbPath();
|
|
187
|
-
openDatabase(dbPath);
|
|
188
|
-
|
|
189
|
-
const { basePath, roadmapPath } = createTempProject();
|
|
190
|
-
|
|
191
|
-
// Set up DB state: milestone, slice, 2 complete tasks
|
|
192
|
-
insertMilestone({ id: 'M001' });
|
|
193
|
-
insertSlice({ id: 'S01', milestoneId: 'M001' });
|
|
194
|
-
insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
|
|
195
|
-
insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 2' });
|
|
196
|
-
|
|
197
|
-
const params = makeValidSliceParams();
|
|
198
|
-
const result = await handleCompleteSlice(params, basePath);
|
|
199
|
-
|
|
200
|
-
assertTrue(!('error' in result), 'handler should succeed without error');
|
|
201
|
-
if (!('error' in result)) {
|
|
202
|
-
assertEq(result.sliceId, 'S01', 'result sliceId');
|
|
203
|
-
assertEq(result.milestoneId, 'M001', 'result milestoneId');
|
|
204
|
-
assertTrue(result.summaryPath.endsWith('S01-SUMMARY.md'), 'summaryPath should end with S01-SUMMARY.md');
|
|
205
|
-
assertTrue(result.uatPath.endsWith('S01-UAT.md'), 'uatPath should end with S01-UAT.md');
|
|
206
|
-
|
|
207
|
-
// (a) Verify SUMMARY.md exists on disk with correct YAML frontmatter
|
|
208
|
-
assertTrue(fs.existsSync(result.summaryPath), 'summary file should exist on disk');
|
|
209
|
-
const summaryContent = fs.readFileSync(result.summaryPath, 'utf-8');
|
|
210
|
-
assertMatch(summaryContent, /^---\n/, 'summary should start with YAML frontmatter');
|
|
211
|
-
assertMatch(summaryContent, /id: S01/, 'summary should contain id: S01');
|
|
212
|
-
assertMatch(summaryContent, /parent: M001/, 'summary should contain parent: M001');
|
|
213
|
-
assertMatch(summaryContent, /milestone: M001/, 'summary should contain milestone: M001');
|
|
214
|
-
assertMatch(summaryContent, /blocker_discovered: false/, 'summary should contain blocker_discovered');
|
|
215
|
-
assertMatch(summaryContent, /verification_result: passed/, 'summary should contain verification_result');
|
|
216
|
-
assertMatch(summaryContent, /key_files:/, 'summary should contain key_files');
|
|
217
|
-
assertMatch(summaryContent, /patterns_established:/, 'summary should contain patterns_established');
|
|
218
|
-
assertMatch(summaryContent, /observability_surfaces:/, 'summary should contain observability_surfaces');
|
|
219
|
-
assertMatch(summaryContent, /provides:/, 'summary should contain provides');
|
|
220
|
-
assertMatch(summaryContent, /# S01: Test Slice/, 'summary should have H1 with slice ID and title');
|
|
221
|
-
assertMatch(summaryContent, /\*\*Implemented test slice with full coverage\*\*/, 'summary should have one-liner in bold');
|
|
222
|
-
assertMatch(summaryContent, /## What Happened/, 'summary should have What Happened section');
|
|
223
|
-
assertMatch(summaryContent, /## Verification/, 'summary should have Verification section');
|
|
224
|
-
assertMatch(summaryContent, /## Requirements Advanced/, 'summary should have Requirements Advanced section');
|
|
225
|
-
|
|
226
|
-
// (b) Verify UAT.md exists on disk
|
|
227
|
-
assertTrue(fs.existsSync(result.uatPath), 'UAT file should exist on disk');
|
|
228
|
-
const uatContent = fs.readFileSync(result.uatPath, 'utf-8');
|
|
229
|
-
assertMatch(uatContent, /# S01: Test Slice — UAT/, 'UAT should have correct title');
|
|
230
|
-
assertMatch(uatContent, /Milestone:\*\* M001/, 'UAT should reference milestone');
|
|
231
|
-
assertMatch(uatContent, /Smoke Test/, 'UAT should contain smoke test from params');
|
|
232
|
-
|
|
233
|
-
// (c) Verify roadmap checkbox toggled to [x]
|
|
234
|
-
const roadmapContent = fs.readFileSync(roadmapPath, 'utf-8');
|
|
235
|
-
assertMatch(roadmapContent, /\[x\]\s+\*\*S01:/, 'S01 should be checked in roadmap');
|
|
236
|
-
assertMatch(roadmapContent, /\[ \]\s+\*\*S02:/, 'S02 should still be unchecked in roadmap');
|
|
237
|
-
|
|
238
|
-
// (d) Verify full_summary_md and full_uat_md stored in DB for D004 recovery
|
|
239
|
-
const sliceAfter = getSlice('M001', 'S01');
|
|
240
|
-
assertTrue(sliceAfter !== null, 'slice should exist in DB after handler');
|
|
241
|
-
assertTrue(sliceAfter!.full_summary_md.length > 0, 'full_summary_md should be non-empty in DB');
|
|
242
|
-
assertMatch(sliceAfter!.full_summary_md, /id: S01/, 'full_summary_md should contain frontmatter');
|
|
243
|
-
assertTrue(sliceAfter!.full_uat_md.length > 0, 'full_uat_md should be non-empty in DB');
|
|
244
|
-
assertMatch(sliceAfter!.full_uat_md, /S01: Test Slice — UAT/, 'full_uat_md should contain UAT title');
|
|
245
|
-
|
|
246
|
-
// (e) Verify slice status is complete in DB
|
|
247
|
-
assertEq(sliceAfter!.status, 'complete', 'slice status should be complete in DB');
|
|
248
|
-
assertTrue(sliceAfter!.completed_at !== null, 'completed_at should be set in DB');
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
cleanupDir(basePath);
|
|
252
|
-
cleanup(dbPath);
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
256
|
-
// complete-slice: Handler rejects incomplete tasks
|
|
257
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
258
|
-
|
|
259
|
-
console.log('\n=== complete-slice: handler rejects incomplete tasks ===');
|
|
260
|
-
{
|
|
261
|
-
const dbPath = tempDbPath();
|
|
262
|
-
openDatabase(dbPath);
|
|
263
|
-
|
|
264
|
-
// Insert milestone, slice, 2 tasks — one complete, one pending
|
|
265
|
-
insertMilestone({ id: 'M001' });
|
|
266
|
-
insertSlice({ id: 'S01', milestoneId: 'M001' });
|
|
267
|
-
insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
|
|
268
|
-
insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'pending', title: 'Task 2' });
|
|
269
|
-
|
|
270
|
-
const params = makeValidSliceParams();
|
|
271
|
-
const result = await handleCompleteSlice(params, '/tmp/fake');
|
|
272
|
-
|
|
273
|
-
assertTrue('error' in result, 'should return error when tasks are incomplete');
|
|
274
|
-
if ('error' in result) {
|
|
275
|
-
assertMatch(result.error, /incomplete tasks/, 'error should mention incomplete tasks');
|
|
276
|
-
assertMatch(result.error, /T02/, 'error should mention the specific incomplete task ID');
|
|
277
|
-
}
|
|
278
119
|
|
|
279
|
-
|
|
280
|
-
|
|
120
|
+
describe("complete-slice: schema v6 migration", () => {
|
|
121
|
+
test("schema version and columns exist", () => {
|
|
122
|
+
const dbPath = tempDbPath();
|
|
123
|
+
openDatabase(dbPath);
|
|
124
|
+
|
|
125
|
+
const adapter = _getAdapter()!;
|
|
126
|
+
|
|
127
|
+
// Verify schema version is current (v10 after M001 planning migrations)
|
|
128
|
+
const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
|
|
129
|
+
assert.strictEqual(versionRow?.['v'], 10, 'schema version should be 10');
|
|
130
|
+
|
|
131
|
+
// Verify slices table has full_summary_md and full_uat_md columns
|
|
132
|
+
const cols = adapter.prepare("PRAGMA table_info(slices)").all();
|
|
133
|
+
const colNames = cols.map(c => c['name'] as string);
|
|
134
|
+
assert.ok(colNames.includes('full_summary_md'), 'slices table should have full_summary_md column');
|
|
135
|
+
assert.ok(colNames.includes('full_uat_md'), 'slices table should have full_uat_md column');
|
|
136
|
+
|
|
137
|
+
cleanup(dbPath);
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe("complete-slice: getSlice/updateSliceStatus accessors", () => {
|
|
142
|
+
test("getSlice and updateSliceStatus work correctly", () => {
|
|
143
|
+
const dbPath = tempDbPath();
|
|
144
|
+
openDatabase(dbPath);
|
|
145
|
+
|
|
146
|
+
// Insert milestone and slice
|
|
147
|
+
insertMilestone({ id: 'M001' });
|
|
148
|
+
insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice', risk: 'high' });
|
|
149
|
+
|
|
150
|
+
// getSlice returns correct row
|
|
151
|
+
const slice = getSlice('M001', 'S01');
|
|
152
|
+
assert.ok(slice !== null, 'getSlice should return non-null for existing slice');
|
|
153
|
+
assert.strictEqual(slice!.id, 'S01', 'slice id');
|
|
154
|
+
assert.strictEqual(slice!.milestone_id, 'M001', 'slice milestone_id');
|
|
155
|
+
assert.strictEqual(slice!.title, 'Test Slice', 'slice title');
|
|
156
|
+
assert.strictEqual(slice!.risk, 'high', 'slice risk');
|
|
157
|
+
assert.strictEqual(slice!.status, 'pending', 'slice default status should be pending');
|
|
158
|
+
assert.strictEqual(slice!.completed_at, null, 'slice completed_at should be null initially');
|
|
159
|
+
assert.strictEqual(slice!.full_summary_md, '', 'slice full_summary_md should be empty initially');
|
|
160
|
+
assert.strictEqual(slice!.full_uat_md, '', 'slice full_uat_md should be empty initially');
|
|
161
|
+
|
|
162
|
+
// getSlice returns null for non-existent
|
|
163
|
+
const noSlice = getSlice('M001', 'S99');
|
|
164
|
+
assert.strictEqual(noSlice, null, 'non-existent slice should return null');
|
|
165
|
+
|
|
166
|
+
// updateSliceStatus changes status and completed_at
|
|
167
|
+
const now = new Date().toISOString();
|
|
168
|
+
updateSliceStatus('M001', 'S01', 'complete', now);
|
|
169
|
+
const updated = getSlice('M001', 'S01');
|
|
170
|
+
assert.strictEqual(updated!.status, 'complete', 'slice status should be updated to complete');
|
|
171
|
+
assert.strictEqual(updated!.completed_at, now, 'slice completed_at should be set');
|
|
172
|
+
|
|
173
|
+
cleanup(dbPath);
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
describe("complete-slice: handler", () => {
|
|
178
|
+
test("happy path", async () => {
|
|
179
|
+
const dbPath = tempDbPath();
|
|
180
|
+
openDatabase(dbPath);
|
|
181
|
+
|
|
182
|
+
const { basePath, roadmapPath } = createTempProject();
|
|
183
|
+
|
|
184
|
+
// Set up DB state: milestone, slice, 2 complete tasks
|
|
185
|
+
insertMilestone({ id: 'M001' });
|
|
186
|
+
insertSlice({ id: 'S01', milestoneId: 'M001' });
|
|
187
|
+
insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
|
|
188
|
+
insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 2' });
|
|
189
|
+
|
|
190
|
+
const params = makeValidSliceParams();
|
|
191
|
+
const result = await handleCompleteSlice(params, basePath);
|
|
192
|
+
|
|
193
|
+
assert.ok(!('error' in result), 'handler should succeed without error');
|
|
194
|
+
if (!('error' in result)) {
|
|
195
|
+
assert.strictEqual(result.sliceId, 'S01', 'result sliceId');
|
|
196
|
+
assert.strictEqual(result.milestoneId, 'M001', 'result milestoneId');
|
|
197
|
+
assert.ok(result.summaryPath.endsWith('S01-SUMMARY.md'), 'summaryPath should end with S01-SUMMARY.md');
|
|
198
|
+
assert.ok(result.uatPath.endsWith('S01-UAT.md'), 'uatPath should end with S01-UAT.md');
|
|
199
|
+
|
|
200
|
+
// (a) Verify SUMMARY.md exists on disk with correct YAML frontmatter
|
|
201
|
+
assert.ok(fs.existsSync(result.summaryPath), 'summary file should exist on disk');
|
|
202
|
+
const summaryContent = fs.readFileSync(result.summaryPath, 'utf-8');
|
|
203
|
+
assert.match(summaryContent, /^---\n/, 'summary should start with YAML frontmatter');
|
|
204
|
+
assert.match(summaryContent, /id: S01/, 'summary should contain id: S01');
|
|
205
|
+
assert.match(summaryContent, /parent: M001/, 'summary should contain parent: M001');
|
|
206
|
+
assert.match(summaryContent, /milestone: M001/, 'summary should contain milestone: M001');
|
|
207
|
+
assert.match(summaryContent, /blocker_discovered: false/, 'summary should contain blocker_discovered');
|
|
208
|
+
assert.match(summaryContent, /verification_result: passed/, 'summary should contain verification_result');
|
|
209
|
+
assert.match(summaryContent, /key_files:/, 'summary should contain key_files');
|
|
210
|
+
assert.match(summaryContent, /patterns_established:/, 'summary should contain patterns_established');
|
|
211
|
+
assert.match(summaryContent, /observability_surfaces:/, 'summary should contain observability_surfaces');
|
|
212
|
+
assert.match(summaryContent, /provides:/, 'summary should contain provides');
|
|
213
|
+
assert.match(summaryContent, /# S01: Test Slice/, 'summary should have H1 with slice ID and title');
|
|
214
|
+
assert.match(summaryContent, /\*\*Implemented test slice with full coverage\*\*/, 'summary should have one-liner in bold');
|
|
215
|
+
assert.match(summaryContent, /## What Happened/, 'summary should have What Happened section');
|
|
216
|
+
assert.match(summaryContent, /## Verification/, 'summary should have Verification section');
|
|
217
|
+
assert.match(summaryContent, /## Requirements Advanced/, 'summary should have Requirements Advanced section');
|
|
218
|
+
|
|
219
|
+
// (b) Verify UAT.md exists on disk
|
|
220
|
+
assert.ok(fs.existsSync(result.uatPath), 'UAT file should exist on disk');
|
|
221
|
+
const uatContent = fs.readFileSync(result.uatPath, 'utf-8');
|
|
222
|
+
assert.match(uatContent, /# S01: Test Slice — UAT/, 'UAT should have correct title');
|
|
223
|
+
assert.match(uatContent, /Milestone:\*\* M001/, 'UAT should reference milestone');
|
|
224
|
+
assert.match(uatContent, /Smoke Test/, 'UAT should contain smoke test from params');
|
|
225
|
+
|
|
226
|
+
// (c) Verify roadmap checkbox toggled to [x]
|
|
227
|
+
const roadmapContent = fs.readFileSync(roadmapPath, 'utf-8');
|
|
228
|
+
assert.match(roadmapContent, /\[x\]\s+\*\*S01:/, 'S01 should be checked in roadmap');
|
|
229
|
+
assert.match(roadmapContent, /\[ \]\s+\*\*S02:/, 'S02 should still be unchecked in roadmap');
|
|
230
|
+
|
|
231
|
+
// (d) Verify full_summary_md and full_uat_md stored in DB for D004 recovery
|
|
232
|
+
const sliceAfter = getSlice('M001', 'S01');
|
|
233
|
+
assert.ok(sliceAfter !== null, 'slice should exist in DB after handler');
|
|
234
|
+
assert.ok(sliceAfter!.full_summary_md.length > 0, 'full_summary_md should be non-empty in DB');
|
|
235
|
+
assert.match(sliceAfter!.full_summary_md, /id: S01/, 'full_summary_md should contain frontmatter');
|
|
236
|
+
assert.ok(sliceAfter!.full_uat_md.length > 0, 'full_uat_md should be non-empty in DB');
|
|
237
|
+
assert.match(sliceAfter!.full_uat_md, /S01: Test Slice — UAT/, 'full_uat_md should contain UAT title');
|
|
238
|
+
|
|
239
|
+
// (e) Verify slice status is complete in DB
|
|
240
|
+
assert.strictEqual(sliceAfter!.status, 'complete', 'slice status should be complete in DB');
|
|
241
|
+
assert.ok(sliceAfter!.completed_at !== null, 'completed_at should be set in DB');
|
|
242
|
+
}
|
|
281
243
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
244
|
+
cleanupDir(basePath);
|
|
245
|
+
cleanup(dbPath);
|
|
246
|
+
});
|
|
285
247
|
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
openDatabase(dbPath);
|
|
248
|
+
test("rejects incomplete tasks", async () => {
|
|
249
|
+
const dbPath = tempDbPath();
|
|
250
|
+
openDatabase(dbPath);
|
|
290
251
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
252
|
+
// Insert milestone, slice, 2 tasks — one complete, one pending
|
|
253
|
+
insertMilestone({ id: 'M001' });
|
|
254
|
+
insertSlice({ id: 'S01', milestoneId: 'M001' });
|
|
255
|
+
insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
|
|
256
|
+
insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'pending', title: 'Task 2' });
|
|
294
257
|
|
|
295
|
-
|
|
296
|
-
|
|
258
|
+
const params = makeValidSliceParams();
|
|
259
|
+
const result = await handleCompleteSlice(params, '/tmp/fake');
|
|
297
260
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
261
|
+
assert.ok('error' in result, 'should return error when tasks are incomplete');
|
|
262
|
+
if ('error' in result) {
|
|
263
|
+
assert.match(result.error, /incomplete tasks/, 'error should mention incomplete tasks');
|
|
264
|
+
assert.match(result.error, /T02/, 'error should mention the specific incomplete task ID');
|
|
265
|
+
}
|
|
302
266
|
|
|
303
|
-
|
|
304
|
-
}
|
|
267
|
+
cleanup(dbPath);
|
|
268
|
+
});
|
|
305
269
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
270
|
+
test("rejects no tasks", async () => {
|
|
271
|
+
const dbPath = tempDbPath();
|
|
272
|
+
openDatabase(dbPath);
|
|
309
273
|
|
|
310
|
-
|
|
311
|
-
{
|
|
312
|
-
|
|
313
|
-
openDatabase(dbPath);
|
|
274
|
+
// Insert milestone and slice but NO tasks
|
|
275
|
+
insertMilestone({ id: 'M001' });
|
|
276
|
+
insertSlice({ id: 'S01', milestoneId: 'M001' });
|
|
314
277
|
|
|
315
|
-
|
|
278
|
+
const params = makeValidSliceParams();
|
|
279
|
+
const result = await handleCompleteSlice(params, '/tmp/fake');
|
|
316
280
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
assertMatch(r1.error, /sliceId/, 'error should mention sliceId');
|
|
322
|
-
}
|
|
281
|
+
assert.ok('error' in result, 'should return error when no tasks exist');
|
|
282
|
+
if ('error' in result) {
|
|
283
|
+
assert.match(result.error, /no tasks found/, 'error should say no tasks found');
|
|
284
|
+
}
|
|
323
285
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
assertTrue('error' in r2, 'should return error for empty milestoneId');
|
|
327
|
-
if ('error' in r2) {
|
|
328
|
-
assertMatch(r2.error, /milestoneId/, 'error should mention milestoneId');
|
|
329
|
-
}
|
|
286
|
+
cleanup(dbPath);
|
|
287
|
+
});
|
|
330
288
|
|
|
331
|
-
|
|
332
|
-
|
|
289
|
+
test("validation errors", async () => {
|
|
290
|
+
const dbPath = tempDbPath();
|
|
291
|
+
openDatabase(dbPath);
|
|
333
292
|
|
|
334
|
-
|
|
335
|
-
// complete-slice: Handler idempotency
|
|
336
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
293
|
+
const params = makeValidSliceParams();
|
|
337
294
|
|
|
338
|
-
|
|
339
|
-
{
|
|
340
|
-
|
|
341
|
-
|
|
295
|
+
// Empty sliceId
|
|
296
|
+
const r1 = await handleCompleteSlice({ ...params, sliceId: '' }, '/tmp/fake');
|
|
297
|
+
assert.ok('error' in r1, 'should return error for empty sliceId');
|
|
298
|
+
if ('error' in r1) {
|
|
299
|
+
assert.match(r1.error, /sliceId/, 'error should mention sliceId');
|
|
300
|
+
}
|
|
342
301
|
|
|
343
|
-
|
|
302
|
+
// Empty milestoneId
|
|
303
|
+
const r2 = await handleCompleteSlice({ ...params, milestoneId: '' }, '/tmp/fake');
|
|
304
|
+
assert.ok('error' in r2, 'should return error for empty milestoneId');
|
|
305
|
+
if ('error' in r2) {
|
|
306
|
+
assert.match(r2.error, /milestoneId/, 'error should mention milestoneId');
|
|
307
|
+
}
|
|
344
308
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
insertSlice({ id: 'S01', milestoneId: 'M001' });
|
|
348
|
-
insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
|
|
309
|
+
cleanup(dbPath);
|
|
310
|
+
});
|
|
349
311
|
|
|
350
|
-
|
|
312
|
+
test("idempotency", async () => {
|
|
313
|
+
const dbPath = tempDbPath();
|
|
314
|
+
openDatabase(dbPath);
|
|
351
315
|
|
|
352
|
-
|
|
353
|
-
const r1 = await handleCompleteSlice(params, basePath);
|
|
354
|
-
assertTrue(!('error' in r1), 'first call should succeed');
|
|
316
|
+
const { basePath, roadmapPath } = createTempProject();
|
|
355
317
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
318
|
+
// Set up DB state
|
|
319
|
+
insertMilestone({ id: 'M001' });
|
|
320
|
+
insertSlice({ id: 'S01', milestoneId: 'M001' });
|
|
321
|
+
insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
|
|
359
322
|
|
|
360
|
-
|
|
361
|
-
const adapter = _getAdapter()!;
|
|
362
|
-
const sliceRows = adapter.prepare("SELECT * FROM slices WHERE milestone_id = 'M001' AND id = 'S01'").all();
|
|
363
|
-
assertEq(sliceRows.length, 1, 'should have exactly 1 slice row after 2 calls');
|
|
323
|
+
const params = makeValidSliceParams();
|
|
364
324
|
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
assertTrue(fs.existsSync(r2.uatPath), 'UAT should still exist after second call');
|
|
369
|
-
}
|
|
325
|
+
// First call
|
|
326
|
+
const r1 = await handleCompleteSlice(params, basePath);
|
|
327
|
+
assert.ok(!('error' in r1), 'first call should succeed');
|
|
370
328
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
329
|
+
// Second call with same params — should not crash
|
|
330
|
+
const r2 = await handleCompleteSlice(params, basePath);
|
|
331
|
+
assert.ok(!('error' in r2), 'second call should succeed (idempotent)');
|
|
374
332
|
|
|
375
|
-
//
|
|
376
|
-
|
|
377
|
-
|
|
333
|
+
// Verify only 1 slice row (not duplicated)
|
|
334
|
+
const adapter = _getAdapter()!;
|
|
335
|
+
const sliceRows = adapter.prepare("SELECT * FROM slices WHERE milestone_id = 'M001' AND id = 'S01'").all();
|
|
336
|
+
assert.strictEqual(sliceRows.length, 1, 'should have exactly 1 slice row after 2 calls');
|
|
378
337
|
|
|
379
|
-
|
|
380
|
-
{
|
|
381
|
-
|
|
382
|
-
|
|
338
|
+
// Files should still exist
|
|
339
|
+
if (!('error' in r2)) {
|
|
340
|
+
assert.ok(fs.existsSync(r2.summaryPath), 'summary should still exist after second call');
|
|
341
|
+
assert.ok(fs.existsSync(r2.uatPath), 'UAT should still exist after second call');
|
|
342
|
+
}
|
|
383
343
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
fs.mkdirSync(sliceDir, { recursive: true });
|
|
344
|
+
cleanupDir(basePath);
|
|
345
|
+
cleanup(dbPath);
|
|
346
|
+
});
|
|
388
347
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
|
|
348
|
+
test("missing roadmap (graceful)", async () => {
|
|
349
|
+
const dbPath = tempDbPath();
|
|
350
|
+
openDatabase(dbPath);
|
|
393
351
|
|
|
394
|
-
|
|
395
|
-
|
|
352
|
+
// Create a temp dir WITHOUT a roadmap file
|
|
353
|
+
const basePath = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-no-roadmap-'));
|
|
354
|
+
const sliceDir = path.join(basePath, '.gsd', 'milestones', 'M001', 'slices', 'S01');
|
|
355
|
+
fs.mkdirSync(sliceDir, { recursive: true });
|
|
396
356
|
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
assertTrue(fs.existsSync(result.uatPath), 'UAT should be written even without roadmap');
|
|
402
|
-
}
|
|
357
|
+
// Set up DB state
|
|
358
|
+
insertMilestone({ id: 'M001' });
|
|
359
|
+
insertSlice({ id: 'S01', milestoneId: 'M001' });
|
|
360
|
+
insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
|
|
403
361
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
}
|
|
362
|
+
const params = makeValidSliceParams();
|
|
363
|
+
const result = await handleCompleteSlice(params, basePath);
|
|
407
364
|
|
|
408
|
-
//
|
|
365
|
+
// Should succeed even without roadmap file — just skip checkbox toggle
|
|
366
|
+
assert.ok(!('error' in result), 'handler should succeed without roadmap file');
|
|
367
|
+
if (!('error' in result)) {
|
|
368
|
+
assert.ok(fs.existsSync(result.summaryPath), 'summary should be written even without roadmap');
|
|
369
|
+
assert.ok(fs.existsSync(result.uatPath), 'UAT should be written even without roadmap');
|
|
370
|
+
}
|
|
409
371
|
|
|
410
|
-
|
|
372
|
+
cleanupDir(basePath);
|
|
373
|
+
cleanup(dbPath);
|
|
374
|
+
});
|
|
375
|
+
});
|