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 } 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
|
} from '../gsd-db.ts';
|
|
18
19
|
import { handleCompleteTask } from '../tools/complete-task.ts';
|
|
19
20
|
|
|
20
|
-
const { assertEq, assertTrue, assertMatch, report } = createTestContext();
|
|
21
|
-
|
|
22
21
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
23
22
|
// Helpers
|
|
24
23
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
@@ -99,341 +98,290 @@ function makeValidParams() {
|
|
|
99
98
|
}
|
|
100
99
|
|
|
101
100
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
102
|
-
//
|
|
101
|
+
// Tests
|
|
103
102
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
104
103
|
|
|
105
|
-
|
|
106
|
-
{
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
const adapter = _getAdapter()!;
|
|
111
|
-
|
|
112
|
-
// Verify schema version is current (v10 after M001 planning migrations)
|
|
113
|
-
const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
|
|
114
|
-
assertEq(versionRow?.['v'], 10, 'schema version should be 10');
|
|
104
|
+
describe("complete-task: schema v5 migration", () => {
|
|
105
|
+
test("schema version and tables exist", () => {
|
|
106
|
+
const dbPath = tempDbPath();
|
|
107
|
+
openDatabase(dbPath);
|
|
115
108
|
|
|
116
|
-
|
|
117
|
-
const tables = adapter.prepare(
|
|
118
|
-
"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
|
|
119
|
-
).all();
|
|
120
|
-
const tableNames = tables.map(t => t['name'] as string);
|
|
121
|
-
assertTrue(tableNames.includes('milestones'), 'milestones table should exist');
|
|
122
|
-
assertTrue(tableNames.includes('slices'), 'slices table should exist');
|
|
123
|
-
assertTrue(tableNames.includes('tasks'), 'tasks table should exist');
|
|
124
|
-
assertTrue(tableNames.includes('verification_evidence'), 'verification_evidence table should exist');
|
|
109
|
+
const adapter = _getAdapter()!;
|
|
125
110
|
|
|
126
|
-
|
|
127
|
-
|
|
111
|
+
// Verify schema version is current (v10 after M001 planning migrations)
|
|
112
|
+
const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
|
|
113
|
+
assert.strictEqual(versionRow?.['v'], 10, 'schema version should be 10');
|
|
128
114
|
|
|
129
|
-
//
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
// Insert milestone
|
|
139
|
-
insertMilestone({ id: 'M001', title: 'Test Milestone' });
|
|
140
|
-
const adapter = _getAdapter()!;
|
|
141
|
-
const mRow = adapter.prepare("SELECT * FROM milestones WHERE id = 'M001'").get();
|
|
142
|
-
assertEq(mRow?.['id'], 'M001', 'milestone id should be M001');
|
|
143
|
-
assertEq(mRow?.['title'], 'Test Milestone', 'milestone title should match');
|
|
144
|
-
|
|
145
|
-
// Insert slice
|
|
146
|
-
insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice', risk: 'high' });
|
|
147
|
-
const sRow = adapter.prepare("SELECT * FROM slices WHERE id = 'S01' AND milestone_id = 'M001'").get();
|
|
148
|
-
assertEq(sRow?.['id'], 'S01', 'slice id should be S01');
|
|
149
|
-
assertEq(sRow?.['risk'], 'high', 'slice risk should be high');
|
|
150
|
-
|
|
151
|
-
// Insert task with all fields
|
|
152
|
-
insertTask({
|
|
153
|
-
id: 'T01',
|
|
154
|
-
sliceId: 'S01',
|
|
155
|
-
milestoneId: 'M001',
|
|
156
|
-
title: 'Test Task',
|
|
157
|
-
status: 'complete',
|
|
158
|
-
oneLiner: 'Did the thing',
|
|
159
|
-
narrative: 'Full story here.',
|
|
160
|
-
verificationResult: 'passed',
|
|
161
|
-
duration: '30m',
|
|
162
|
-
blockerDiscovered: false,
|
|
163
|
-
deviations: 'None',
|
|
164
|
-
knownIssues: 'None',
|
|
165
|
-
keyFiles: ['file1.ts', 'file2.ts'],
|
|
166
|
-
keyDecisions: ['D001'],
|
|
167
|
-
fullSummaryMd: '# Summary',
|
|
168
|
-
});
|
|
115
|
+
// Verify all 4 new tables exist
|
|
116
|
+
const tables = adapter.prepare(
|
|
117
|
+
"SELECT name FROM sqlite_master WHERE type='table' ORDER BY name"
|
|
118
|
+
).all();
|
|
119
|
+
const tableNames = tables.map(t => t['name'] as string);
|
|
120
|
+
assert.ok(tableNames.includes('milestones'), 'milestones table should exist');
|
|
121
|
+
assert.ok(tableNames.includes('slices'), 'slices table should exist');
|
|
122
|
+
assert.ok(tableNames.includes('tasks'), 'tasks table should exist');
|
|
123
|
+
assert.ok(tableNames.includes('verification_evidence'), 'verification_evidence table should exist');
|
|
169
124
|
|
|
170
|
-
|
|
171
|
-
const task = getTask('M001', 'S01', 'T01');
|
|
172
|
-
assertTrue(task !== null, 'task should not be null');
|
|
173
|
-
assertEq(task!.id, 'T01', 'task id');
|
|
174
|
-
assertEq(task!.slice_id, 'S01', 'task slice_id');
|
|
175
|
-
assertEq(task!.milestone_id, 'M001', 'task milestone_id');
|
|
176
|
-
assertEq(task!.title, 'Test Task', 'task title');
|
|
177
|
-
assertEq(task!.status, 'complete', 'task status');
|
|
178
|
-
assertEq(task!.one_liner, 'Did the thing', 'task one_liner');
|
|
179
|
-
assertEq(task!.narrative, 'Full story here.', 'task narrative');
|
|
180
|
-
assertEq(task!.verification_result, 'passed', 'task verification_result');
|
|
181
|
-
assertEq(task!.blocker_discovered, false, 'task blocker_discovered');
|
|
182
|
-
assertEq(task!.key_files, ['file1.ts', 'file2.ts'], 'task key_files JSON round-trip');
|
|
183
|
-
assertEq(task!.key_decisions, ['D001'], 'task key_decisions JSON round-trip');
|
|
184
|
-
assertEq(task!.full_summary_md, '# Summary', 'task full_summary_md');
|
|
185
|
-
|
|
186
|
-
// getTask returns null for non-existent
|
|
187
|
-
const noTask = getTask('M001', 'S01', 'T99');
|
|
188
|
-
assertEq(noTask, null, 'non-existent task should return null');
|
|
189
|
-
|
|
190
|
-
// Insert verification evidence
|
|
191
|
-
insertVerificationEvidence({
|
|
192
|
-
taskId: 'T01',
|
|
193
|
-
sliceId: 'S01',
|
|
194
|
-
milestoneId: 'M001',
|
|
195
|
-
command: 'npm test',
|
|
196
|
-
exitCode: 0,
|
|
197
|
-
verdict: '✅ pass',
|
|
198
|
-
durationMs: 3000,
|
|
125
|
+
cleanup(dbPath);
|
|
199
126
|
});
|
|
200
|
-
|
|
201
|
-
"SELECT * FROM verification_evidence WHERE task_id = 'T01' AND slice_id = 'S01' AND milestone_id = 'M001'"
|
|
202
|
-
).all();
|
|
203
|
-
assertEq(evRows.length, 1, 'should have 1 verification evidence row');
|
|
204
|
-
assertEq(evRows[0]['command'], 'npm test', 'evidence command');
|
|
205
|
-
assertEq(evRows[0]['exit_code'], 0, 'evidence exit_code');
|
|
206
|
-
assertEq(evRows[0]['verdict'], '✅ pass', 'evidence verdict');
|
|
207
|
-
assertEq(evRows[0]['duration_ms'], 3000, 'evidence duration_ms');
|
|
208
|
-
|
|
209
|
-
// getSliceTasks returns array
|
|
210
|
-
const sliceTasks = getSliceTasks('M001', 'S01');
|
|
211
|
-
assertEq(sliceTasks.length, 1, 'getSliceTasks should return 1 task');
|
|
212
|
-
assertEq(sliceTasks[0].id, 'T01', 'getSliceTasks first task id');
|
|
213
|
-
|
|
214
|
-
// updateTaskStatus changes status
|
|
215
|
-
updateTaskStatus('M001', 'S01', 'T01', 'failed', new Date().toISOString());
|
|
216
|
-
const updatedTask = getTask('M001', 'S01', 'T01');
|
|
217
|
-
assertEq(updatedTask!.status, 'failed', 'task status should be updated to failed');
|
|
218
|
-
assertTrue(updatedTask!.completed_at !== null, 'completed_at should be set after status update');
|
|
219
|
-
|
|
220
|
-
cleanup(dbPath);
|
|
221
|
-
}
|
|
127
|
+
});
|
|
222
128
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
129
|
+
describe("complete-task: accessor CRUD", () => {
|
|
130
|
+
test("insert and query milestones, slices, tasks, evidence", () => {
|
|
131
|
+
const dbPath = tempDbPath();
|
|
132
|
+
openDatabase(dbPath);
|
|
226
133
|
|
|
227
|
-
|
|
228
|
-
{
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
'
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
'insertTask should throw GSD_STALE_STATE');
|
|
258
|
-
}
|
|
259
|
-
assertTrue(threw, 'insertTask should throw when no DB open');
|
|
260
|
-
|
|
261
|
-
threw = false;
|
|
262
|
-
try {
|
|
263
|
-
insertVerificationEvidence({
|
|
264
|
-
taskId: 'T01', sliceId: 'S01', milestoneId: 'M001',
|
|
265
|
-
command: 'test', exitCode: 0, verdict: 'pass', durationMs: 0,
|
|
134
|
+
// Insert milestone
|
|
135
|
+
insertMilestone({ id: 'M001', title: 'Test Milestone' });
|
|
136
|
+
const adapter = _getAdapter()!;
|
|
137
|
+
const mRow = adapter.prepare("SELECT * FROM milestones WHERE id = 'M001'").get();
|
|
138
|
+
assert.strictEqual(mRow?.['id'], 'M001', 'milestone id should be M001');
|
|
139
|
+
assert.strictEqual(mRow?.['title'], 'Test Milestone', 'milestone title should match');
|
|
140
|
+
|
|
141
|
+
// Insert slice
|
|
142
|
+
insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice', risk: 'high' });
|
|
143
|
+
const sRow = adapter.prepare("SELECT * FROM slices WHERE id = 'S01' AND milestone_id = 'M001'").get();
|
|
144
|
+
assert.strictEqual(sRow?.['id'], 'S01', 'slice id should be S01');
|
|
145
|
+
assert.strictEqual(sRow?.['risk'], 'high', 'slice risk should be high');
|
|
146
|
+
|
|
147
|
+
// Insert task with all fields
|
|
148
|
+
insertTask({
|
|
149
|
+
id: 'T01',
|
|
150
|
+
sliceId: 'S01',
|
|
151
|
+
milestoneId: 'M001',
|
|
152
|
+
title: 'Test Task',
|
|
153
|
+
status: 'complete',
|
|
154
|
+
oneLiner: 'Did the thing',
|
|
155
|
+
narrative: 'Full story here.',
|
|
156
|
+
verificationResult: 'passed',
|
|
157
|
+
duration: '30m',
|
|
158
|
+
blockerDiscovered: false,
|
|
159
|
+
deviations: 'None',
|
|
160
|
+
knownIssues: 'None',
|
|
161
|
+
keyFiles: ['file1.ts', 'file2.ts'],
|
|
162
|
+
keyDecisions: ['D001'],
|
|
163
|
+
fullSummaryMd: '# Summary',
|
|
266
164
|
});
|
|
267
|
-
} catch (err: any) {
|
|
268
|
-
threw = true;
|
|
269
|
-
assertTrue(err.code === 'GSD_STALE_STATE' || err.message.includes('No database open'),
|
|
270
|
-
'insertVerificationEvidence should throw GSD_STALE_STATE');
|
|
271
|
-
}
|
|
272
|
-
assertTrue(threw, 'insertVerificationEvidence should throw when no DB open');
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
276
|
-
// complete-task: Handler happy path
|
|
277
|
-
// ═══════════════════════════════════════════════════════════════════════════
|
|
278
|
-
|
|
279
|
-
console.log('\n=== complete-task: handler happy path ===');
|
|
280
|
-
{
|
|
281
|
-
const dbPath = tempDbPath();
|
|
282
|
-
openDatabase(dbPath);
|
|
283
165
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
const params = makeValidParams();
|
|
287
|
-
const result = await handleCompleteTask(params, basePath);
|
|
288
|
-
|
|
289
|
-
assertTrue(!('error' in result), 'handler should succeed without error');
|
|
290
|
-
if (!('error' in result)) {
|
|
291
|
-
assertEq(result.taskId, 'T01', 'result taskId');
|
|
292
|
-
assertEq(result.sliceId, 'S01', 'result sliceId');
|
|
293
|
-
assertEq(result.milestoneId, 'M001', 'result milestoneId');
|
|
294
|
-
assertTrue(result.summaryPath.endsWith('T01-SUMMARY.md'), 'summaryPath should end with T01-SUMMARY.md');
|
|
295
|
-
|
|
296
|
-
// (a) Verify task row in DB with status 'complete'
|
|
166
|
+
// getTask verifies all fields
|
|
297
167
|
const task = getTask('M001', 'S01', 'T01');
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
168
|
+
assert.ok(task !== null, 'task should not be null');
|
|
169
|
+
assert.strictEqual(task!.id, 'T01', 'task id');
|
|
170
|
+
assert.strictEqual(task!.slice_id, 'S01', 'task slice_id');
|
|
171
|
+
assert.strictEqual(task!.milestone_id, 'M001', 'task milestone_id');
|
|
172
|
+
assert.strictEqual(task!.title, 'Test Task', 'task title');
|
|
173
|
+
assert.strictEqual(task!.status, 'complete', 'task status');
|
|
174
|
+
assert.strictEqual(task!.one_liner, 'Did the thing', 'task one_liner');
|
|
175
|
+
assert.strictEqual(task!.narrative, 'Full story here.', 'task narrative');
|
|
176
|
+
assert.strictEqual(task!.verification_result, 'passed', 'task verification_result');
|
|
177
|
+
assert.strictEqual(task!.blocker_discovered, false, 'task blocker_discovered');
|
|
178
|
+
assert.deepStrictEqual(task!.key_files, ['file1.ts', 'file2.ts'], 'task key_files JSON round-trip');
|
|
179
|
+
assert.deepStrictEqual(task!.key_decisions, ['D001'], 'task key_decisions JSON round-trip');
|
|
180
|
+
assert.strictEqual(task!.full_summary_md, '# Summary', 'task full_summary_md');
|
|
181
|
+
|
|
182
|
+
// getTask returns null for non-existent
|
|
183
|
+
const noTask = getTask('M001', 'S01', 'T99');
|
|
184
|
+
assert.strictEqual(noTask, null, 'non-existent task should return null');
|
|
185
|
+
|
|
186
|
+
// Insert verification evidence
|
|
187
|
+
insertVerificationEvidence({
|
|
188
|
+
taskId: 'T01',
|
|
189
|
+
sliceId: 'S01',
|
|
190
|
+
milestoneId: 'M001',
|
|
191
|
+
command: 'npm test',
|
|
192
|
+
exitCode: 0,
|
|
193
|
+
verdict: '✅ pass',
|
|
194
|
+
durationMs: 3000,
|
|
195
|
+
});
|
|
305
196
|
const evRows = adapter.prepare(
|
|
306
|
-
"SELECT * FROM verification_evidence WHERE task_id = 'T01' AND milestone_id = 'M001'"
|
|
197
|
+
"SELECT * FROM verification_evidence WHERE task_id = 'T01' AND slice_id = 'S01' AND milestone_id = 'M001'"
|
|
307
198
|
).all();
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
// T02 should still be unchecked
|
|
329
|
-
assertMatch(planContent, /\[ \]\s+\*\*T02:/, 'T02 should still be unchecked in plan');
|
|
330
|
-
|
|
331
|
-
// (e) Verify full_summary_md stored in DB for D004 recovery
|
|
332
|
-
const taskAfter = getTask('M001', 'S01', 'T01');
|
|
333
|
-
assertTrue(taskAfter!.full_summary_md.length > 0, 'full_summary_md should be non-empty in DB');
|
|
334
|
-
assertMatch(taskAfter!.full_summary_md, /id: T01/, 'full_summary_md should contain frontmatter');
|
|
335
|
-
}
|
|
199
|
+
assert.strictEqual(evRows.length, 1, 'should have 1 verification evidence row');
|
|
200
|
+
assert.strictEqual(evRows[0]['command'], 'npm test', 'evidence command');
|
|
201
|
+
assert.strictEqual(evRows[0]['exit_code'], 0, 'evidence exit_code');
|
|
202
|
+
assert.strictEqual(evRows[0]['verdict'], '✅ pass', 'evidence verdict');
|
|
203
|
+
assert.strictEqual(evRows[0]['duration_ms'], 3000, 'evidence duration_ms');
|
|
204
|
+
|
|
205
|
+
// getSliceTasks returns array
|
|
206
|
+
const sliceTasks = getSliceTasks('M001', 'S01');
|
|
207
|
+
assert.strictEqual(sliceTasks.length, 1, 'getSliceTasks should return 1 task');
|
|
208
|
+
assert.strictEqual(sliceTasks[0].id, 'T01', 'getSliceTasks first task id');
|
|
209
|
+
|
|
210
|
+
// updateTaskStatus changes status
|
|
211
|
+
updateTaskStatus('M001', 'S01', 'T01', 'failed', new Date().toISOString());
|
|
212
|
+
const updatedTask = getTask('M001', 'S01', 'T01');
|
|
213
|
+
assert.strictEqual(updatedTask!.status, 'failed', 'task status should be updated to failed');
|
|
214
|
+
assert.ok(updatedTask!.completed_at !== null, 'completed_at should be set after status update');
|
|
215
|
+
|
|
216
|
+
cleanup(dbPath);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
336
219
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
220
|
+
describe("complete-task: accessor stale-state error", () => {
|
|
221
|
+
test("accessors throw when no DB open", () => {
|
|
222
|
+
closeDatabase();
|
|
340
223
|
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
224
|
+
assert.throws(() => insertMilestone({ id: 'M001' }),
|
|
225
|
+
(err: any) => err.code === 'GSD_STALE_STATE' || err.message.includes('No database open'),
|
|
226
|
+
'insertMilestone should throw when no DB open');
|
|
344
227
|
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
openDatabase(dbPath);
|
|
228
|
+
assert.throws(() => insertSlice({ id: 'S01', milestoneId: 'M001' }),
|
|
229
|
+
(err: any) => err.code === 'GSD_STALE_STATE' || err.message.includes('No database open'),
|
|
230
|
+
'insertSlice should throw when no DB open');
|
|
349
231
|
|
|
350
|
-
|
|
232
|
+
assert.throws(() => insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001' }),
|
|
233
|
+
(err: any) => err.code === 'GSD_STALE_STATE' || err.message.includes('No database open'),
|
|
234
|
+
'insertTask should throw when no DB open');
|
|
351
235
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
236
|
+
assert.throws(() => insertVerificationEvidence({
|
|
237
|
+
taskId: 'T01', sliceId: 'S01', milestoneId: 'M001',
|
|
238
|
+
command: 'test', exitCode: 0, verdict: 'pass', durationMs: 0,
|
|
239
|
+
}),
|
|
240
|
+
(err: any) => err.code === 'GSD_STALE_STATE' || err.message.includes('No database open'),
|
|
241
|
+
'insertVerificationEvidence should throw when no DB open');
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
describe("complete-task: handler", () => {
|
|
246
|
+
test("happy path", async () => {
|
|
247
|
+
const dbPath = tempDbPath();
|
|
248
|
+
openDatabase(dbPath);
|
|
249
|
+
|
|
250
|
+
const { basePath, planPath } = createTempProject();
|
|
251
|
+
|
|
252
|
+
const params = makeValidParams();
|
|
253
|
+
const result = await handleCompleteTask(params, basePath);
|
|
254
|
+
|
|
255
|
+
assert.ok(!('error' in result), 'handler should succeed without error');
|
|
256
|
+
if (!('error' in result)) {
|
|
257
|
+
assert.strictEqual(result.taskId, 'T01', 'result taskId');
|
|
258
|
+
assert.strictEqual(result.sliceId, 'S01', 'result sliceId');
|
|
259
|
+
assert.strictEqual(result.milestoneId, 'M001', 'result milestoneId');
|
|
260
|
+
assert.ok(result.summaryPath.endsWith('T01-SUMMARY.md'), 'summaryPath should end with T01-SUMMARY.md');
|
|
261
|
+
|
|
262
|
+
// (a) Verify task row in DB with status 'complete'
|
|
263
|
+
const task = getTask('M001', 'S01', 'T01');
|
|
264
|
+
assert.ok(task !== null, 'task should exist in DB after handler');
|
|
265
|
+
assert.strictEqual(task!.status, 'complete', 'task status should be complete');
|
|
266
|
+
assert.strictEqual(task!.one_liner, 'Added test functionality', 'task one_liner in DB');
|
|
267
|
+
assert.deepStrictEqual(task!.key_files, ['src/test.ts', 'src/test.test.ts'], 'task key_files in DB');
|
|
268
|
+
|
|
269
|
+
// (b) Verify verification_evidence rows in DB
|
|
270
|
+
const adapter = _getAdapter()!;
|
|
271
|
+
const evRows = adapter.prepare(
|
|
272
|
+
"SELECT * FROM verification_evidence WHERE task_id = 'T01' AND milestone_id = 'M001'"
|
|
273
|
+
).all();
|
|
274
|
+
assert.strictEqual(evRows.length, 1, 'should have 1 verification evidence row after handler');
|
|
275
|
+
assert.strictEqual(evRows[0]['command'], 'npm run test:unit', 'evidence command from handler');
|
|
276
|
+
|
|
277
|
+
// (c) Verify T01-SUMMARY.md file on disk with correct YAML frontmatter
|
|
278
|
+
assert.ok(fs.existsSync(result.summaryPath), 'summary file should exist on disk');
|
|
279
|
+
const summaryContent = fs.readFileSync(result.summaryPath, 'utf-8');
|
|
280
|
+
assert.match(summaryContent, /^---\n/, 'summary should start with YAML frontmatter');
|
|
281
|
+
assert.match(summaryContent, /id: T01/, 'summary should contain id: T01');
|
|
282
|
+
assert.match(summaryContent, /parent: S01/, 'summary should contain parent: S01');
|
|
283
|
+
assert.match(summaryContent, /milestone: M001/, 'summary should contain milestone: M001');
|
|
284
|
+
assert.match(summaryContent, /blocker_discovered: false/, 'summary should contain blocker_discovered');
|
|
285
|
+
assert.match(summaryContent, /# T01:/, 'summary should have H1 with task ID');
|
|
286
|
+
assert.match(summaryContent, /\*\*Added test functionality\*\*/, 'summary should have one-liner in bold');
|
|
287
|
+
assert.match(summaryContent, /## What Happened/, 'summary should have What Happened section');
|
|
288
|
+
assert.match(summaryContent, /## Verification Evidence/, 'summary should have Verification Evidence section');
|
|
289
|
+
assert.match(summaryContent, /npm run test:unit/, 'summary evidence should contain command');
|
|
290
|
+
|
|
291
|
+
// (d) Verify plan checkbox changed to [x]
|
|
292
|
+
const planContent = fs.readFileSync(planPath, 'utf-8');
|
|
293
|
+
assert.match(planContent, /\[x\]\s+\*\*T01:/, 'T01 should be checked in plan');
|
|
294
|
+
// T02 should still be unchecked
|
|
295
|
+
assert.match(planContent, /\[ \]\s+\*\*T02:/, 'T02 should still be unchecked in plan');
|
|
296
|
+
|
|
297
|
+
// (e) Verify full_summary_md stored in DB for D004 recovery
|
|
298
|
+
const taskAfter = getTask('M001', 'S01', 'T01');
|
|
299
|
+
assert.ok(taskAfter!.full_summary_md.length > 0, 'full_summary_md should be non-empty in DB');
|
|
300
|
+
assert.match(taskAfter!.full_summary_md, /id: T01/, 'full_summary_md should contain frontmatter');
|
|
301
|
+
}
|
|
358
302
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
if ('error' in r2) {
|
|
363
|
-
assertMatch(r2.error, /milestoneId/, 'error should mention milestoneId');
|
|
364
|
-
}
|
|
303
|
+
cleanupDir(basePath);
|
|
304
|
+
cleanup(dbPath);
|
|
305
|
+
});
|
|
365
306
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
if ('error' in r3) {
|
|
370
|
-
assertMatch(r3.error, /sliceId/, 'error should mention sliceId');
|
|
371
|
-
}
|
|
307
|
+
test("validation errors", async () => {
|
|
308
|
+
const dbPath = tempDbPath();
|
|
309
|
+
openDatabase(dbPath);
|
|
372
310
|
|
|
373
|
-
|
|
374
|
-
}
|
|
311
|
+
const params = makeValidParams();
|
|
375
312
|
|
|
376
|
-
//
|
|
377
|
-
|
|
378
|
-
|
|
313
|
+
// Empty taskId
|
|
314
|
+
const r1 = await handleCompleteTask({ ...params, taskId: '' }, '/tmp/fake');
|
|
315
|
+
assert.ok('error' in r1, 'should return error for empty taskId');
|
|
316
|
+
if ('error' in r1) {
|
|
317
|
+
assert.match(r1.error, /taskId/, 'error should mention taskId');
|
|
318
|
+
}
|
|
379
319
|
|
|
380
|
-
|
|
381
|
-
{
|
|
382
|
-
|
|
383
|
-
|
|
320
|
+
// Empty milestoneId
|
|
321
|
+
const r2 = await handleCompleteTask({ ...params, milestoneId: '' }, '/tmp/fake');
|
|
322
|
+
assert.ok('error' in r2, 'should return error for empty milestoneId');
|
|
323
|
+
if ('error' in r2) {
|
|
324
|
+
assert.match(r2.error, /milestoneId/, 'error should mention milestoneId');
|
|
325
|
+
}
|
|
384
326
|
|
|
385
|
-
|
|
327
|
+
// Empty sliceId
|
|
328
|
+
const r3 = await handleCompleteTask({ ...params, sliceId: '' }, '/tmp/fake');
|
|
329
|
+
assert.ok('error' in r3, 'should return error for empty sliceId');
|
|
330
|
+
if ('error' in r3) {
|
|
331
|
+
assert.match(r3.error, /sliceId/, 'error should mention sliceId');
|
|
332
|
+
}
|
|
386
333
|
|
|
387
|
-
|
|
334
|
+
cleanup(dbPath);
|
|
335
|
+
});
|
|
388
336
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
337
|
+
test("idempotency", async () => {
|
|
338
|
+
const dbPath = tempDbPath();
|
|
339
|
+
openDatabase(dbPath);
|
|
392
340
|
|
|
393
|
-
|
|
394
|
-
const r2 = await handleCompleteTask(params, basePath);
|
|
395
|
-
assertTrue(!('error' in r2), 'second call should succeed (idempotent)');
|
|
341
|
+
const { basePath, planPath } = createTempProject();
|
|
396
342
|
|
|
397
|
-
|
|
398
|
-
const tasks = getSliceTasks('M001', 'S01');
|
|
399
|
-
assertEq(tasks.length, 1, 'should have exactly 1 task row after 2 calls (upsert)');
|
|
343
|
+
const params = makeValidParams();
|
|
400
344
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
}
|
|
345
|
+
// First call
|
|
346
|
+
const r1 = await handleCompleteTask(params, basePath);
|
|
347
|
+
assert.ok(!('error' in r1), 'first call should succeed');
|
|
405
348
|
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
349
|
+
// Second call with same params — should not crash (INSERT OR REPLACE)
|
|
350
|
+
const r2 = await handleCompleteTask(params, basePath);
|
|
351
|
+
assert.ok(!('error' in r2), 'second call should succeed (idempotent)');
|
|
409
352
|
|
|
410
|
-
//
|
|
411
|
-
|
|
412
|
-
|
|
353
|
+
// Verify only 1 task row (upserted, not duplicated)
|
|
354
|
+
const tasks = getSliceTasks('M001', 'S01');
|
|
355
|
+
assert.strictEqual(tasks.length, 1, 'should have exactly 1 task row after 2 calls (upsert)');
|
|
413
356
|
|
|
414
|
-
|
|
415
|
-
{
|
|
416
|
-
|
|
417
|
-
|
|
357
|
+
// File should still exist
|
|
358
|
+
if (!('error' in r2)) {
|
|
359
|
+
assert.ok(fs.existsSync(r2.summaryPath), 'summary should still exist after second call');
|
|
360
|
+
}
|
|
418
361
|
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
fs.mkdirSync(tasksDir, { recursive: true });
|
|
362
|
+
cleanupDir(basePath);
|
|
363
|
+
cleanup(dbPath);
|
|
364
|
+
});
|
|
423
365
|
|
|
424
|
-
|
|
425
|
-
|
|
366
|
+
test("missing plan file (graceful)", async () => {
|
|
367
|
+
const dbPath = tempDbPath();
|
|
368
|
+
openDatabase(dbPath);
|
|
426
369
|
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
}
|
|
370
|
+
// Create a temp dir WITHOUT a plan file
|
|
371
|
+
const basePath = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-no-plan-'));
|
|
372
|
+
const tasksDir = path.join(basePath, '.gsd', 'milestones', 'M001', 'slices', 'S01', 'tasks');
|
|
373
|
+
fs.mkdirSync(tasksDir, { recursive: true });
|
|
432
374
|
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
}
|
|
375
|
+
const params = makeValidParams();
|
|
376
|
+
const result = await handleCompleteTask(params, basePath);
|
|
436
377
|
|
|
437
|
-
//
|
|
378
|
+
// Should succeed even without plan file — just skip checkbox toggle
|
|
379
|
+
assert.ok(!('error' in result), 'handler should succeed without plan file');
|
|
380
|
+
if (!('error' in result)) {
|
|
381
|
+
assert.ok(fs.existsSync(result.summaryPath), 'summary should be written even without plan file');
|
|
382
|
+
}
|
|
438
383
|
|
|
439
|
-
|
|
384
|
+
cleanupDir(basePath);
|
|
385
|
+
cleanup(dbPath);
|
|
386
|
+
});
|
|
387
|
+
});
|