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.
Files changed (419) hide show
  1. package/README.md +59 -36
  2. package/dist/headless-events.d.ts +18 -0
  3. package/dist/headless-events.js +36 -0
  4. package/dist/headless-query.js +1 -1
  5. package/dist/headless-types.d.ts +28 -0
  6. package/dist/headless-types.js +7 -0
  7. package/dist/headless.d.ts +8 -3
  8. package/dist/headless.js +47 -16
  9. package/dist/help-text.js +16 -5
  10. package/dist/onboarding.js +5 -4
  11. package/dist/remote-questions-config.js +1 -1
  12. package/dist/resources/extensions/async-jobs/async-bash-tool.js +29 -17
  13. package/dist/resources/extensions/async-jobs/job-manager.js +4 -1
  14. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +18 -19
  15. package/dist/resources/extensions/get-secrets-from-user.js +7 -0
  16. package/dist/resources/extensions/gsd/auto/phases.js +34 -8
  17. package/dist/resources/extensions/gsd/auto-dispatch.js +23 -1
  18. package/dist/resources/extensions/gsd/auto-start.js +2 -0
  19. package/dist/resources/extensions/gsd/auto-timers.js +24 -2
  20. package/dist/resources/extensions/gsd/auto-tool-tracking.js +25 -7
  21. package/dist/resources/extensions/gsd/auto-worktree.js +91 -14
  22. package/dist/resources/extensions/gsd/auto.js +30 -4
  23. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +99 -70
  24. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +12 -2
  25. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +1 -1
  26. package/dist/resources/extensions/gsd/claude-import.js +60 -9
  27. package/dist/resources/extensions/gsd/commands/handlers/auto.js +69 -6
  28. package/dist/resources/extensions/gsd/commands-config.js +10 -5
  29. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +4 -4
  30. package/dist/resources/extensions/gsd/detection.js +6 -6
  31. package/dist/resources/extensions/gsd/docs/preferences-reference.md +5 -5
  32. package/dist/resources/extensions/gsd/error-classifier.js +105 -0
  33. package/dist/resources/extensions/gsd/git-service.js +4 -3
  34. package/dist/resources/extensions/gsd/gitignore.js +7 -7
  35. package/dist/resources/extensions/gsd/gsd-db.js +298 -45
  36. package/dist/resources/extensions/gsd/guided-flow.js +4 -3
  37. package/dist/resources/extensions/gsd/init-wizard.js +2 -2
  38. package/dist/resources/extensions/gsd/key-manager.js +7 -16
  39. package/dist/resources/extensions/gsd/markdown-renderer.js +5 -4
  40. package/dist/resources/extensions/gsd/memory-store.js +28 -13
  41. package/dist/resources/extensions/gsd/milestone-actions.js +19 -0
  42. package/dist/resources/extensions/gsd/parallel-orchestrator.js +18 -2
  43. package/dist/resources/extensions/gsd/preferences-models.js +1 -13
  44. package/dist/resources/extensions/gsd/preferences-types.js +1 -1
  45. package/dist/resources/extensions/gsd/preferences.js +13 -13
  46. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  47. package/dist/resources/extensions/gsd/provider-error-pause.js +0 -44
  48. package/dist/resources/extensions/gsd/rule-registry.js +1 -1
  49. package/dist/resources/extensions/gsd/service-tier.js +13 -2
  50. package/dist/resources/extensions/gsd/state.js +38 -30
  51. package/dist/resources/extensions/gsd/status-guards.js +12 -0
  52. package/dist/resources/extensions/gsd/tools/complete-milestone.js +7 -13
  53. package/dist/resources/extensions/gsd/tools/complete-slice.js +7 -20
  54. package/dist/resources/extensions/gsd/tools/complete-task.js +11 -21
  55. package/dist/resources/extensions/gsd/tools/plan-milestone.js +28 -29
  56. package/dist/resources/extensions/gsd/tools/plan-slice.js +27 -26
  57. package/dist/resources/extensions/gsd/tools/plan-task.js +23 -23
  58. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +50 -41
  59. package/dist/resources/extensions/gsd/tools/reopen-slice.js +4 -3
  60. package/dist/resources/extensions/gsd/tools/reopen-task.js +5 -4
  61. package/dist/resources/extensions/gsd/tools/replan-slice.js +51 -41
  62. package/dist/resources/extensions/gsd/tools/validate-milestone.js +23 -16
  63. package/dist/resources/extensions/gsd/validation.js +21 -0
  64. package/dist/resources/extensions/gsd/workflow-logger.js +0 -1
  65. package/dist/resources/extensions/remote-questions/config.js +1 -1
  66. package/dist/resources/extensions/remote-questions/remote-command.js +1 -1
  67. package/dist/resources/extensions/search-the-web/native-search.js +1 -1
  68. package/dist/resources/extensions/search-the-web/provider.js +1 -1
  69. package/dist/resources/extensions/shared/rtk.js +14 -4
  70. package/dist/rtk.js +3 -1
  71. package/dist/web/standalone/.next/BUILD_ID +1 -1
  72. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  73. package/dist/web/standalone/.next/build-manifest.json +4 -4
  74. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  75. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  76. package/dist/web/standalone/.next/required-server-files.json +3 -3
  77. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  78. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  80. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  83. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  88. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  92. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  94. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  97. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  104. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  116. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  144. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  150. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  164. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  166. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  168. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  170. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/index.html +1 -1
  180. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  181. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  182. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  183. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  184. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  185. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  186. package/dist/web/standalone/.next/server/app/page.js +2 -2
  187. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  189. package/dist/web/standalone/.next/server/chunks/2229.js +3 -3
  190. package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
  191. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/middleware.js +2 -2
  194. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  196. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  197. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  198. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  199. package/dist/web/standalone/.next/static/chunks/4024.87fd909ae0110f50.js +9 -0
  200. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  201. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  202. package/dist/web/standalone/.next/static/chunks/app/page-b950e4e384cc62b3.js +1 -0
  203. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  204. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  205. package/dist/web/standalone/.next/static/chunks/{webpack-cfc9a116e6450a6b.js → webpack-bca0e732db0dcec3.js} +1 -1
  206. package/dist/web/standalone/.next/static/css/a58ef8a151aa0493.css +1 -0
  207. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  208. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  209. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  210. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  211. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  212. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  213. package/dist/web/standalone/server.js +1 -1
  214. package/dist/wizard.js +4 -1
  215. package/package.json +2 -2
  216. package/packages/mcp-server/README.md +202 -0
  217. package/packages/mcp-server/package.json +36 -0
  218. package/packages/mcp-server/src/cli.ts +68 -0
  219. package/packages/mcp-server/src/index.ts +14 -0
  220. package/packages/mcp-server/src/mcp-server.test.ts +628 -0
  221. package/packages/mcp-server/src/server.ts +278 -0
  222. package/packages/mcp-server/src/session-manager.ts +328 -0
  223. package/packages/mcp-server/src/types.ts +107 -0
  224. package/packages/mcp-server/tsconfig.json +24 -0
  225. package/packages/pi-ai/dist/models.d.ts +14 -3
  226. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  227. package/packages/pi-ai/dist/models.js +53 -10
  228. package/packages/pi-ai/dist/models.js.map +1 -1
  229. package/packages/pi-ai/dist/models.test.js +102 -1
  230. package/packages/pi-ai/dist/models.test.js.map +1 -1
  231. package/packages/pi-ai/dist/types.d.ts +30 -0
  232. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  233. package/packages/pi-ai/dist/types.js.map +1 -1
  234. package/packages/pi-ai/src/models.test.ts +114 -1
  235. package/packages/pi-ai/src/models.ts +70 -13
  236. package/packages/pi-ai/src/types.ts +31 -0
  237. package/packages/pi-coding-agent/dist/cli/args.d.ts +2 -0
  238. package/packages/pi-coding-agent/dist/cli/args.d.ts.map +1 -1
  239. package/packages/pi-coding-agent/dist/cli/args.js +3 -0
  240. package/packages/pi-coding-agent/dist/cli/args.js.map +1 -1
  241. package/packages/pi-coding-agent/dist/core/bash-executor.d.ts.map +1 -1
  242. package/packages/pi-coding-agent/dist/core/bash-executor.js +5 -1
  243. package/packages/pi-coding-agent/dist/core/bash-executor.js.map +1 -1
  244. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  245. package/packages/pi-coding-agent/dist/core/model-registry.js +9 -4
  246. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  247. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.d.ts +19 -0
  248. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.d.ts.map +1 -0
  249. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +83 -0
  250. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -0
  251. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  252. package/packages/pi-coding-agent/dist/core/tools/bash.js +5 -1
  253. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  255. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  256. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  257. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  258. package/packages/pi-coding-agent/dist/main.js +5 -3
  259. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  260. package/packages/pi-coding-agent/dist/modes/index.d.ts +1 -1
  261. package/packages/pi-coding-agent/dist/modes/index.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/modes/index.js.map +1 -1
  263. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  264. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +0 -2
  265. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  266. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts +28 -1
  267. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  268. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +49 -0
  269. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
  270. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts +1 -1
  271. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  272. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +114 -6
  273. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  274. package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.d.ts +9 -0
  275. package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.d.ts.map +1 -0
  276. package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.js +831 -0
  277. package/packages/pi-coding-agent/dist/modes/rpc/rpc-protocol-v2.test.js.map +1 -0
  278. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +66 -0
  279. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  280. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
  281. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  282. package/packages/pi-coding-agent/dist/utils/shell.js +0 -1
  283. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  284. package/packages/pi-coding-agent/package.json +1 -1
  285. package/packages/pi-coding-agent/src/cli/args.ts +4 -0
  286. package/packages/pi-coding-agent/src/core/bash-executor.ts +5 -1
  287. package/packages/pi-coding-agent/src/core/model-registry.ts +10 -3
  288. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +101 -0
  289. package/packages/pi-coding-agent/src/core/tools/bash.ts +5 -1
  290. package/packages/pi-coding-agent/src/index.ts +3 -0
  291. package/packages/pi-coding-agent/src/main.ts +5 -3
  292. package/packages/pi-coding-agent/src/modes/index.ts +8 -1
  293. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +0 -2
  294. package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +54 -1
  295. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +124 -6
  296. package/packages/pi-coding-agent/src/modes/rpc/rpc-protocol-v2.test.ts +971 -0
  297. package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +61 -4
  298. package/packages/pi-coding-agent/src/utils/shell.ts +0 -1
  299. package/packages/rpc-client/package.json +20 -0
  300. package/pkg/package.json +1 -1
  301. package/scripts/ensure-workspace-builds.cjs +36 -8
  302. package/src/resources/extensions/async-jobs/async-bash-tool.ts +22 -11
  303. package/src/resources/extensions/async-jobs/job-manager.ts +4 -1
  304. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +19 -20
  305. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +21 -0
  306. package/src/resources/extensions/get-secrets-from-user.ts +8 -0
  307. package/src/resources/extensions/gsd/auto/phases.ts +44 -7
  308. package/src/resources/extensions/gsd/auto-dispatch.ts +25 -1
  309. package/src/resources/extensions/gsd/auto-start.ts +2 -0
  310. package/src/resources/extensions/gsd/auto-timers.ts +25 -1
  311. package/src/resources/extensions/gsd/auto-tool-tracking.ts +30 -6
  312. package/src/resources/extensions/gsd/auto-worktree.ts +94 -14
  313. package/src/resources/extensions/gsd/auto.ts +31 -4
  314. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +118 -73
  315. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +11 -2
  316. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +1 -1
  317. package/src/resources/extensions/gsd/claude-import.ts +58 -9
  318. package/src/resources/extensions/gsd/commands/handlers/auto.ts +73 -6
  319. package/src/resources/extensions/gsd/commands-config.ts +11 -5
  320. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +4 -4
  321. package/src/resources/extensions/gsd/detection.ts +6 -6
  322. package/src/resources/extensions/gsd/docs/preferences-reference.md +5 -5
  323. package/src/resources/extensions/gsd/error-classifier.ts +139 -0
  324. package/src/resources/extensions/gsd/git-service.ts +4 -3
  325. package/src/resources/extensions/gsd/gitignore.ts +7 -7
  326. package/src/resources/extensions/gsd/gsd-db.ts +355 -63
  327. package/src/resources/extensions/gsd/guided-flow.ts +4 -3
  328. package/src/resources/extensions/gsd/init-wizard.ts +2 -2
  329. package/src/resources/extensions/gsd/key-manager.ts +7 -16
  330. package/src/resources/extensions/gsd/markdown-renderer.ts +5 -4
  331. package/src/resources/extensions/gsd/memory-store.ts +29 -18
  332. package/src/resources/extensions/gsd/milestone-actions.ts +17 -0
  333. package/src/resources/extensions/gsd/parallel-orchestrator.ts +23 -1
  334. package/src/resources/extensions/gsd/preferences-models.ts +1 -13
  335. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  336. package/src/resources/extensions/gsd/preferences.ts +12 -13
  337. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  338. package/src/resources/extensions/gsd/provider-error-pause.ts +0 -57
  339. package/src/resources/extensions/gsd/rule-registry.ts +1 -1
  340. package/src/resources/extensions/gsd/service-tier.ts +14 -2
  341. package/src/resources/extensions/gsd/state.ts +39 -30
  342. package/src/resources/extensions/gsd/status-guards.ts +13 -0
  343. package/src/resources/extensions/gsd/tests/active-milestone-id-guard.test.ts +91 -0
  344. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +1 -1
  345. package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +61 -0
  346. package/src/resources/extensions/gsd/tests/auto-stale-lock-self-kill.test.ts +87 -0
  347. package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +80 -0
  348. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +1 -1
  349. package/src/resources/extensions/gsd/tests/claude-import-marketplace-discovery.test.ts +191 -0
  350. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +1 -1
  351. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +39 -0
  352. package/src/resources/extensions/gsd/tests/commands-config.test.ts +24 -0
  353. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +2 -2
  354. package/src/resources/extensions/gsd/tests/complete-task-rollback-evidence.test.ts +106 -0
  355. package/src/resources/extensions/gsd/tests/complete-task.test.ts +2 -2
  356. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +35 -7
  357. package/src/resources/extensions/gsd/tests/detection.test.ts +1 -1
  358. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +4 -4
  359. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +1 -1
  360. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +2 -2
  361. package/src/resources/extensions/gsd/tests/empty-db-reconciliation.test.ts +79 -0
  362. package/src/resources/extensions/gsd/tests/git-service.test.ts +65 -31
  363. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  364. package/src/resources/extensions/gsd/tests/idle-watchdog-stall-override.test.ts +125 -0
  365. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +1 -1
  366. package/src/resources/extensions/gsd/tests/interactive-tool-idle-exemption.test.ts +119 -0
  367. package/src/resources/extensions/gsd/tests/key-manager.test.ts +16 -1
  368. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  369. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  370. package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +51 -0
  371. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +7 -7
  372. package/src/resources/extensions/gsd/tests/parallel-orchestrator-zombie-cleanup.test.ts +277 -0
  373. package/src/resources/extensions/gsd/tests/park-db-sync.test.ts +85 -0
  374. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +103 -0
  375. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +91 -0
  376. package/src/resources/extensions/gsd/tests/preferences.test.ts +2 -2
  377. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +77 -70
  378. package/src/resources/extensions/gsd/tests/rate-limit-model-fallback.test.ts +90 -0
  379. package/src/resources/extensions/gsd/tests/remediation-completion-guard.test.ts +110 -0
  380. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +29 -0
  381. package/src/resources/extensions/gsd/tests/session-lock-transient-read.test.ts +9 -8
  382. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +125 -0
  383. package/src/resources/extensions/gsd/tests/status-guards.test.ts +30 -0
  384. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +42 -31
  385. package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +2 -2
  386. package/src/resources/extensions/gsd/tests/vacuous-truth-slices.test.ts +115 -0
  387. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +90 -0
  388. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +12 -2
  389. package/src/resources/extensions/gsd/tests/validation-gate-patterns.test.ts +124 -0
  390. package/src/resources/extensions/gsd/tests/validation.test.ts +72 -0
  391. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +81 -1
  392. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +130 -0
  393. package/src/resources/extensions/gsd/tools/complete-milestone.ts +7 -17
  394. package/src/resources/extensions/gsd/tools/complete-slice.ts +7 -24
  395. package/src/resources/extensions/gsd/tools/complete-task.ts +13 -25
  396. package/src/resources/extensions/gsd/tools/plan-milestone.ts +30 -32
  397. package/src/resources/extensions/gsd/tools/plan-slice.ts +30 -30
  398. package/src/resources/extensions/gsd/tools/plan-task.ts +26 -26
  399. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +57 -46
  400. package/src/resources/extensions/gsd/tools/reopen-slice.ts +4 -3
  401. package/src/resources/extensions/gsd/tools/reopen-task.ts +5 -4
  402. package/src/resources/extensions/gsd/tools/replan-slice.ts +55 -44
  403. package/src/resources/extensions/gsd/tools/validate-milestone.ts +26 -20
  404. package/src/resources/extensions/gsd/validation.ts +23 -0
  405. package/src/resources/extensions/gsd/workflow-logger.ts +0 -1
  406. package/src/resources/extensions/remote-questions/config.ts +1 -1
  407. package/src/resources/extensions/remote-questions/remote-command.ts +1 -1
  408. package/src/resources/extensions/search-the-web/native-search.ts +1 -1
  409. package/src/resources/extensions/search-the-web/provider.ts +1 -1
  410. package/src/resources/extensions/shared/rtk.ts +22 -4
  411. package/dist/web/standalone/.next/static/chunks/4024.9ad5def014d90ce4.js +0 -9
  412. package/dist/web/standalone/.next/static/chunks/app/page-fbecd1237e2d6d1f.js +0 -1
  413. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  414. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  415. package/dist/web/standalone/.next/static/css/de141508b083f922.css +0 -1
  416. /package/dist/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -0
  417. /package/dist/web/standalone/.next/static/{vkr67v-utm1dgZnbrBWQh → zpvUPKoW5jRAMB_fWHlPi}/_buildManifest.js +0 -0
  418. /package/dist/web/standalone/.next/static/{vkr67v-utm1dgZnbrBWQh → zpvUPKoW5jRAMB_fWHlPi}/_ssgManifest.js +0 -0
  419. /package/src/resources/extensions/gsd/templates/{preferences.md → PREFERENCES.md} +0 -0
@@ -110,25 +110,35 @@ function createAdapter(rawDb: unknown): DbAdapter {
110
110
  close(): void;
111
111
  };
112
112
 
113
+ const stmtCache = new Map<string, DbStatement>();
114
+
115
+ function wrapStmt(raw: { run(...a: unknown[]): unknown; get(...a: unknown[]): unknown; all(...a: unknown[]): unknown[] }): DbStatement {
116
+ return {
117
+ run(...params: unknown[]): unknown {
118
+ return raw.run(...params);
119
+ },
120
+ get(...params: unknown[]): Record<string, unknown> | undefined {
121
+ return normalizeRow(raw.get(...params));
122
+ },
123
+ all(...params: unknown[]): Record<string, unknown>[] {
124
+ return normalizeRows(raw.all(...params));
125
+ },
126
+ };
127
+ }
128
+
113
129
  return {
114
130
  exec(sql: string): void {
115
131
  db.exec(sql);
116
132
  },
117
133
  prepare(sql: string): DbStatement {
118
- const stmt = db.prepare(sql);
119
- return {
120
- run(...params: unknown[]): unknown {
121
- return stmt.run(...params);
122
- },
123
- get(...params: unknown[]): Record<string, unknown> | undefined {
124
- return normalizeRow(stmt.get(...params));
125
- },
126
- all(...params: unknown[]): Record<string, unknown>[] {
127
- return normalizeRows(stmt.all(...params));
128
- },
129
- };
134
+ let cached = stmtCache.get(sql);
135
+ if (cached) return cached;
136
+ cached = wrapStmt(db.prepare(sql));
137
+ stmtCache.set(sql, cached);
138
+ return cached;
130
139
  },
131
140
  close(): void {
141
+ stmtCache.clear();
132
142
  db.close();
133
143
  },
134
144
  };
@@ -149,11 +159,16 @@ function openRawDb(path: string): unknown {
149
159
  return new Database(path);
150
160
  }
151
161
 
152
- const SCHEMA_VERSION = 12;
162
+ const SCHEMA_VERSION = 14;
153
163
 
154
164
  function initSchema(db: DbAdapter, fileBacked: boolean): void {
155
165
  if (fileBacked) db.exec("PRAGMA journal_mode=WAL");
156
166
  if (fileBacked) db.exec("PRAGMA busy_timeout = 5000");
167
+ if (fileBacked) db.exec("PRAGMA synchronous = NORMAL");
168
+ if (fileBacked) db.exec("PRAGMA auto_vacuum = INCREMENTAL");
169
+ if (fileBacked) db.exec("PRAGMA cache_size = -8000"); // 8 MB page cache
170
+ if (fileBacked) db.exec("PRAGMA mmap_size = 67108864"); // 64 MB mmap
171
+ db.exec("PRAGMA temp_store = MEMORY");
157
172
  db.exec("PRAGMA foreign_keys = ON");
158
173
 
159
174
  db.exec("BEGIN");
@@ -273,7 +288,7 @@ function initSchema(db: DbAdapter, fileBacked: boolean): void {
273
288
  proof_level TEXT NOT NULL DEFAULT '',
274
289
  integration_closure TEXT NOT NULL DEFAULT '',
275
290
  observability_impact TEXT NOT NULL DEFAULT '',
276
- sequence INTEGER DEFAULT 0, -- DEAD CODE: no tool exposes sequence always 0
291
+ sequence INTEGER DEFAULT 0, -- Ordering hint: tools may set this to control execution order
277
292
  replan_triggered_at TEXT DEFAULT NULL,
278
293
  PRIMARY KEY (milestone_id, id),
279
294
  FOREIGN KEY (milestone_id) REFERENCES milestones(id)
@@ -306,7 +321,7 @@ function initSchema(db: DbAdapter, fileBacked: boolean): void {
306
321
  expected_output TEXT NOT NULL DEFAULT '[]',
307
322
  observability_impact TEXT NOT NULL DEFAULT '',
308
323
  full_plan_md TEXT NOT NULL DEFAULT '',
309
- sequence INTEGER DEFAULT 0, -- DEAD CODE: no tool exposes sequence always 0
324
+ sequence INTEGER DEFAULT 0, -- Ordering hint: tools may set this to control execution order
310
325
  PRIMARY KEY (milestone_id, slice_id, id),
311
326
  FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
312
327
  )
@@ -372,9 +387,31 @@ function initSchema(db: DbAdapter, fileBacked: boolean): void {
372
387
  )
373
388
  `);
374
389
 
390
+ // Slice dependency junction table (v14)
391
+ db.exec(`
392
+ CREATE TABLE IF NOT EXISTS slice_dependencies (
393
+ milestone_id TEXT NOT NULL,
394
+ slice_id TEXT NOT NULL,
395
+ depends_on_slice_id TEXT NOT NULL,
396
+ PRIMARY KEY (milestone_id, slice_id, depends_on_slice_id),
397
+ FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id),
398
+ FOREIGN KEY (milestone_id, depends_on_slice_id) REFERENCES slices(milestone_id, id)
399
+ )
400
+ `);
401
+
375
402
  db.exec("CREATE INDEX IF NOT EXISTS idx_memories_active ON memories(superseded_by)");
376
403
  db.exec("CREATE INDEX IF NOT EXISTS idx_replan_history_milestone ON replan_history(milestone_id, created_at)");
377
404
 
405
+ // v13 indexes — hot-path dispatch queries
406
+ db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_active ON tasks(milestone_id, slice_id, status)");
407
+ db.exec("CREATE INDEX IF NOT EXISTS idx_slices_active ON slices(milestone_id, status)");
408
+ db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
409
+ db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
410
+ db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
411
+
412
+ // v14 index — slice dependency lookups
413
+ db.exec("CREATE INDEX IF NOT EXISTS idx_slice_deps_target ON slice_dependencies(milestone_id, depends_on_slice_id)");
414
+
378
415
  db.exec(`CREATE VIEW IF NOT EXISTS active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL`);
379
416
  db.exec(`CREATE VIEW IF NOT EXISTS active_requirements AS SELECT * FROM requirements WHERE superseded_by IS NULL`);
380
417
  db.exec(`CREATE VIEW IF NOT EXISTS active_memories AS SELECT * FROM memories WHERE superseded_by IS NULL`);
@@ -677,6 +714,37 @@ function migrateSchema(db: DbAdapter): void {
677
714
  });
678
715
  }
679
716
 
717
+ if (currentVersion < 13) {
718
+ // Hot-path indexes for auto-loop dispatch queries
719
+ db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_active ON tasks(milestone_id, slice_id, status)");
720
+ db.exec("CREATE INDEX IF NOT EXISTS idx_slices_active ON slices(milestone_id, status)");
721
+ db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
722
+ db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
723
+ db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
724
+ db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
725
+ ":version": 13,
726
+ ":applied_at": new Date().toISOString(),
727
+ });
728
+ }
729
+
730
+ if (currentVersion < 14) {
731
+ db.exec(`
732
+ CREATE TABLE IF NOT EXISTS slice_dependencies (
733
+ milestone_id TEXT NOT NULL,
734
+ slice_id TEXT NOT NULL,
735
+ depends_on_slice_id TEXT NOT NULL,
736
+ PRIMARY KEY (milestone_id, slice_id, depends_on_slice_id),
737
+ FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id),
738
+ FOREIGN KEY (milestone_id, depends_on_slice_id) REFERENCES slices(milestone_id, id)
739
+ )
740
+ `);
741
+ db.exec("CREATE INDEX IF NOT EXISTS idx_slice_deps_target ON slice_dependencies(milestone_id, depends_on_slice_id)");
742
+ db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
743
+ ":version": 14,
744
+ ":applied_at": new Date().toISOString(),
745
+ });
746
+ }
747
+
680
748
  db.exec("COMMIT");
681
749
  } catch (err) {
682
750
  db.exec("ROLLBACK");
@@ -731,6 +799,10 @@ export function closeDatabase(): void {
731
799
  try {
732
800
  currentDb.exec('PRAGMA wal_checkpoint(TRUNCATE)');
733
801
  } catch { /* non-fatal — best effort before close */ }
802
+ try {
803
+ // Incremental vacuum to reclaim space without blocking
804
+ currentDb.exec('PRAGMA incremental_vacuum(64)');
805
+ } catch { /* non-fatal */ }
734
806
  try {
735
807
  currentDb.close();
736
808
  } catch {
@@ -742,8 +814,31 @@ export function closeDatabase(): void {
742
814
  }
743
815
  }
744
816
 
817
+ /** Run a full VACUUM — call sparingly (e.g. after milestone completion). */
818
+ export function vacuumDatabase(): void {
819
+ if (!currentDb) return;
820
+ try {
821
+ currentDb.exec('VACUUM');
822
+ } catch { /* non-fatal */ }
823
+ }
824
+
825
+ let _txDepth = 0;
826
+
745
827
  export function transaction<T>(fn: () => T): T {
746
828
  if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
829
+
830
+ // Re-entrant: if already inside a transaction, just run fn() without
831
+ // starting a new one. SQLite does not support nested BEGIN/COMMIT.
832
+ if (_txDepth > 0) {
833
+ _txDepth++;
834
+ try {
835
+ return fn();
836
+ } finally {
837
+ _txDepth--;
838
+ }
839
+ }
840
+
841
+ _txDepth++;
747
842
  currentDb.exec("BEGIN");
748
843
  try {
749
844
  const result = fn();
@@ -752,6 +847,8 @@ export function transaction<T>(fn: () => T): T {
752
847
  } catch (err) {
753
848
  currentDb.exec("ROLLBACK");
754
849
  throw err;
850
+ } finally {
851
+ _txDepth--;
755
852
  }
756
853
  }
757
854
 
@@ -1308,6 +1405,20 @@ export function updateSliceStatus(milestoneId: string, sliceId: string, status:
1308
1405
  });
1309
1406
  }
1310
1407
 
1408
+ export function setTaskSummaryMd(milestoneId: string, sliceId: string, taskId: string, md: string): void {
1409
+ if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1410
+ currentDb.prepare(
1411
+ `UPDATE tasks SET full_summary_md = :md WHERE milestone_id = :mid AND slice_id = :sid AND id = :tid`,
1412
+ ).run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId, ":md": md });
1413
+ }
1414
+
1415
+ export function setSliceSummaryMd(milestoneId: string, sliceId: string, summaryMd: string, uatMd: string): void {
1416
+ if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1417
+ currentDb.prepare(
1418
+ `UPDATE slices SET full_summary_md = :summary_md, full_uat_md = :uat_md WHERE milestone_id = :mid AND id = :sid`,
1419
+ ).run({ ":mid": milestoneId, ":sid": sliceId, ":summary_md": summaryMd, ":uat_md": uatMd });
1420
+ }
1421
+
1311
1422
  export interface TaskRow {
1312
1423
  milestone_id: string;
1313
1424
  slice_id: string;
@@ -1485,6 +1596,18 @@ export function getMilestone(id: string): MilestoneRow | null {
1485
1596
  return rowToMilestone(row);
1486
1597
  }
1487
1598
 
1599
+ /**
1600
+ * Update a milestone's status in the database.
1601
+ * Used by park/unpark to keep the DB in sync with the filesystem marker.
1602
+ * See: https://github.com/gsd-build/gsd-2/issues/2694
1603
+ */
1604
+ export function updateMilestoneStatus(milestoneId: string, status: string, completedAt?: string | null): void {
1605
+ if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1606
+ currentDb.prepare(
1607
+ `UPDATE milestones SET status = :status, completed_at = :completed_at WHERE id = :id`,
1608
+ ).run({ ":status": status, ":completed_at": completedAt ?? null, ":id": milestoneId });
1609
+ }
1610
+
1488
1611
  export function getActiveMilestoneFromDb(): MilestoneRow | null {
1489
1612
  if (!currentDb) return null;
1490
1613
  const row = currentDb.prepare(
@@ -1496,23 +1619,24 @@ export function getActiveMilestoneFromDb(): MilestoneRow | null {
1496
1619
 
1497
1620
  export function getActiveSliceFromDb(milestoneId: string): SliceRow | null {
1498
1621
  if (!currentDb) return null;
1499
- const rows = currentDb.prepare(
1500
- "SELECT * FROM slices WHERE milestone_id = :mid AND status NOT IN ('complete', 'done') ORDER BY sequence, id",
1501
- ).all({ ":mid": milestoneId });
1502
- if (rows.length === 0) return null;
1503
1622
 
1504
- const completedRows = currentDb.prepare(
1505
- "SELECT id FROM slices WHERE milestone_id = :mid AND status IN ('complete', 'done')",
1506
- ).all({ ":mid": milestoneId });
1507
- const completedIds = new Set(completedRows.map((r) => r["id"] as string));
1508
-
1509
- for (const row of rows) {
1510
- const slice = rowToSlice(row);
1511
- if (slice.depends.length === 0 || slice.depends.every((d) => completedIds.has(d))) {
1512
- return slice;
1513
- }
1514
- }
1515
- return null;
1623
+ // Single query: find the first non-complete slice whose dependencies are all satisfied.
1624
+ // Uses json_each() to expand the JSON depends array and checks each dep is complete.
1625
+ const row = currentDb.prepare(
1626
+ `SELECT s.* FROM slices s
1627
+ WHERE s.milestone_id = :mid
1628
+ AND s.status NOT IN ('complete', 'done')
1629
+ AND NOT EXISTS (
1630
+ SELECT 1 FROM json_each(s.depends) AS dep
1631
+ WHERE dep.value NOT IN (
1632
+ SELECT id FROM slices WHERE milestone_id = :mid AND status IN ('complete', 'done')
1633
+ )
1634
+ )
1635
+ ORDER BY s.sequence, s.id
1636
+ LIMIT 1`,
1637
+ ).get({ ":mid": milestoneId });
1638
+ if (!row) return null;
1639
+ return rowToSlice(row);
1516
1640
  }
1517
1641
 
1518
1642
  export function getActiveTaskFromDb(milestoneId: string, sliceId: string): TaskRow | null {
@@ -1537,6 +1661,73 @@ export function getArtifact(path: string): ArtifactRow | null {
1537
1661
  return rowToArtifact(row);
1538
1662
  }
1539
1663
 
1664
+ // ─── Lightweight Query Variants (hot-path optimized) ─────────────────────
1665
+
1666
+ /** Fast milestone status check — avoids deserializing JSON planning fields. */
1667
+ export function getActiveMilestoneIdFromDb(): { id: string; status: string } | null {
1668
+ if (!currentDb) return null;
1669
+ const row = currentDb.prepare(
1670
+ "SELECT id, status FROM milestones WHERE status NOT IN ('complete', 'parked') ORDER BY id LIMIT 1",
1671
+ ).get();
1672
+ if (!row) return null;
1673
+ return { id: row["id"] as string, status: row["status"] as string };
1674
+ }
1675
+
1676
+ /** Fast slice status check — avoids deserializing JSON depends/planning fields. */
1677
+ export function getSliceStatusSummary(milestoneId: string): Array<{ id: string; status: string }> {
1678
+ if (!currentDb) return [];
1679
+ return currentDb.prepare(
1680
+ "SELECT id, status FROM slices WHERE milestone_id = :mid ORDER BY sequence, id",
1681
+ ).all({ ":mid": milestoneId }).map((r) => ({ id: r["id"] as string, status: r["status"] as string }));
1682
+ }
1683
+
1684
+ /** Fast task status check — avoids deserializing JSON arrays and large text fields. */
1685
+ export function getActiveTaskIdFromDb(milestoneId: string, sliceId: string): { id: string; status: string; title: string } | null {
1686
+ if (!currentDb) return null;
1687
+ const row = currentDb.prepare(
1688
+ "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",
1689
+ ).get({ ":mid": milestoneId, ":sid": sliceId });
1690
+ if (!row) return null;
1691
+ return { id: row["id"] as string, status: row["status"] as string, title: row["title"] as string };
1692
+ }
1693
+
1694
+ /** Count tasks by status for a slice — useful for progress reporting without full row load. */
1695
+ export function getSliceTaskCounts(milestoneId: string, sliceId: string): { total: number; done: number; pending: number } {
1696
+ if (!currentDb) return { total: 0, done: 0, pending: 0 };
1697
+ const row = currentDb.prepare(
1698
+ `SELECT
1699
+ COUNT(*) as total,
1700
+ SUM(CASE WHEN status IN ('complete', 'done') THEN 1 ELSE 0 END) as done,
1701
+ SUM(CASE WHEN status NOT IN ('complete', 'done') THEN 1 ELSE 0 END) as pending
1702
+ FROM tasks WHERE milestone_id = :mid AND slice_id = :sid`,
1703
+ ).get({ ":mid": milestoneId, ":sid": sliceId });
1704
+ if (!row) return { total: 0, done: 0, pending: 0 };
1705
+ return { total: (row["total"] as number) ?? 0, done: (row["done"] as number) ?? 0, pending: (row["pending"] as number) ?? 0 };
1706
+ }
1707
+
1708
+ // ─── Slice Dependencies (junction table) ─────────────────────────────────
1709
+
1710
+ /** Sync the slice_dependencies junction table from a slice's JSON depends array. */
1711
+ export function syncSliceDependencies(milestoneId: string, sliceId: string, depends: string[]): void {
1712
+ if (!currentDb) return;
1713
+ currentDb.prepare(
1714
+ "DELETE FROM slice_dependencies WHERE milestone_id = :mid AND slice_id = :sid",
1715
+ ).run({ ":mid": milestoneId, ":sid": sliceId });
1716
+ for (const dep of depends) {
1717
+ currentDb.prepare(
1718
+ "INSERT OR IGNORE INTO slice_dependencies (milestone_id, slice_id, depends_on_slice_id) VALUES (:mid, :sid, :dep)",
1719
+ ).run({ ":mid": milestoneId, ":sid": sliceId, ":dep": dep });
1720
+ }
1721
+ }
1722
+
1723
+ /** Get all slices that depend on a given slice. */
1724
+ export function getDependentSlices(milestoneId: string, sliceId: string): string[] {
1725
+ if (!currentDb) return [];
1726
+ return currentDb.prepare(
1727
+ "SELECT slice_id FROM slice_dependencies WHERE milestone_id = :mid AND depends_on_slice_id = :sid",
1728
+ ).all({ ":mid": milestoneId, ":sid": sliceId }).map((r) => r["slice_id"] as string);
1729
+ }
1730
+
1540
1731
  // ─── Worktree DB Helpers ──────────────────────────────────────────────────
1541
1732
 
1542
1733
  export function copyWorktreeDb(srcDbPath: string, destDbPath: string): boolean {
@@ -1552,18 +1743,28 @@ export function copyWorktreeDb(srcDbPath: string, destDbPath: string): boolean {
1552
1743
  }
1553
1744
  }
1554
1745
 
1555
- export function reconcileWorktreeDb(
1556
- mainDbPath: string,
1557
- worktreeDbPath: string,
1558
- ): {
1746
+ export interface ReconcileResult {
1559
1747
  decisions: number;
1560
1748
  requirements: number;
1561
1749
  artifacts: number;
1750
+ milestones: number;
1751
+ slices: number;
1752
+ tasks: number;
1753
+ memories: number;
1754
+ verification_evidence: number;
1562
1755
  conflicts: string[];
1563
- } {
1564
- const zero = { decisions: 0, requirements: 0, artifacts: 0, conflicts: [] as string[] };
1756
+ }
1757
+
1758
+ export function reconcileWorktreeDb(
1759
+ mainDbPath: string,
1760
+ worktreeDbPath: string,
1761
+ ): ReconcileResult {
1762
+ const zero: ReconcileResult = { decisions: 0, requirements: 0, artifacts: 0, milestones: 0, slices: 0, tasks: 0, memories: 0, verification_evidence: 0, conflicts: [] };
1565
1763
  if (!existsSync(worktreeDbPath)) return zero;
1566
- if (worktreeDbPath.includes("'")) {
1764
+ // Sanitize path: reject any characters that could break ATTACH syntax.
1765
+ // ATTACH DATABASE doesn't support parameterized paths in all providers,
1766
+ // so we use strict allowlist validation instead.
1767
+ if (/['";\x00]/.test(worktreeDbPath)) {
1567
1768
  process.stderr.write("gsd-db: worktree DB reconciliation failed: path contains unsafe characters\n");
1568
1769
  return zero;
1569
1770
  }
@@ -1594,20 +1795,24 @@ export function reconcileWorktreeDb(
1594
1795
  ).all();
1595
1796
  for (const row of reqConf) conflicts.push(`requirement ${(row as Record<string, unknown>)["id"]}: modified in both`);
1596
1797
 
1597
- const merged = { decisions: 0, requirements: 0, artifacts: 0 };
1798
+ const merged: Omit<ReconcileResult, "conflicts"> = { decisions: 0, requirements: 0, artifacts: 0, milestones: 0, slices: 0, tasks: 0, memories: 0, verification_evidence: 0 };
1799
+
1800
+ function countChanges(result: unknown): number {
1801
+ return typeof result === "object" && result !== null ? ((result as { changes?: number }).changes ?? 0) : 0;
1802
+ }
1803
+
1598
1804
  adapter.exec("BEGIN");
1599
1805
  try {
1600
- const dR = adapter.prepare(`
1806
+ merged.decisions = countChanges(adapter.prepare(`
1601
1807
  INSERT OR REPLACE INTO decisions (
1602
1808
  id, when_context, scope, decision, choice, rationale, revisable, made_by, superseded_by
1603
1809
  )
1604
1810
  SELECT id, when_context, scope, decision, choice, rationale, revisable, ${
1605
1811
  hasMadeBy ? "made_by" : "'agent'"
1606
1812
  }, superseded_by FROM wt.decisions
1607
- `).run();
1608
- merged.decisions = typeof dR === "object" && dR !== null ? ((dR as { changes?: number }).changes ?? 0) : 0;
1813
+ `).run());
1609
1814
 
1610
- const rR = adapter.prepare(`
1815
+ merged.requirements = countChanges(adapter.prepare(`
1611
1816
  INSERT OR REPLACE INTO requirements (
1612
1817
  id, class, status, description, why, source, primary_owner,
1613
1818
  supporting_slices, validation, notes, full_content, superseded_by
@@ -1615,17 +1820,80 @@ export function reconcileWorktreeDb(
1615
1820
  SELECT id, class, status, description, why, source, primary_owner,
1616
1821
  supporting_slices, validation, notes, full_content, superseded_by
1617
1822
  FROM wt.requirements
1618
- `).run();
1619
- merged.requirements = typeof rR === "object" && rR !== null ? ((rR as { changes?: number }).changes ?? 0) : 0;
1823
+ `).run());
1620
1824
 
1621
- const aR = adapter.prepare(`
1825
+ merged.artifacts = countChanges(adapter.prepare(`
1622
1826
  INSERT OR REPLACE INTO artifacts (
1623
1827
  path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at
1624
1828
  )
1625
1829
  SELECT path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at
1626
1830
  FROM wt.artifacts
1627
- `).run();
1628
- merged.artifacts = typeof aR === "object" && aR !== null ? ((aR as { changes?: number }).changes ?? 0) : 0;
1831
+ `).run());
1832
+
1833
+ // Merge milestones — worktree may have updated status/planning fields
1834
+ merged.milestones = countChanges(adapter.prepare(`
1835
+ INSERT OR REPLACE INTO milestones (
1836
+ id, title, status, depends_on, created_at, completed_at,
1837
+ vision, success_criteria, key_risks, proof_strategy,
1838
+ verification_contract, verification_integration, verification_operational, verification_uat,
1839
+ definition_of_done, requirement_coverage, boundary_map_markdown
1840
+ )
1841
+ SELECT id, title, status, depends_on, created_at, completed_at,
1842
+ vision, success_criteria, key_risks, proof_strategy,
1843
+ verification_contract, verification_integration, verification_operational, verification_uat,
1844
+ definition_of_done, requirement_coverage, boundary_map_markdown
1845
+ FROM wt.milestones
1846
+ `).run());
1847
+
1848
+ // Merge slices — preserve worktree progress (status, summaries, planning)
1849
+ merged.slices = countChanges(adapter.prepare(`
1850
+ INSERT OR REPLACE INTO slices (
1851
+ milestone_id, id, title, status, risk, depends, demo, created_at, completed_at,
1852
+ full_summary_md, full_uat_md, goal, success_criteria, proof_level,
1853
+ integration_closure, observability_impact, sequence, replan_triggered_at
1854
+ )
1855
+ SELECT milestone_id, id, title, status, risk, depends, demo, created_at, completed_at,
1856
+ full_summary_md, full_uat_md, goal, success_criteria, proof_level,
1857
+ integration_closure, observability_impact, sequence, replan_triggered_at
1858
+ FROM wt.slices
1859
+ `).run());
1860
+
1861
+ // Merge tasks — preserve execution results, status, summaries
1862
+ merged.tasks = countChanges(adapter.prepare(`
1863
+ INSERT OR REPLACE INTO tasks (
1864
+ milestone_id, slice_id, id, title, status, one_liner, narrative,
1865
+ verification_result, duration, completed_at, blocker_discovered,
1866
+ deviations, known_issues, key_files, key_decisions, full_summary_md,
1867
+ description, estimate, files, verify, inputs, expected_output,
1868
+ observability_impact, full_plan_md, sequence
1869
+ )
1870
+ SELECT milestone_id, slice_id, id, title, status, one_liner, narrative,
1871
+ verification_result, duration, completed_at, blocker_discovered,
1872
+ deviations, known_issues, key_files, key_decisions, full_summary_md,
1873
+ description, estimate, files, verify, inputs, expected_output,
1874
+ observability_impact, full_plan_md, sequence
1875
+ FROM wt.tasks
1876
+ `).run());
1877
+
1878
+ // Merge memories — keep worktree-learned insights
1879
+ merged.memories = countChanges(adapter.prepare(`
1880
+ INSERT OR REPLACE INTO memories (
1881
+ seq, id, category, content, confidence, source_unit_type, source_unit_id,
1882
+ created_at, updated_at, superseded_by, hit_count
1883
+ )
1884
+ SELECT seq, id, category, content, confidence, source_unit_type, source_unit_id,
1885
+ created_at, updated_at, superseded_by, hit_count
1886
+ FROM wt.memories
1887
+ `).run());
1888
+
1889
+ // Merge verification evidence — append-only, use INSERT OR IGNORE to avoid duplicates
1890
+ merged.verification_evidence = countChanges(adapter.prepare(`
1891
+ INSERT OR IGNORE INTO verification_evidence (
1892
+ task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at
1893
+ )
1894
+ SELECT task_id, slice_id, milestone_id, command, exit_code, verdict, duration_ms, created_at
1895
+ FROM wt.verification_evidence
1896
+ `).run());
1629
1897
 
1630
1898
  adapter.exec("COMMIT");
1631
1899
  } catch (txErr) {
@@ -1694,29 +1962,53 @@ export function insertAssessment(entry: {
1694
1962
  });
1695
1963
  }
1696
1964
 
1697
- export function deleteTask(milestoneId: string, sliceId: string, taskId: string): void {
1965
+ export function deleteAssessmentByScope(milestoneId: string, scope: string): void {
1698
1966
  if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1699
- // Must delete verification_evidence first (FK constraint)
1700
1967
  currentDb.prepare(
1701
- `DELETE FROM verification_evidence WHERE milestone_id = :mid AND slice_id = :sid AND task_id = :tid`,
1702
- ).run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
1968
+ `DELETE FROM assessments WHERE milestone_id = :mid AND scope = :scope`,
1969
+ ).run({ ":mid": milestoneId, ":scope": scope });
1970
+ }
1971
+
1972
+ export function deleteVerificationEvidence(milestoneId: string, sliceId: string, taskId: string): void {
1973
+ if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1703
1974
  currentDb.prepare(
1704
- `DELETE FROM tasks WHERE milestone_id = :mid AND slice_id = :sid AND id = :tid`,
1975
+ `DELETE FROM verification_evidence WHERE milestone_id = :mid AND slice_id = :sid AND task_id = :tid`,
1705
1976
  ).run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
1706
1977
  }
1707
1978
 
1979
+ export function deleteTask(milestoneId: string, sliceId: string, taskId: string): void {
1980
+ if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1981
+ transaction(() => {
1982
+ // Must delete verification_evidence first (FK constraint)
1983
+ currentDb!.prepare(
1984
+ `DELETE FROM verification_evidence WHERE milestone_id = :mid AND slice_id = :sid AND task_id = :tid`,
1985
+ ).run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
1986
+ currentDb!.prepare(
1987
+ `DELETE FROM tasks WHERE milestone_id = :mid AND slice_id = :sid AND id = :tid`,
1988
+ ).run({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
1989
+ });
1990
+ }
1991
+
1708
1992
  export function deleteSlice(milestoneId: string, sliceId: string): void {
1709
1993
  if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1710
- // Cascade-style manual deletion: evidence → tasks → slice
1711
- currentDb.prepare(
1712
- `DELETE FROM verification_evidence WHERE milestone_id = :mid AND slice_id = :sid`,
1713
- ).run({ ":mid": milestoneId, ":sid": sliceId });
1714
- currentDb.prepare(
1715
- `DELETE FROM tasks WHERE milestone_id = :mid AND slice_id = :sid`,
1716
- ).run({ ":mid": milestoneId, ":sid": sliceId });
1717
- currentDb.prepare(
1718
- `DELETE FROM slices WHERE milestone_id = :mid AND id = :sid`,
1719
- ).run({ ":mid": milestoneId, ":sid": sliceId });
1994
+ transaction(() => {
1995
+ // Cascade-style manual deletion: evidence → tasks → dependencies → slice
1996
+ currentDb!.prepare(
1997
+ `DELETE FROM verification_evidence WHERE milestone_id = :mid AND slice_id = :sid`,
1998
+ ).run({ ":mid": milestoneId, ":sid": sliceId });
1999
+ currentDb!.prepare(
2000
+ `DELETE FROM tasks WHERE milestone_id = :mid AND slice_id = :sid`,
2001
+ ).run({ ":mid": milestoneId, ":sid": sliceId });
2002
+ currentDb!.prepare(
2003
+ `DELETE FROM slice_dependencies WHERE milestone_id = :mid AND slice_id = :sid`,
2004
+ ).run({ ":mid": milestoneId, ":sid": sliceId });
2005
+ currentDb!.prepare(
2006
+ `DELETE FROM slice_dependencies WHERE milestone_id = :mid AND depends_on_slice_id = :sid`,
2007
+ ).run({ ":mid": milestoneId, ":sid": sliceId });
2008
+ currentDb!.prepare(
2009
+ `DELETE FROM slices WHERE milestone_id = :mid AND id = :sid`,
2010
+ ).run({ ":mid": milestoneId, ":sid": sliceId });
2011
+ });
1720
2012
  }
1721
2013
 
1722
2014
  export function updateSliceFields(milestoneId: string, sliceId: string, fields: {
@@ -517,8 +517,9 @@ export async function showDiscuss(
517
517
 
518
518
  const state = await deriveState(basePath);
519
519
 
520
- // No active milestone check for pending milestones to discuss instead
521
- if (!state.activeMilestone) {
520
+ // No active milestone (or corrupted milestone with undefined id)
521
+ // check for pending milestones to discuss instead
522
+ if (!state.activeMilestone?.id) {
522
523
  const pendingMilestones = state.registry.filter(m => m.status === "pending");
523
524
  if (pendingMilestones.length === 0) {
524
525
  ctx.ui.notify("No active milestone. Run /gsd to create one first.", "warning");
@@ -1043,7 +1044,7 @@ export async function showSmartEntry(
1043
1044
 
1044
1045
  const state = await deriveState(basePath);
1045
1046
 
1046
- if (!state.activeMilestone) {
1047
+ if (!state.activeMilestone?.id) {
1047
1048
  // Guard: if a discuss session is already in flight, don't re-inject the prompt.
1048
1049
  // Both /gsd and /gsd auto reach this branch when no milestone exists yet.
1049
1050
  // Without this guard, every subsequent /gsd call overwrites pendingAutoStart
@@ -422,9 +422,9 @@ function bootstrapGsdDirectory(
422
422
  const gsd = gsdRoot(basePath);
423
423
  mkdirSync(join(gsd, "milestones"), { recursive: true });
424
424
 
425
- // Write preferences.md from wizard answers
425
+ // Write PREFERENCES.md from wizard answers
426
426
  const preferencesContent = buildPreferencesFile(prefs);
427
- writeFileSync(join(gsd, "preferences.md"), preferencesContent, "utf-8");
427
+ writeFileSync(join(gsd, "PREFERENCES.md"), preferencesContent, "utf-8");
428
428
 
429
429
  // Seed CONTEXT.md with detected project signals
430
430
  const contextContent = buildContextSeed(signals);