gsd-pi 2.51.0 → 2.52.0-dev.655ad8a
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 +59 -36
- package/dist/headless-events.d.ts +18 -0
- package/dist/headless-events.js +36 -0
- package/dist/headless-query.js +1 -1
- package/dist/headless-types.d.ts +28 -0
- package/dist/headless-types.js +7 -0
- package/dist/headless.d.ts +8 -3
- package/dist/headless.js +47 -16
- package/dist/help-text.js +16 -5
- package/dist/onboarding.js +5 -4
- package/dist/remote-questions-config.js +1 -1
- package/dist/resources/extensions/async-jobs/async-bash-tool.js +29 -17
- package/dist/resources/extensions/async-jobs/job-manager.js +4 -1
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +18 -19
- package/dist/resources/extensions/get-secrets-from-user.js +7 -0
- package/dist/resources/extensions/gsd/auto/phases.js +34 -8
- package/dist/resources/extensions/gsd/auto-dispatch.js +23 -1
- package/dist/resources/extensions/gsd/auto-start.js +2 -0
- package/dist/resources/extensions/gsd/auto-timers.js +24 -2
- package/dist/resources/extensions/gsd/auto-tool-tracking.js +25 -7
- package/dist/resources/extensions/gsd/auto-worktree.js +91 -14
- package/dist/resources/extensions/gsd/auto.js +30 -4
- package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +99 -70
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +12 -2
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +1 -1
- package/dist/resources/extensions/gsd/claude-import.js +60 -9
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +69 -6
- package/dist/resources/extensions/gsd/commands-config.js +10 -5
- package/dist/resources/extensions/gsd/commands-prefs-wizard.js +4 -4
- package/dist/resources/extensions/gsd/detection.js +6 -6
- package/dist/resources/extensions/gsd/docs/preferences-reference.md +5 -5
- package/dist/resources/extensions/gsd/error-classifier.js +105 -0
- package/dist/resources/extensions/gsd/git-service.js +4 -3
- package/dist/resources/extensions/gsd/gitignore.js +7 -7
- package/dist/resources/extensions/gsd/gsd-db.js +298 -45
- package/dist/resources/extensions/gsd/guided-flow.js +4 -3
- package/dist/resources/extensions/gsd/init-wizard.js +2 -2
- package/dist/resources/extensions/gsd/key-manager.js +7 -16
- package/dist/resources/extensions/gsd/markdown-renderer.js +5 -4
- package/dist/resources/extensions/gsd/memory-store.js +28 -13
- package/dist/resources/extensions/gsd/milestone-actions.js +19 -0
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +18 -2
- package/dist/resources/extensions/gsd/preferences-models.js +1 -13
- package/dist/resources/extensions/gsd/preferences-types.js +1 -1
- package/dist/resources/extensions/gsd/preferences.js +13 -13
- package/dist/resources/extensions/gsd/prompts/system.md +1 -1
- package/dist/resources/extensions/gsd/provider-error-pause.js +0 -44
- package/dist/resources/extensions/gsd/rule-registry.js +1 -1
- package/dist/resources/extensions/gsd/service-tier.js +13 -2
- package/dist/resources/extensions/gsd/state.js +38 -30
- package/dist/resources/extensions/gsd/status-guards.js +12 -0
- package/dist/resources/extensions/gsd/tools/complete-milestone.js +7 -13
- package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -20
- package/dist/resources/extensions/gsd/tools/complete-task.js +11 -21
- package/dist/resources/extensions/gsd/tools/plan-milestone.js +28 -29
- package/dist/resources/extensions/gsd/tools/plan-slice.js +27 -26
- package/dist/resources/extensions/gsd/tools/plan-task.js +23 -23
- package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +50 -41
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +4 -3
- package/dist/resources/extensions/gsd/tools/reopen-task.js +5 -4
- package/dist/resources/extensions/gsd/tools/replan-slice.js +51 -41
- package/dist/resources/extensions/gsd/tools/validate-milestone.js +23 -16
- package/dist/resources/extensions/gsd/validation.js +21 -0
- package/dist/resources/extensions/gsd/workflow-logger.js +0 -1
- package/dist/resources/extensions/remote-questions/config.js +1 -1
- package/dist/resources/extensions/remote-questions/remote-command.js +1 -1
- package/dist/resources/extensions/search-the-web/native-search.js +1 -1
- package/dist/resources/extensions/search-the-web/provider.js +1 -1
- package/dist/resources/extensions/shared/rtk.js +14 -4
- package/dist/rtk.js +3 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
- package/dist/web/standalone/.next/build-manifest.json +4 -4
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/required-server-files.json +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
- package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
- package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
- 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/experimental/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +5 -5
- 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 +5 -5
- 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 +11 -11
- package/dist/web/standalone/.next/server/chunks/2229.js +3 -3
- package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware.js +2 -2
- package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
- package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +2 -2
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/4024.87fd909ae0110f50.js +9 -0
- package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
- package/dist/web/standalone/.next/static/chunks/app/page-b950e4e384cc62b3.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-cfc9a116e6450a6b.js → webpack-bca0e732db0dcec3.js} +1 -1
- package/dist/web/standalone/.next/static/css/a58ef8a151aa0493.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/dist/wizard.js +4 -1
- package/package.json +2 -2
- package/packages/mcp-server/README.md +202 -0
- package/packages/mcp-server/package.json +36 -0
- package/packages/mcp-server/src/cli.ts +68 -0
- package/packages/mcp-server/src/index.ts +14 -0
- package/packages/mcp-server/src/mcp-server.test.ts +628 -0
- package/packages/mcp-server/src/server.ts +278 -0
- package/packages/mcp-server/src/session-manager.ts +328 -0
- package/packages/mcp-server/src/types.ts +107 -0
- package/packages/mcp-server/tsconfig.json +24 -0
- package/packages/pi-ai/dist/models.d.ts +14 -3
- package/packages/pi-ai/dist/models.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.js +53 -10
- package/packages/pi-ai/dist/models.js.map +1 -1
- package/packages/pi-ai/dist/models.test.js +102 -1
- package/packages/pi-ai/dist/models.test.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +30 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/src/models.test.ts +114 -1
- package/packages/pi-ai/src/models.ts +70 -13
- package/packages/pi-ai/src/types.ts +31 -0
- package/packages/pi-coding-agent/dist/cli/args.d.ts +2 -0
- package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/cli/args.js +3 -0
- package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.js +5 -1
- package/packages/pi-coding-agent/dist/core/bash-executor.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/model-registry.js +9 -4
- package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.d.ts +19 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +83 -0
- package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js +5 -1
- package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/main.js +5 -3
- package/packages/pi-coding-agent/dist/main.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/index.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/index.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 +0 -2
- package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts +28 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +49 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +114 -6
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.d.ts +9 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.js +831 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +66 -0
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/utils/shell.js +0 -1
- package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
- package/packages/pi-coding-agent/package.json +1 -1
- package/packages/pi-coding-agent/src/cli/args.ts +4 -0
- package/packages/pi-coding-agent/src/core/bash-executor.ts +5 -1
- package/packages/pi-coding-agent/src/core/model-registry.ts +10 -3
- package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +101 -0
- package/packages/pi-coding-agent/src/core/tools/bash.ts +5 -1
- package/packages/pi-coding-agent/src/index.ts +3 -0
- package/packages/pi-coding-agent/src/main.ts +5 -3
- package/packages/pi-coding-agent/src/modes/index.ts +8 -1
- package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +0 -2
- package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +54 -1
- package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +124 -6
- package/packages/pi-coding-agent/src/modes/rpc/rpc-protocol-v2.test.ts +971 -0
- package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +61 -4
- package/packages/pi-coding-agent/src/utils/shell.ts +0 -1
- package/packages/rpc-client/package.json +20 -0
- package/pkg/package.json +1 -1
- package/scripts/ensure-workspace-builds.cjs +36 -8
- package/src/resources/extensions/async-jobs/async-bash-tool.ts +22 -11
- package/src/resources/extensions/async-jobs/job-manager.ts +4 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +19 -20
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +21 -0
- package/src/resources/extensions/get-secrets-from-user.ts +8 -0
- package/src/resources/extensions/gsd/auto/phases.ts +44 -7
- package/src/resources/extensions/gsd/auto-dispatch.ts +25 -1
- package/src/resources/extensions/gsd/auto-start.ts +2 -0
- package/src/resources/extensions/gsd/auto-timers.ts +25 -1
- package/src/resources/extensions/gsd/auto-tool-tracking.ts +30 -6
- package/src/resources/extensions/gsd/auto-worktree.ts +94 -14
- package/src/resources/extensions/gsd/auto.ts +31 -4
- package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +118 -73
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +11 -2
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +1 -1
- package/src/resources/extensions/gsd/claude-import.ts +58 -9
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +73 -6
- package/src/resources/extensions/gsd/commands-config.ts +11 -5
- package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -4
- package/src/resources/extensions/gsd/detection.ts +6 -6
- package/src/resources/extensions/gsd/docs/preferences-reference.md +5 -5
- package/src/resources/extensions/gsd/error-classifier.ts +139 -0
- package/src/resources/extensions/gsd/git-service.ts +4 -3
- package/src/resources/extensions/gsd/gitignore.ts +7 -7
- package/src/resources/extensions/gsd/gsd-db.ts +355 -63
- package/src/resources/extensions/gsd/guided-flow.ts +4 -3
- package/src/resources/extensions/gsd/init-wizard.ts +2 -2
- package/src/resources/extensions/gsd/key-manager.ts +7 -16
- package/src/resources/extensions/gsd/markdown-renderer.ts +5 -4
- package/src/resources/extensions/gsd/memory-store.ts +29 -18
- package/src/resources/extensions/gsd/milestone-actions.ts +17 -0
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +23 -1
- package/src/resources/extensions/gsd/preferences-models.ts +1 -13
- package/src/resources/extensions/gsd/preferences-types.ts +1 -1
- package/src/resources/extensions/gsd/preferences.ts +12 -13
- package/src/resources/extensions/gsd/prompts/system.md +1 -1
- package/src/resources/extensions/gsd/provider-error-pause.ts +0 -57
- package/src/resources/extensions/gsd/rule-registry.ts +1 -1
- package/src/resources/extensions/gsd/service-tier.ts +14 -2
- package/src/resources/extensions/gsd/state.ts +39 -30
- package/src/resources/extensions/gsd/status-guards.ts +13 -0
- package/src/resources/extensions/gsd/tests/active-milestone-id-guard.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +61 -0
- package/src/resources/extensions/gsd/tests/auto-stale-lock-self-kill.test.ts +87 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +80 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/claude-import-marketplace-discovery.test.ts +191 -0
- package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +39 -0
- package/src/resources/extensions/gsd/tests/commands-config.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +106 -0
- package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +35 -7
- package/src/resources/extensions/gsd/tests/detection.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/doctor-git.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/empty-db-reconciliation.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/git-service.test.ts +65 -31
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/init-wizard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/interactive-tool-idle-exemption.test.ts +119 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +51 -0
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +7 -7
- package/src/resources/extensions/gsd/tests/parallel-orchestrator-zombie-cleanup.test.ts +277 -0
- package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +85 -0
- package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +103 -0
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +77 -70
- package/src/resources/extensions/gsd/tests/rate-limit-model-fallback.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +110 -0
- package/src/resources/extensions/gsd/tests/remote-questions.test.ts +29 -0
- package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +9 -8
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +125 -0
- package/src/resources/extensions/gsd/tests/status-guards.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +42 -31
- package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/vacuous-truth-slices.test.ts +115 -0
- package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +90 -0
- package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -2
- package/src/resources/extensions/gsd/tests/validation-gate-patterns.test.ts +124 -0
- package/src/resources/extensions/gsd/tests/validation.test.ts +72 -0
- package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +81 -1
- package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +130 -0
- package/src/resources/extensions/gsd/tools/complete-milestone.ts +7 -17
- package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -24
- package/src/resources/extensions/gsd/tools/complete-task.ts +13 -25
- package/src/resources/extensions/gsd/tools/plan-milestone.ts +30 -32
- package/src/resources/extensions/gsd/tools/plan-slice.ts +30 -30
- package/src/resources/extensions/gsd/tools/plan-task.ts +26 -26
- package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +57 -46
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +4 -3
- package/src/resources/extensions/gsd/tools/reopen-task.ts +5 -4
- package/src/resources/extensions/gsd/tools/replan-slice.ts +55 -44
- package/src/resources/extensions/gsd/tools/validate-milestone.ts +26 -20
- package/src/resources/extensions/gsd/validation.ts +23 -0
- package/src/resources/extensions/gsd/workflow-logger.ts +0 -1
- package/src/resources/extensions/remote-questions/config.ts +1 -1
- package/src/resources/extensions/remote-questions/remote-command.ts +1 -1
- package/src/resources/extensions/search-the-web/native-search.ts +1 -1
- package/src/resources/extensions/search-the-web/provider.ts +1 -1
- package/src/resources/extensions/shared/rtk.ts +22 -4
- package/dist/web/standalone/.next/static/chunks/4024.9ad5def014d90ce4.js +0 -9
- package/dist/web/standalone/.next/static/chunks/app/page-fbecd1237e2d6d1f.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/css/de141508b083f922.css +0 -1
- /package/dist/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -0
- /package/dist/web/standalone/.next/static/{vkr67v-utm1dgZnbrBWQh → zpvUPKoW5jRAMB_fWHlPi}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{vkr67v-utm1dgZnbrBWQh → zpvUPKoW5jRAMB_fWHlPi}/_ssgManifest.js +0 -0
- /package/src/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -0
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified error classifier for provider/network/server errors.
|
|
3
|
+
*
|
|
4
|
+
* Consolidates patterns from:
|
|
5
|
+
* - isTransientNetworkError() in preferences-models.ts
|
|
6
|
+
* - classifyProviderError() in provider-error-pause.ts
|
|
7
|
+
*
|
|
8
|
+
* Single entry point: classifyError(errorMsg, retryAfterMs?)
|
|
9
|
+
*
|
|
10
|
+
* @see https://github.com/gsd-build/gsd/issues/2577
|
|
11
|
+
*/
|
|
12
|
+
export function createRetryState() {
|
|
13
|
+
return { networkRetryCount: 0, consecutiveTransientCount: 0, currentRetryModelId: undefined };
|
|
14
|
+
}
|
|
15
|
+
export function resetRetryState(state) {
|
|
16
|
+
state.networkRetryCount = 0;
|
|
17
|
+
state.consecutiveTransientCount = 0;
|
|
18
|
+
state.currentRetryModelId = undefined;
|
|
19
|
+
}
|
|
20
|
+
// ── Classification ──────────────────────────────────────────────────────────
|
|
21
|
+
const PERMANENT_RE = /auth|unauthorized|forbidden|invalid.*key|invalid.*api|billing|quota exceeded|account/i;
|
|
22
|
+
const RATE_LIMIT_RE = /rate.?limit|too many requests|429/i;
|
|
23
|
+
const NETWORK_RE = /network|ECONNRESET|ETIMEDOUT|ECONNREFUSED|socket hang up|fetch failed|connection.*reset|dns/i;
|
|
24
|
+
const SERVER_RE = /internal server error|500|502|503|overloaded|server_error|api_error|service.?unavailable/i;
|
|
25
|
+
// ECONNRESET/ECONNREFUSED are in NETWORK_RE (same-model retry first).
|
|
26
|
+
const CONNECTION_RE = /terminated|connection.?refused|other side closed|EPIPE|network.?(?:is\s+)?unavailable|stream_exhausted(?:_without_result)?/i;
|
|
27
|
+
const STREAM_RE = /Unexpected end of JSON|Unexpected token.*JSON|Expected double-quoted property name|SyntaxError.*JSON/i;
|
|
28
|
+
const RESET_DELAY_RE = /reset in (\d+)s/i;
|
|
29
|
+
/**
|
|
30
|
+
* Classify an error message into one of the ErrorClass kinds.
|
|
31
|
+
*
|
|
32
|
+
* Classification order:
|
|
33
|
+
* 1. Permanent (auth/billing/quota) — unless also rate-limited
|
|
34
|
+
* 2. Rate limit (429, rate.?limit, too many requests)
|
|
35
|
+
* 3. Network (ECONNRESET, ETIMEDOUT, socket hang up, fetch failed, dns)
|
|
36
|
+
* 4. Server (500/502/503, overloaded, server_error)
|
|
37
|
+
* 5. Connection (terminated, ECONNREFUSED, EPIPE, other side closed)
|
|
38
|
+
* 6. Stream truncation (malformed JSON from mid-stream cut)
|
|
39
|
+
* 7. Unknown
|
|
40
|
+
*/
|
|
41
|
+
export function classifyError(errorMsg, retryAfterMs) {
|
|
42
|
+
const isPermanent = PERMANENT_RE.test(errorMsg);
|
|
43
|
+
const isRateLimit = RATE_LIMIT_RE.test(errorMsg);
|
|
44
|
+
// 1. Permanent — but rate limit takes precedence
|
|
45
|
+
if (isPermanent && !isRateLimit) {
|
|
46
|
+
return { kind: "permanent" };
|
|
47
|
+
}
|
|
48
|
+
// 2. Rate limit
|
|
49
|
+
if (isRateLimit) {
|
|
50
|
+
if (retryAfterMs != null && retryAfterMs > 0) {
|
|
51
|
+
return { kind: "rate-limit", retryAfterMs };
|
|
52
|
+
}
|
|
53
|
+
const resetMatch = errorMsg.match(RESET_DELAY_RE);
|
|
54
|
+
const delayMs = resetMatch ? Number(resetMatch[1]) * 1000 : 60_000;
|
|
55
|
+
return { kind: "rate-limit", retryAfterMs: delayMs };
|
|
56
|
+
}
|
|
57
|
+
// 3. Network errors — same-model retry candidate
|
|
58
|
+
if (NETWORK_RE.test(errorMsg)) {
|
|
59
|
+
// Exclude if also matches permanent signals (already handled above for
|
|
60
|
+
// rate-limit, but double-check for non-rate-limit permanent overlap like
|
|
61
|
+
// "billing" appearing alongside "network").
|
|
62
|
+
return { kind: "network", retryAfterMs: retryAfterMs ?? 3_000 };
|
|
63
|
+
}
|
|
64
|
+
// 4. Server errors — try fallback model
|
|
65
|
+
if (SERVER_RE.test(errorMsg)) {
|
|
66
|
+
return { kind: "server", retryAfterMs: retryAfterMs ?? 30_000 };
|
|
67
|
+
}
|
|
68
|
+
// 5. Connection errors — try fallback model
|
|
69
|
+
if (CONNECTION_RE.test(errorMsg)) {
|
|
70
|
+
return { kind: "connection", retryAfterMs: retryAfterMs ?? 15_000 };
|
|
71
|
+
}
|
|
72
|
+
// 6. Stream truncation — downstream symptom of connection drop
|
|
73
|
+
if (STREAM_RE.test(errorMsg)) {
|
|
74
|
+
return { kind: "stream", retryAfterMs: retryAfterMs ?? 15_000 };
|
|
75
|
+
}
|
|
76
|
+
// 7. Unknown
|
|
77
|
+
return { kind: "unknown" };
|
|
78
|
+
}
|
|
79
|
+
// ── Helpers ─────────────────────────────────────────────────────────────────
|
|
80
|
+
/** Returns true for all transient (auto-resumable) error kinds. */
|
|
81
|
+
export function isTransient(cls) {
|
|
82
|
+
switch (cls.kind) {
|
|
83
|
+
case "network":
|
|
84
|
+
case "rate-limit":
|
|
85
|
+
case "server":
|
|
86
|
+
case "stream":
|
|
87
|
+
case "connection":
|
|
88
|
+
return true;
|
|
89
|
+
default:
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Backward-compatible thin wrapper.
|
|
95
|
+
*
|
|
96
|
+
* Returns true when the error is a transient *network* error specifically
|
|
97
|
+
* (worth retrying the same model). Permanent signals (auth, billing, quota)
|
|
98
|
+
* cause this to return false even if a network keyword is present.
|
|
99
|
+
*/
|
|
100
|
+
export function isTransientNetworkError(errorMsg) {
|
|
101
|
+
if (!errorMsg)
|
|
102
|
+
return false;
|
|
103
|
+
const cls = classifyError(errorMsg);
|
|
104
|
+
return cls.kind === "network";
|
|
105
|
+
}
|
|
@@ -446,11 +446,12 @@ export class GitServiceImpl {
|
|
|
446
446
|
}
|
|
447
447
|
/**
|
|
448
448
|
* Create a snapshot ref for the given label (typically a slice branch name).
|
|
449
|
-
*
|
|
449
|
+
* Enabled by default; opt out with prefs.snapshots === false.
|
|
450
|
+
* Ref path: refs/gsd/snapshots/<label>/<timestamp>
|
|
450
451
|
* The ref points at HEAD, capturing the current commit before destructive operations.
|
|
451
452
|
*/
|
|
452
453
|
createSnapshot(label) {
|
|
453
|
-
if (this.prefs.snapshots
|
|
454
|
+
if (this.prefs.snapshots === false)
|
|
454
455
|
return;
|
|
455
456
|
const now = new Date();
|
|
456
457
|
const ts = now.getFullYear().toString()
|
|
@@ -470,7 +471,7 @@ export class GitServiceImpl {
|
|
|
470
471
|
* Stub: to be implemented in T03.
|
|
471
472
|
*/
|
|
472
473
|
runPreMergeCheck() {
|
|
473
|
-
if (this.prefs.pre_merge_check === false
|
|
474
|
+
if (this.prefs.pre_merge_check === false) {
|
|
474
475
|
return { passed: true, skipped: true };
|
|
475
476
|
}
|
|
476
477
|
// Determine command: explicit string or auto-detect from package.json
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* GSD bootstrappers for .gitignore and
|
|
2
|
+
* GSD bootstrappers for .gitignore and PREFERENCES.md
|
|
3
3
|
*
|
|
4
4
|
* Ensures baseline .gitignore exists with universally-correct patterns.
|
|
5
|
-
* Creates an empty
|
|
5
|
+
* Creates an empty PREFERENCES.md template if it doesn't exist.
|
|
6
6
|
* Both idempotent — non-destructive if already present.
|
|
7
7
|
*/
|
|
8
8
|
import { join } from "node:path";
|
|
@@ -190,16 +190,16 @@ export function untrackRuntimeFiles(basePath) {
|
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
192
|
/**
|
|
193
|
-
* Ensure basePath/.gsd/
|
|
193
|
+
* Ensure basePath/.gsd/PREFERENCES.md exists as an empty template.
|
|
194
194
|
* Creates the file with frontmatter only if it doesn't exist.
|
|
195
195
|
* Returns true if created, false if already exists.
|
|
196
196
|
*
|
|
197
|
-
* Checks both
|
|
198
|
-
* creating a duplicate when
|
|
197
|
+
* Checks both uppercase (canonical) and lowercase (legacy) to avoid
|
|
198
|
+
* creating a duplicate when a lowercase file already exists.
|
|
199
199
|
*/
|
|
200
200
|
export function ensurePreferences(basePath) {
|
|
201
|
-
const preferencesPath = join(gsdRoot(basePath), "
|
|
202
|
-
const legacyPath = join(gsdRoot(basePath), "
|
|
201
|
+
const preferencesPath = join(gsdRoot(basePath), "PREFERENCES.md");
|
|
202
|
+
const legacyPath = join(gsdRoot(basePath), "preferences.md");
|
|
203
203
|
if (existsSync(preferencesPath) || existsSync(legacyPath)) {
|
|
204
204
|
return false;
|
|
205
205
|
}
|
|
@@ -75,25 +75,34 @@ function normalizeRows(rows) {
|
|
|
75
75
|
}
|
|
76
76
|
function createAdapter(rawDb) {
|
|
77
77
|
const db = rawDb;
|
|
78
|
+
const stmtCache = new Map();
|
|
79
|
+
function wrapStmt(raw) {
|
|
80
|
+
return {
|
|
81
|
+
run(...params) {
|
|
82
|
+
return raw.run(...params);
|
|
83
|
+
},
|
|
84
|
+
get(...params) {
|
|
85
|
+
return normalizeRow(raw.get(...params));
|
|
86
|
+
},
|
|
87
|
+
all(...params) {
|
|
88
|
+
return normalizeRows(raw.all(...params));
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
78
92
|
return {
|
|
79
93
|
exec(sql) {
|
|
80
94
|
db.exec(sql);
|
|
81
95
|
},
|
|
82
96
|
prepare(sql) {
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
return normalizeRow(stmt.get(...params));
|
|
90
|
-
},
|
|
91
|
-
all(...params) {
|
|
92
|
-
return normalizeRows(stmt.all(...params));
|
|
93
|
-
},
|
|
94
|
-
};
|
|
97
|
+
let cached = stmtCache.get(sql);
|
|
98
|
+
if (cached)
|
|
99
|
+
return cached;
|
|
100
|
+
cached = wrapStmt(db.prepare(sql));
|
|
101
|
+
stmtCache.set(sql, cached);
|
|
102
|
+
return cached;
|
|
95
103
|
},
|
|
96
104
|
close() {
|
|
105
|
+
stmtCache.clear();
|
|
97
106
|
db.close();
|
|
98
107
|
},
|
|
99
108
|
};
|
|
@@ -109,12 +118,21 @@ function openRawDb(path) {
|
|
|
109
118
|
const Database = providerModule;
|
|
110
119
|
return new Database(path);
|
|
111
120
|
}
|
|
112
|
-
const SCHEMA_VERSION =
|
|
121
|
+
const SCHEMA_VERSION = 14;
|
|
113
122
|
function initSchema(db, fileBacked) {
|
|
114
123
|
if (fileBacked)
|
|
115
124
|
db.exec("PRAGMA journal_mode=WAL");
|
|
116
125
|
if (fileBacked)
|
|
117
126
|
db.exec("PRAGMA busy_timeout = 5000");
|
|
127
|
+
if (fileBacked)
|
|
128
|
+
db.exec("PRAGMA synchronous = NORMAL");
|
|
129
|
+
if (fileBacked)
|
|
130
|
+
db.exec("PRAGMA auto_vacuum = INCREMENTAL");
|
|
131
|
+
if (fileBacked)
|
|
132
|
+
db.exec("PRAGMA cache_size = -8000"); // 8 MB page cache
|
|
133
|
+
if (fileBacked)
|
|
134
|
+
db.exec("PRAGMA mmap_size = 67108864"); // 64 MB mmap
|
|
135
|
+
db.exec("PRAGMA temp_store = MEMORY");
|
|
118
136
|
db.exec("PRAGMA foreign_keys = ON");
|
|
119
137
|
db.exec("BEGIN");
|
|
120
138
|
try {
|
|
@@ -226,7 +244,7 @@ function initSchema(db, fileBacked) {
|
|
|
226
244
|
proof_level TEXT NOT NULL DEFAULT '',
|
|
227
245
|
integration_closure TEXT NOT NULL DEFAULT '',
|
|
228
246
|
observability_impact TEXT NOT NULL DEFAULT '',
|
|
229
|
-
sequence INTEGER DEFAULT 0, --
|
|
247
|
+
sequence INTEGER DEFAULT 0, -- Ordering hint: tools may set this to control execution order
|
|
230
248
|
replan_triggered_at TEXT DEFAULT NULL,
|
|
231
249
|
PRIMARY KEY (milestone_id, id),
|
|
232
250
|
FOREIGN KEY (milestone_id) REFERENCES milestones(id)
|
|
@@ -258,7 +276,7 @@ function initSchema(db, fileBacked) {
|
|
|
258
276
|
expected_output TEXT NOT NULL DEFAULT '[]',
|
|
259
277
|
observability_impact TEXT NOT NULL DEFAULT '',
|
|
260
278
|
full_plan_md TEXT NOT NULL DEFAULT '',
|
|
261
|
-
sequence INTEGER DEFAULT 0, --
|
|
279
|
+
sequence INTEGER DEFAULT 0, -- Ordering hint: tools may set this to control execution order
|
|
262
280
|
PRIMARY KEY (milestone_id, slice_id, id),
|
|
263
281
|
FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
|
|
264
282
|
)
|
|
@@ -318,9 +336,28 @@ function initSchema(db, fileBacked) {
|
|
|
318
336
|
PRIMARY KEY (milestone_id, slice_id, gate_id, task_id),
|
|
319
337
|
FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
|
|
320
338
|
)
|
|
339
|
+
`);
|
|
340
|
+
// Slice dependency junction table (v14)
|
|
341
|
+
db.exec(`
|
|
342
|
+
CREATE TABLE IF NOT EXISTS slice_dependencies (
|
|
343
|
+
milestone_id TEXT NOT NULL,
|
|
344
|
+
slice_id TEXT NOT NULL,
|
|
345
|
+
depends_on_slice_id TEXT NOT NULL,
|
|
346
|
+
PRIMARY KEY (milestone_id, slice_id, depends_on_slice_id),
|
|
347
|
+
FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id),
|
|
348
|
+
FOREIGN KEY (milestone_id, depends_on_slice_id) REFERENCES slices(milestone_id, id)
|
|
349
|
+
)
|
|
321
350
|
`);
|
|
322
351
|
db.exec("CREATE INDEX IF NOT EXISTS idx_memories_active ON memories(superseded_by)");
|
|
323
352
|
db.exec("CREATE INDEX IF NOT EXISTS idx_replan_history_milestone ON replan_history(milestone_id, created_at)");
|
|
353
|
+
// v13 indexes — hot-path dispatch queries
|
|
354
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_active ON tasks(milestone_id, slice_id, status)");
|
|
355
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_slices_active ON slices(milestone_id, status)");
|
|
356
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
|
|
357
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
|
|
358
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
|
|
359
|
+
// v14 index — slice dependency lookups
|
|
360
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_slice_deps_target ON slice_dependencies(milestone_id, depends_on_slice_id)");
|
|
324
361
|
db.exec(`CREATE VIEW IF NOT EXISTS active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL`);
|
|
325
362
|
db.exec(`CREATE VIEW IF NOT EXISTS active_requirements AS SELECT * FROM requirements WHERE superseded_by IS NULL`);
|
|
326
363
|
db.exec(`CREATE VIEW IF NOT EXISTS active_memories AS SELECT * FROM memories WHERE superseded_by IS NULL`);
|
|
@@ -599,6 +636,35 @@ function migrateSchema(db) {
|
|
|
599
636
|
":applied_at": new Date().toISOString(),
|
|
600
637
|
});
|
|
601
638
|
}
|
|
639
|
+
if (currentVersion < 13) {
|
|
640
|
+
// Hot-path indexes for auto-loop dispatch queries
|
|
641
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_active ON tasks(milestone_id, slice_id, status)");
|
|
642
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_slices_active ON slices(milestone_id, status)");
|
|
643
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
|
|
644
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
|
|
645
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
|
|
646
|
+
db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
|
|
647
|
+
":version": 13,
|
|
648
|
+
":applied_at": new Date().toISOString(),
|
|
649
|
+
});
|
|
650
|
+
}
|
|
651
|
+
if (currentVersion < 14) {
|
|
652
|
+
db.exec(`
|
|
653
|
+
CREATE TABLE IF NOT EXISTS slice_dependencies (
|
|
654
|
+
milestone_id TEXT NOT NULL,
|
|
655
|
+
slice_id TEXT NOT NULL,
|
|
656
|
+
depends_on_slice_id TEXT NOT NULL,
|
|
657
|
+
PRIMARY KEY (milestone_id, slice_id, depends_on_slice_id),
|
|
658
|
+
FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id),
|
|
659
|
+
FOREIGN KEY (milestone_id, depends_on_slice_id) REFERENCES slices(milestone_id, id)
|
|
660
|
+
)
|
|
661
|
+
`);
|
|
662
|
+
db.exec("CREATE INDEX IF NOT EXISTS idx_slice_deps_target ON slice_dependencies(milestone_id, depends_on_slice_id)");
|
|
663
|
+
db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
|
|
664
|
+
":version": 14,
|
|
665
|
+
":applied_at": new Date().toISOString(),
|
|
666
|
+
});
|
|
667
|
+
}
|
|
602
668
|
db.exec("COMMIT");
|
|
603
669
|
}
|
|
604
670
|
catch (err) {
|
|
@@ -655,6 +721,11 @@ export function closeDatabase() {
|
|
|
655
721
|
currentDb.exec('PRAGMA wal_checkpoint(TRUNCATE)');
|
|
656
722
|
}
|
|
657
723
|
catch { /* non-fatal — best effort before close */ }
|
|
724
|
+
try {
|
|
725
|
+
// Incremental vacuum to reclaim space without blocking
|
|
726
|
+
currentDb.exec('PRAGMA incremental_vacuum(64)');
|
|
727
|
+
}
|
|
728
|
+
catch { /* non-fatal */ }
|
|
658
729
|
try {
|
|
659
730
|
currentDb.close();
|
|
660
731
|
}
|
|
@@ -666,9 +737,31 @@ export function closeDatabase() {
|
|
|
666
737
|
currentPid = 0;
|
|
667
738
|
}
|
|
668
739
|
}
|
|
740
|
+
/** Run a full VACUUM — call sparingly (e.g. after milestone completion). */
|
|
741
|
+
export function vacuumDatabase() {
|
|
742
|
+
if (!currentDb)
|
|
743
|
+
return;
|
|
744
|
+
try {
|
|
745
|
+
currentDb.exec('VACUUM');
|
|
746
|
+
}
|
|
747
|
+
catch { /* non-fatal */ }
|
|
748
|
+
}
|
|
749
|
+
let _txDepth = 0;
|
|
669
750
|
export function transaction(fn) {
|
|
670
751
|
if (!currentDb)
|
|
671
752
|
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
753
|
+
// Re-entrant: if already inside a transaction, just run fn() without
|
|
754
|
+
// starting a new one. SQLite does not support nested BEGIN/COMMIT.
|
|
755
|
+
if (_txDepth > 0) {
|
|
756
|
+
_txDepth++;
|
|
757
|
+
try {
|
|
758
|
+
return fn();
|
|
759
|
+
}
|
|
760
|
+
finally {
|
|
761
|
+
_txDepth--;
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
_txDepth++;
|
|
672
765
|
currentDb.exec("BEGIN");
|
|
673
766
|
try {
|
|
674
767
|
const result = fn();
|
|
@@ -679,6 +772,9 @@ export function transaction(fn) {
|
|
|
679
772
|
currentDb.exec("ROLLBACK");
|
|
680
773
|
throw err;
|
|
681
774
|
}
|
|
775
|
+
finally {
|
|
776
|
+
_txDepth--;
|
|
777
|
+
}
|
|
682
778
|
}
|
|
683
779
|
export function insertDecision(d) {
|
|
684
780
|
if (!currentDb)
|
|
@@ -1112,6 +1208,16 @@ export function updateSliceStatus(milestoneId, sliceId, status, completedAt) {
|
|
|
1112
1208
|
":id": sliceId,
|
|
1113
1209
|
});
|
|
1114
1210
|
}
|
|
1211
|
+
export function setTaskSummaryMd(milestoneId, sliceId, taskId, md) {
|
|
1212
|
+
if (!currentDb)
|
|
1213
|
+
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1214
|
+
currentDb.prepare(`UPDATE tasks SET full_summary_md = :md WHERE milestone_id = :mid AND slice_id = :sid AND id = :tid`).run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId, ":md": md });
|
|
1215
|
+
}
|
|
1216
|
+
export function setSliceSummaryMd(milestoneId, sliceId, summaryMd, uatMd) {
|
|
1217
|
+
if (!currentDb)
|
|
1218
|
+
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1219
|
+
currentDb.prepare(`UPDATE slices SET full_summary_md = :summary_md, full_uat_md = :uat_md WHERE milestone_id = :mid AND id = :sid`).run({ ":mid": milestoneId, ":sid": sliceId, ":summary_md": summaryMd, ":uat_md": uatMd });
|
|
1220
|
+
}
|
|
1115
1221
|
function rowToTask(row) {
|
|
1116
1222
|
return {
|
|
1117
1223
|
milestone_id: row["milestone_id"],
|
|
@@ -1216,6 +1322,16 @@ export function getMilestone(id) {
|
|
|
1216
1322
|
return null;
|
|
1217
1323
|
return rowToMilestone(row);
|
|
1218
1324
|
}
|
|
1325
|
+
/**
|
|
1326
|
+
* Update a milestone's status in the database.
|
|
1327
|
+
* Used by park/unpark to keep the DB in sync with the filesystem marker.
|
|
1328
|
+
* See: https://github.com/gsd-build/gsd-2/issues/2694
|
|
1329
|
+
*/
|
|
1330
|
+
export function updateMilestoneStatus(milestoneId, status, completedAt) {
|
|
1331
|
+
if (!currentDb)
|
|
1332
|
+
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1333
|
+
currentDb.prepare(`UPDATE milestones SET status = :status, completed_at = :completed_at WHERE id = :id`).run({ ":status": status, ":completed_at": completedAt ?? null, ":id": milestoneId });
|
|
1334
|
+
}
|
|
1219
1335
|
export function getActiveMilestoneFromDb() {
|
|
1220
1336
|
if (!currentDb)
|
|
1221
1337
|
return null;
|
|
@@ -1227,18 +1343,22 @@ export function getActiveMilestoneFromDb() {
|
|
|
1227
1343
|
export function getActiveSliceFromDb(milestoneId) {
|
|
1228
1344
|
if (!currentDb)
|
|
1229
1345
|
return null;
|
|
1230
|
-
|
|
1231
|
-
|
|
1346
|
+
// Single query: find the first non-complete slice whose dependencies are all satisfied.
|
|
1347
|
+
// Uses json_each() to expand the JSON depends array and checks each dep is complete.
|
|
1348
|
+
const row = currentDb.prepare(`SELECT s.* FROM slices s
|
|
1349
|
+
WHERE s.milestone_id = :mid
|
|
1350
|
+
AND s.status NOT IN ('complete', 'done')
|
|
1351
|
+
AND NOT EXISTS (
|
|
1352
|
+
SELECT 1 FROM json_each(s.depends) AS dep
|
|
1353
|
+
WHERE dep.value NOT IN (
|
|
1354
|
+
SELECT id FROM slices WHERE milestone_id = :mid AND status IN ('complete', 'done')
|
|
1355
|
+
)
|
|
1356
|
+
)
|
|
1357
|
+
ORDER BY s.sequence, s.id
|
|
1358
|
+
LIMIT 1`).get({ ":mid": milestoneId });
|
|
1359
|
+
if (!row)
|
|
1232
1360
|
return null;
|
|
1233
|
-
|
|
1234
|
-
const completedIds = new Set(completedRows.map((r) => r["id"]));
|
|
1235
|
-
for (const row of rows) {
|
|
1236
|
-
const slice = rowToSlice(row);
|
|
1237
|
-
if (slice.depends.length === 0 || slice.depends.every((d) => completedIds.has(d))) {
|
|
1238
|
-
return slice;
|
|
1239
|
-
}
|
|
1240
|
-
}
|
|
1241
|
-
return null;
|
|
1361
|
+
return rowToSlice(row);
|
|
1242
1362
|
}
|
|
1243
1363
|
export function getActiveTaskFromDb(milestoneId, sliceId) {
|
|
1244
1364
|
if (!currentDb)
|
|
@@ -1262,6 +1382,60 @@ export function getArtifact(path) {
|
|
|
1262
1382
|
return null;
|
|
1263
1383
|
return rowToArtifact(row);
|
|
1264
1384
|
}
|
|
1385
|
+
// ─── Lightweight Query Variants (hot-path optimized) ─────────────────────
|
|
1386
|
+
/** Fast milestone status check — avoids deserializing JSON planning fields. */
|
|
1387
|
+
export function getActiveMilestoneIdFromDb() {
|
|
1388
|
+
if (!currentDb)
|
|
1389
|
+
return null;
|
|
1390
|
+
const row = currentDb.prepare("SELECT id, status FROM milestones WHERE status NOT IN ('complete', 'parked') ORDER BY id LIMIT 1").get();
|
|
1391
|
+
if (!row)
|
|
1392
|
+
return null;
|
|
1393
|
+
return { id: row["id"], status: row["status"] };
|
|
1394
|
+
}
|
|
1395
|
+
/** Fast slice status check — avoids deserializing JSON depends/planning fields. */
|
|
1396
|
+
export function getSliceStatusSummary(milestoneId) {
|
|
1397
|
+
if (!currentDb)
|
|
1398
|
+
return [];
|
|
1399
|
+
return currentDb.prepare("SELECT id, status FROM slices WHERE milestone_id = :mid ORDER BY sequence, id").all({ ":mid": milestoneId }).map((r) => ({ id: r["id"], status: r["status"] }));
|
|
1400
|
+
}
|
|
1401
|
+
/** Fast task status check — avoids deserializing JSON arrays and large text fields. */
|
|
1402
|
+
export function getActiveTaskIdFromDb(milestoneId, sliceId) {
|
|
1403
|
+
if (!currentDb)
|
|
1404
|
+
return null;
|
|
1405
|
+
const row = currentDb.prepare("SELECT id, status, title FROM tasks WHERE milestone_id = :mid AND slice_id = :sid AND status NOT IN ('complete', 'done') ORDER BY sequence, id LIMIT 1").get({ ":mid": milestoneId, ":sid": sliceId });
|
|
1406
|
+
if (!row)
|
|
1407
|
+
return null;
|
|
1408
|
+
return { id: row["id"], status: row["status"], title: row["title"] };
|
|
1409
|
+
}
|
|
1410
|
+
/** Count tasks by status for a slice — useful for progress reporting without full row load. */
|
|
1411
|
+
export function getSliceTaskCounts(milestoneId, sliceId) {
|
|
1412
|
+
if (!currentDb)
|
|
1413
|
+
return { total: 0, done: 0, pending: 0 };
|
|
1414
|
+
const row = currentDb.prepare(`SELECT
|
|
1415
|
+
COUNT(*) as total,
|
|
1416
|
+
SUM(CASE WHEN status IN ('complete', 'done') THEN 1 ELSE 0 END) as done,
|
|
1417
|
+
SUM(CASE WHEN status NOT IN ('complete', 'done') THEN 1 ELSE 0 END) as pending
|
|
1418
|
+
FROM tasks WHERE milestone_id = :mid AND slice_id = :sid`).get({ ":mid": milestoneId, ":sid": sliceId });
|
|
1419
|
+
if (!row)
|
|
1420
|
+
return { total: 0, done: 0, pending: 0 };
|
|
1421
|
+
return { total: row["total"] ?? 0, done: row["done"] ?? 0, pending: row["pending"] ?? 0 };
|
|
1422
|
+
}
|
|
1423
|
+
// ─── Slice Dependencies (junction table) ─────────────────────────────────
|
|
1424
|
+
/** Sync the slice_dependencies junction table from a slice's JSON depends array. */
|
|
1425
|
+
export function syncSliceDependencies(milestoneId, sliceId, depends) {
|
|
1426
|
+
if (!currentDb)
|
|
1427
|
+
return;
|
|
1428
|
+
currentDb.prepare("DELETE FROM slice_dependencies WHERE milestone_id = :mid AND slice_id = :sid").run({ ":mid": milestoneId, ":sid": sliceId });
|
|
1429
|
+
for (const dep of depends) {
|
|
1430
|
+
currentDb.prepare("INSERT OR IGNORE INTO slice_dependencies (milestone_id, slice_id, depends_on_slice_id) VALUES (:mid, :sid, :dep)").run({ ":mid": milestoneId, ":sid": sliceId, ":dep": dep });
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
/** Get all slices that depend on a given slice. */
|
|
1434
|
+
export function getDependentSlices(milestoneId, sliceId) {
|
|
1435
|
+
if (!currentDb)
|
|
1436
|
+
return [];
|
|
1437
|
+
return currentDb.prepare("SELECT slice_id FROM slice_dependencies WHERE milestone_id = :mid AND depends_on_slice_id = :sid").all({ ":mid": milestoneId, ":sid": sliceId }).map((r) => r["slice_id"]);
|
|
1438
|
+
}
|
|
1265
1439
|
// ─── Worktree DB Helpers ──────────────────────────────────────────────────
|
|
1266
1440
|
export function copyWorktreeDb(srcDbPath, destDbPath) {
|
|
1267
1441
|
try {
|
|
@@ -1278,10 +1452,13 @@ export function copyWorktreeDb(srcDbPath, destDbPath) {
|
|
|
1278
1452
|
}
|
|
1279
1453
|
}
|
|
1280
1454
|
export function reconcileWorktreeDb(mainDbPath, worktreeDbPath) {
|
|
1281
|
-
const zero = { decisions: 0, requirements: 0, artifacts: 0, conflicts: [] };
|
|
1455
|
+
const zero = { decisions: 0, requirements: 0, artifacts: 0, milestones: 0, slices: 0, tasks: 0, memories: 0, verification_evidence: 0, conflicts: [] };
|
|
1282
1456
|
if (!existsSync(worktreeDbPath))
|
|
1283
1457
|
return zero;
|
|
1284
|
-
|
|
1458
|
+
// Sanitize path: reject any characters that could break ATTACH syntax.
|
|
1459
|
+
// ATTACH DATABASE doesn't support parameterized paths in all providers,
|
|
1460
|
+
// so we use strict allowlist validation instead.
|
|
1461
|
+
if (/['";\x00]/.test(worktreeDbPath)) {
|
|
1285
1462
|
process.stderr.write("gsd-db: worktree DB reconciliation failed: path contains unsafe characters\n");
|
|
1286
1463
|
return zero;
|
|
1287
1464
|
}
|
|
@@ -1305,17 +1482,19 @@ export function reconcileWorktreeDb(mainDbPath, worktreeDbPath) {
|
|
|
1305
1482
|
const reqConf = adapter.prepare(`SELECT m.id FROM requirements m INNER JOIN wt.requirements w ON m.id = w.id WHERE m.description != w.description OR m.status != w.status OR m.notes != w.notes OR m.superseded_by IS NOT w.superseded_by`).all();
|
|
1306
1483
|
for (const row of reqConf)
|
|
1307
1484
|
conflicts.push(`requirement ${row["id"]}: modified in both`);
|
|
1308
|
-
const merged = { decisions: 0, requirements: 0, artifacts: 0 };
|
|
1485
|
+
const merged = { decisions: 0, requirements: 0, artifacts: 0, milestones: 0, slices: 0, tasks: 0, memories: 0, verification_evidence: 0 };
|
|
1486
|
+
function countChanges(result) {
|
|
1487
|
+
return typeof result === "object" && result !== null ? (result.changes ?? 0) : 0;
|
|
1488
|
+
}
|
|
1309
1489
|
adapter.exec("BEGIN");
|
|
1310
1490
|
try {
|
|
1311
|
-
|
|
1491
|
+
merged.decisions = countChanges(adapter.prepare(`
|
|
1312
1492
|
INSERT OR REPLACE INTO decisions (
|
|
1313
1493
|
id, when_context, scope, decision, choice, rationale, revisable, made_by, superseded_by
|
|
1314
1494
|
)
|
|
1315
1495
|
SELECT id, when_context, scope, decision, choice, rationale, revisable, ${hasMadeBy ? "made_by" : "'agent'"}, superseded_by FROM wt.decisions
|
|
1316
|
-
`).run();
|
|
1317
|
-
merged.
|
|
1318
|
-
const rR = adapter.prepare(`
|
|
1496
|
+
`).run());
|
|
1497
|
+
merged.requirements = countChanges(adapter.prepare(`
|
|
1319
1498
|
INSERT OR REPLACE INTO requirements (
|
|
1320
1499
|
id, class, status, description, why, source, primary_owner,
|
|
1321
1500
|
supporting_slices, validation, notes, full_content, superseded_by
|
|
@@ -1323,16 +1502,74 @@ export function reconcileWorktreeDb(mainDbPath, worktreeDbPath) {
|
|
|
1323
1502
|
SELECT id, class, status, description, why, source, primary_owner,
|
|
1324
1503
|
supporting_slices, validation, notes, full_content, superseded_by
|
|
1325
1504
|
FROM wt.requirements
|
|
1326
|
-
`).run();
|
|
1327
|
-
merged.
|
|
1328
|
-
const aR = adapter.prepare(`
|
|
1505
|
+
`).run());
|
|
1506
|
+
merged.artifacts = countChanges(adapter.prepare(`
|
|
1329
1507
|
INSERT OR REPLACE INTO artifacts (
|
|
1330
1508
|
path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at
|
|
1331
1509
|
)
|
|
1332
1510
|
SELECT path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at
|
|
1333
1511
|
FROM wt.artifacts
|
|
1334
|
-
`).run();
|
|
1335
|
-
|
|
1512
|
+
`).run());
|
|
1513
|
+
// Merge milestones — worktree may have updated status/planning fields
|
|
1514
|
+
merged.milestones = countChanges(adapter.prepare(`
|
|
1515
|
+
INSERT OR REPLACE INTO milestones (
|
|
1516
|
+
id, title, status, depends_on, created_at, completed_at,
|
|
1517
|
+
vision, success_criteria, key_risks, proof_strategy,
|
|
1518
|
+
verification_contract, verification_integration, verification_operational, verification_uat,
|
|
1519
|
+
definition_of_done, requirement_coverage, boundary_map_markdown
|
|
1520
|
+
)
|
|
1521
|
+
SELECT id, title, status, depends_on, created_at, completed_at,
|
|
1522
|
+
vision, success_criteria, key_risks, proof_strategy,
|
|
1523
|
+
verification_contract, verification_integration, verification_operational, verification_uat,
|
|
1524
|
+
definition_of_done, requirement_coverage, boundary_map_markdown
|
|
1525
|
+
FROM wt.milestones
|
|
1526
|
+
`).run());
|
|
1527
|
+
// Merge slices — preserve worktree progress (status, summaries, planning)
|
|
1528
|
+
merged.slices = countChanges(adapter.prepare(`
|
|
1529
|
+
INSERT OR REPLACE INTO slices (
|
|
1530
|
+
milestone_id, id, title, status, risk, depends, demo, created_at, completed_at,
|
|
1531
|
+
full_summary_md, full_uat_md, goal, success_criteria, proof_level,
|
|
1532
|
+
integration_closure, observability_impact, sequence, replan_triggered_at
|
|
1533
|
+
)
|
|
1534
|
+
SELECT milestone_id, id, title, status, risk, depends, demo, created_at, completed_at,
|
|
1535
|
+
full_summary_md, full_uat_md, goal, success_criteria, proof_level,
|
|
1536
|
+
integration_closure, observability_impact, sequence, replan_triggered_at
|
|
1537
|
+
FROM wt.slices
|
|
1538
|
+
`).run());
|
|
1539
|
+
// Merge tasks — preserve execution results, status, summaries
|
|
1540
|
+
merged.tasks = countChanges(adapter.prepare(`
|
|
1541
|
+
INSERT OR REPLACE INTO tasks (
|
|
1542
|
+
milestone_id, slice_id, id, title, status, one_liner, narrative,
|
|
1543
|
+
verification_result, duration, completed_at, blocker_discovered,
|
|
1544
|
+
deviations, known_issues, key_files, key_decisions, full_summary_md,
|
|
1545
|
+
description, estimate, files, verify, inputs, expected_output,
|
|
1546
|
+
observability_impact, full_plan_md, sequence
|
|
1547
|
+
)
|
|
1548
|
+
SELECT milestone_id, slice_id, id, title, status, one_liner, narrative,
|
|
1549
|
+
verification_result, duration, completed_at, blocker_discovered,
|
|
1550
|
+
deviations, known_issues, key_files, key_decisions, full_summary_md,
|
|
1551
|
+
description, estimate, files, verify, inputs, expected_output,
|
|
1552
|
+
observability_impact, full_plan_md, sequence
|
|
1553
|
+
FROM wt.tasks
|
|
1554
|
+
`).run());
|
|
1555
|
+
// Merge memories — keep worktree-learned insights
|
|
1556
|
+
merged.memories = countChanges(adapter.prepare(`
|
|
1557
|
+
INSERT OR REPLACE INTO memories (
|
|
1558
|
+
seq, id, category, content, confidence, source_unit_type, source_unit_id,
|
|
1559
|
+
created_at, updated_at, superseded_by, hit_count
|
|
1560
|
+
)
|
|
1561
|
+
SELECT seq, id, category, content, confidence, source_unit_type, source_unit_id,
|
|
1562
|
+
created_at, updated_at, superseded_by, hit_count
|
|
1563
|
+
FROM wt.memories
|
|
1564
|
+
`).run());
|
|
1565
|
+
// Merge verification evidence — append-only, use INSERT OR IGNORE to avoid duplicates
|
|
1566
|
+
merged.verification_evidence = countChanges(adapter.prepare(`
|
|
1567
|
+
INSERT OR IGNORE INTO verification_evidence (
|
|
1568
|
+
task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at
|
|
1569
|
+
)
|
|
1570
|
+
SELECT task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at
|
|
1571
|
+
FROM wt.verification_evidence
|
|
1572
|
+
`).run());
|
|
1336
1573
|
adapter.exec("COMMIT");
|
|
1337
1574
|
}
|
|
1338
1575
|
catch (txErr) {
|
|
@@ -1388,20 +1625,36 @@ export function insertAssessment(entry) {
|
|
|
1388
1625
|
":created_at": new Date().toISOString(),
|
|
1389
1626
|
});
|
|
1390
1627
|
}
|
|
1391
|
-
export function
|
|
1628
|
+
export function deleteAssessmentByScope(milestoneId, scope) {
|
|
1629
|
+
if (!currentDb)
|
|
1630
|
+
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1631
|
+
currentDb.prepare(`DELETE FROM assessments WHERE milestone_id = :mid AND scope = :scope`).run({ ":mid": milestoneId, ":scope": scope });
|
|
1632
|
+
}
|
|
1633
|
+
export function deleteVerificationEvidence(milestoneId, sliceId, taskId) {
|
|
1392
1634
|
if (!currentDb)
|
|
1393
1635
|
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1394
|
-
// Must delete verification_evidence first (FK constraint)
|
|
1395
1636
|
currentDb.prepare(`DELETE FROM verification_evidence WHERE milestone_id = :mid AND slice_id = :sid AND task_id = :tid`).run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
|
|
1396
|
-
|
|
1637
|
+
}
|
|
1638
|
+
export function deleteTask(milestoneId, sliceId, taskId) {
|
|
1639
|
+
if (!currentDb)
|
|
1640
|
+
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1641
|
+
transaction(() => {
|
|
1642
|
+
// Must delete verification_evidence first (FK constraint)
|
|
1643
|
+
currentDb.prepare(`DELETE FROM verification_evidence WHERE milestone_id = :mid AND slice_id = :sid AND task_id = :tid`).run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
|
|
1644
|
+
currentDb.prepare(`DELETE FROM tasks WHERE milestone_id = :mid AND slice_id = :sid AND id = :tid`).run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
|
|
1645
|
+
});
|
|
1397
1646
|
}
|
|
1398
1647
|
export function deleteSlice(milestoneId, sliceId) {
|
|
1399
1648
|
if (!currentDb)
|
|
1400
1649
|
throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1650
|
+
transaction(() => {
|
|
1651
|
+
// Cascade-style manual deletion: evidence → tasks → dependencies → slice
|
|
1652
|
+
currentDb.prepare(`DELETE FROM verification_evidence WHERE milestone_id = :mid AND slice_id = :sid`).run({ ":mid": milestoneId, ":sid": sliceId });
|
|
1653
|
+
currentDb.prepare(`DELETE FROM tasks WHERE milestone_id = :mid AND slice_id = :sid`).run({ ":mid": milestoneId, ":sid": sliceId });
|
|
1654
|
+
currentDb.prepare(`DELETE FROM slice_dependencies WHERE milestone_id = :mid AND slice_id = :sid`).run({ ":mid": milestoneId, ":sid": sliceId });
|
|
1655
|
+
currentDb.prepare(`DELETE FROM slice_dependencies WHERE milestone_id = :mid AND depends_on_slice_id = :sid`).run({ ":mid": milestoneId, ":sid": sliceId });
|
|
1656
|
+
currentDb.prepare(`DELETE FROM slices WHERE milestone_id = :mid AND id = :sid`).run({ ":mid": milestoneId, ":sid": sliceId });
|
|
1657
|
+
});
|
|
1405
1658
|
}
|
|
1406
1659
|
export function updateSliceFields(milestoneId, sliceId, fields) {
|
|
1407
1660
|
if (!currentDb)
|