gsd-pi 2.79.0 → 2.80.0-dev.4ea7d80e7

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 (805) hide show
  1. package/README.md +94 -47
  2. package/dist/loader.js +0 -0
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/extensions/github-sync/templates.js +90 -74
  5. package/dist/resources/extensions/gsd/auto/contracts.js +1 -0
  6. package/dist/resources/extensions/gsd/auto/custom-verify-retry-store.js +53 -0
  7. package/dist/resources/extensions/gsd/auto/loop.js +365 -522
  8. package/dist/resources/extensions/gsd/auto/orchestrator.js +146 -0
  9. package/dist/resources/extensions/gsd/auto/phases.js +61 -7
  10. package/dist/resources/extensions/gsd/auto/run-unit.js +19 -15
  11. package/dist/resources/extensions/gsd/auto/session.js +8 -0
  12. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-dispatch-outcome.js +12 -0
  13. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-iteration.js +24 -0
  14. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-reconcile-outcome.js +33 -0
  15. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-reconcile.js +26 -0
  16. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-retry.js +49 -0
  17. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-verify-outcome.js +25 -0
  18. package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +48 -0
  19. package/dist/resources/extensions/gsd/auto/workflow-dispatch-ledger.js +26 -0
  20. package/dist/resources/extensions/gsd/auto/workflow-iteration-completion.js +10 -0
  21. package/dist/resources/extensions/gsd/auto/workflow-journal-reporter.js +16 -0
  22. package/dist/resources/extensions/gsd/auto/workflow-kernel.js +263 -0
  23. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +36 -0
  24. package/dist/resources/extensions/gsd/auto/workflow-phase-reporter.js +9 -0
  25. package/dist/resources/extensions/gsd/auto/workflow-session-lock.js +35 -0
  26. package/dist/resources/extensions/gsd/auto/workflow-sidecar-iteration.js +24 -0
  27. package/dist/resources/extensions/gsd/auto/workflow-sidecar-queue.js +26 -0
  28. package/dist/resources/extensions/gsd/auto/workflow-turn-reporter.js +36 -0
  29. package/dist/resources/extensions/gsd/auto/workflow-unit-dispatch.js +44 -0
  30. package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +15 -0
  31. package/dist/resources/extensions/gsd/auto-artifact-paths.js +2 -2
  32. package/dist/resources/extensions/gsd/auto-dashboard.js +54 -15
  33. package/dist/resources/extensions/gsd/auto-dispatch.js +12 -0
  34. package/dist/resources/extensions/gsd/auto-prompts.js +220 -32
  35. package/dist/resources/extensions/gsd/auto-recovery.js +216 -62
  36. package/dist/resources/extensions/gsd/auto-runtime-state.js +4 -0
  37. package/dist/resources/extensions/gsd/auto-start.js +4 -4
  38. package/dist/resources/extensions/gsd/auto-verification.js +2 -11
  39. package/dist/resources/extensions/gsd/auto-worktree.js +87 -38
  40. package/dist/resources/extensions/gsd/auto.js +168 -3
  41. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +24 -2
  42. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -0
  43. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -2
  44. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +63 -51
  45. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +137 -9
  46. package/dist/resources/extensions/gsd/commands/context.js +1 -1
  47. package/dist/resources/extensions/gsd/commands-extract-learnings.js +17 -12
  48. package/dist/resources/extensions/gsd/commands-ship.js +23 -46
  49. package/dist/resources/extensions/gsd/commands-workflow-templates.js +12 -7
  50. package/dist/resources/extensions/gsd/component-loader.js +5 -11
  51. package/dist/resources/extensions/gsd/custom-workflow-engine.js +25 -1
  52. package/dist/resources/extensions/gsd/db-adapter.js +47 -0
  53. package/dist/resources/extensions/gsd/db-base-schema.js +351 -0
  54. package/dist/resources/extensions/gsd/db-connection-cache.js +31 -0
  55. package/dist/resources/extensions/gsd/db-coordination-schema.js +104 -0
  56. package/dist/resources/extensions/gsd/db-decision-requirement-rows.js +71 -0
  57. package/dist/resources/extensions/gsd/db-gate-rows.js +16 -0
  58. package/dist/resources/extensions/gsd/db-lightweight-query-rows.js +29 -0
  59. package/dist/resources/extensions/gsd/db-memory-fts-schema.js +56 -0
  60. package/dist/resources/extensions/gsd/db-migration-backup.js +22 -0
  61. package/dist/resources/extensions/gsd/db-migration-steps.js +410 -0
  62. package/dist/resources/extensions/gsd/db-milestone-artifact-rows.js +35 -0
  63. package/dist/resources/extensions/gsd/db-open-state.js +32 -0
  64. package/dist/resources/extensions/gsd/db-provider.js +108 -0
  65. package/dist/resources/extensions/gsd/db-runtime-kv-schema.js +27 -0
  66. package/dist/resources/extensions/gsd/db-schema-metadata.js +23 -0
  67. package/dist/resources/extensions/gsd/db-task-slice-rows.js +86 -0
  68. package/dist/resources/extensions/gsd/db-transaction.js +63 -0
  69. package/dist/resources/extensions/gsd/db-verification-evidence-rows.js +3 -0
  70. package/dist/resources/extensions/gsd/db-verification-evidence-schema.js +19 -0
  71. package/dist/resources/extensions/gsd/escalation.js +2 -0
  72. package/dist/resources/extensions/gsd/graph.js +9 -3
  73. package/dist/resources/extensions/gsd/gsd-db.js +316 -1520
  74. package/dist/resources/extensions/gsd/guided-flow.js +42 -2
  75. package/dist/resources/extensions/gsd/legacy-telemetry.js +70 -0
  76. package/dist/resources/extensions/gsd/markdown-renderer.js +2 -0
  77. package/dist/resources/extensions/gsd/model-router.js +9 -6
  78. package/dist/resources/extensions/gsd/notification-widget.js +21 -3
  79. package/dist/resources/extensions/gsd/paths.js +5 -1
  80. package/dist/resources/extensions/gsd/post-execution-checks.js +27 -6
  81. package/dist/resources/extensions/gsd/pr-evidence.js +117 -0
  82. package/dist/resources/extensions/gsd/pre-execution-checks.js +2 -0
  83. package/dist/resources/extensions/gsd/preferences-types.js +20 -2
  84. package/dist/resources/extensions/gsd/preferences-validation.js +3 -3
  85. package/dist/resources/extensions/gsd/process-task-path.js +61 -0
  86. package/dist/resources/extensions/gsd/prompt-loader.js +9 -5
  87. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +32 -30
  88. package/dist/resources/extensions/gsd/prompts/complete-slice.md +23 -34
  89. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +50 -96
  90. package/dist/resources/extensions/gsd/prompts/discuss.md +81 -181
  91. package/dist/resources/extensions/gsd/prompts/execute-task.md +40 -67
  92. package/dist/resources/extensions/gsd/prompts/forensics.md +41 -84
  93. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +29 -39
  94. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +30 -65
  95. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +25 -52
  96. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +36 -36
  97. package/dist/resources/extensions/gsd/prompts/guided-research-project.md +20 -38
  98. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +45 -59
  99. package/dist/resources/extensions/gsd/prompts/plan-slice.md +25 -87
  100. package/dist/resources/extensions/gsd/prompts/queue.md +46 -53
  101. package/dist/resources/extensions/gsd/prompts/refine-slice.md +23 -23
  102. package/dist/resources/extensions/gsd/prompts/research-slice.md +23 -23
  103. package/dist/resources/extensions/gsd/prompts/rethink.md +10 -10
  104. package/dist/resources/extensions/gsd/prompts/system.md +65 -107
  105. package/dist/resources/extensions/gsd/prompts/triage-captures.md +15 -15
  106. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +24 -24
  107. package/dist/resources/extensions/gsd/prompts/worktree-merge.md +35 -35
  108. package/dist/resources/extensions/gsd/state.js +4 -0
  109. package/dist/resources/extensions/gsd/tools/complete-milestone.js +14 -9
  110. package/dist/resources/extensions/gsd/tools/complete-task.js +2 -0
  111. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +88 -3
  112. package/dist/resources/extensions/gsd/unit-context-composer.js +32 -0
  113. package/dist/resources/extensions/gsd/unit-context-manifest.js +21 -0
  114. package/dist/resources/extensions/gsd/uok/audit.js +23 -9
  115. package/dist/resources/extensions/gsd/uok/contracts.js +69 -1
  116. package/dist/resources/extensions/gsd/uok/dispatch-envelope.js +3 -0
  117. package/dist/resources/extensions/gsd/uok/kernel.js +8 -3
  118. package/dist/resources/extensions/gsd/uok/loop-adapter.js +48 -33
  119. package/dist/resources/extensions/gsd/uok/plan-v2.js +2 -0
  120. package/dist/resources/extensions/gsd/uok/timeline.js +125 -0
  121. package/dist/resources/extensions/gsd/workflow-logger.js +13 -13
  122. package/dist/resources/extensions/gsd/workflow-manifest.js +2 -0
  123. package/dist/resources/extensions/gsd/workflow-projections.js +2 -0
  124. package/dist/resources/extensions/gsd/workflow-templates.js +9 -0
  125. package/dist/resources/extensions/gsd/working-output-messages.js +64 -0
  126. package/dist/resources/extensions/shared/gsd-phase-state.js +45 -3
  127. package/dist/resources/extensions/shared/interview-ui.js +15 -4
  128. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  129. package/dist/web/standalone/.next/BUILD_ID +1 -1
  130. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  131. package/dist/web/standalone/.next/build-manifest.json +4 -4
  132. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  133. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  134. package/dist/web/standalone/.next/required-server-files.json +4 -4
  135. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  136. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  138. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  145. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  146. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  148. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  149. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  150. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  151. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  152. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  153. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  154. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  155. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  160. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  165. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  174. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  179. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  181. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  184. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  187. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  190. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  193. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  196. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  199. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  201. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  202. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  203. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  204. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  205. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  206. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  207. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  208. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  210. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  211. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  212. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  213. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  214. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  215. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  216. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  217. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  218. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  219. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  220. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  221. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  222. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  223. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  224. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  225. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  226. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  227. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  228. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  229. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  230. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  231. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  232. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  233. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  234. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  235. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  236. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  237. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  238. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  239. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  240. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  241. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  242. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  243. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  244. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  245. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  246. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  247. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  248. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  249. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  250. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  251. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  252. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  253. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  254. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  255. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  256. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  257. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  258. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  259. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  260. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  261. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  262. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  263. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  264. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  265. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  266. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  267. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  268. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  269. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  270. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  271. package/dist/web/standalone/.next/server/app/index.html +1 -1
  272. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  273. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  274. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  275. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  276. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  277. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  278. package/dist/web/standalone/.next/server/app/page.js +2 -2
  279. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  280. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  281. package/dist/web/standalone/.next/server/chunks/167.js +2 -0
  282. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  283. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  284. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  285. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  286. package/dist/web/standalone/.next/server/middleware.js +2 -2
  287. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  288. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  289. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  290. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  291. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  292. package/dist/web/standalone/.next/static/chunks/{8336.6f6f30e410419aff.js → 8336.631939fb583761fa.js} +1 -1
  293. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  294. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  295. package/dist/web/standalone/.next/static/chunks/app/page-fab3ebb85b006001.js +1 -0
  296. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  297. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  298. package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-0481f1221120a7c6.js} +1 -1
  299. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  300. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  301. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  302. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  303. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  304. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  305. package/dist/web/standalone/package.json +1 -0
  306. package/dist/web/standalone/server.js +1 -1
  307. package/package.json +18 -7
  308. package/packages/contracts/dist/index.d.ts +3 -0
  309. package/packages/contracts/dist/index.d.ts.map +1 -0
  310. package/packages/contracts/dist/index.js +5 -0
  311. package/packages/contracts/dist/index.js.map +1 -0
  312. package/packages/contracts/dist/rpc.d.ts +549 -0
  313. package/packages/contracts/dist/rpc.d.ts.map +1 -0
  314. package/packages/contracts/dist/rpc.js +53 -0
  315. package/packages/contracts/dist/rpc.js.map +1 -0
  316. package/packages/contracts/dist/rpc.test.d.ts +2 -0
  317. package/packages/contracts/dist/rpc.test.d.ts.map +1 -0
  318. package/packages/contracts/dist/rpc.test.js +47 -0
  319. package/packages/contracts/dist/rpc.test.js.map +1 -0
  320. package/packages/contracts/dist/workflow.d.ts +180 -0
  321. package/packages/contracts/dist/workflow.d.ts.map +1 -0
  322. package/packages/contracts/dist/workflow.js +201 -0
  323. package/packages/contracts/dist/workflow.js.map +1 -0
  324. package/packages/contracts/package.json +39 -0
  325. package/packages/contracts/src/index.ts +5 -0
  326. package/packages/contracts/src/rpc.test.ts +72 -0
  327. package/packages/contracts/src/rpc.ts +286 -0
  328. package/packages/contracts/src/workflow.ts +213 -0
  329. package/packages/contracts/tsconfig.json +25 -0
  330. package/packages/daemon/package.json +3 -2
  331. package/packages/daemon/src/event-bridge.test.ts +2 -1
  332. package/packages/daemon/src/event-bridge.ts +1 -1
  333. package/packages/daemon/src/event-formatter.test.ts +1 -2
  334. package/packages/daemon/src/event-formatter.ts +1 -2
  335. package/packages/daemon/src/session-manager.ts +2 -2
  336. package/packages/daemon/src/types.ts +3 -18
  337. package/packages/mcp-server/dist/server.d.ts +13 -0
  338. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  339. package/packages/mcp-server/dist/server.js +77 -0
  340. package/packages/mcp-server/dist/server.js.map +1 -1
  341. package/packages/mcp-server/dist/session-manager.js +1 -1
  342. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  343. package/packages/mcp-server/dist/types.d.ts +3 -11
  344. package/packages/mcp-server/dist/types.d.ts.map +1 -1
  345. package/packages/mcp-server/dist/types.js.map +1 -1
  346. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
  347. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  348. package/packages/mcp-server/dist/workflow-tools.js +52 -37
  349. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  350. package/packages/mcp-server/package.json +3 -2
  351. package/packages/mcp-server/src/mcp-server.test.ts +138 -0
  352. package/packages/mcp-server/src/server.ts +99 -1
  353. package/packages/mcp-server/src/session-manager.ts +2 -2
  354. package/packages/mcp-server/src/types.ts +7 -18
  355. package/packages/mcp-server/src/workflow-tools.test.ts +129 -2
  356. package/packages/mcp-server/src/workflow-tools.ts +80 -37
  357. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  358. package/packages/native/package.json +1 -1
  359. package/packages/pi-agent-core/package.json +1 -1
  360. package/packages/pi-ai/dist/models/fake-model.d.ts +12 -0
  361. package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
  362. package/packages/pi-ai/dist/models/fake-model.js +27 -0
  363. package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
  364. package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
  365. package/packages/pi-ai/dist/models/index.js +8 -0
  366. package/packages/pi-ai/dist/models/index.js.map +1 -1
  367. package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
  368. package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
  369. package/packages/pi-ai/dist/providers/fake.js +319 -0
  370. package/packages/pi-ai/dist/providers/fake.js.map +1 -0
  371. package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
  372. package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
  373. package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
  374. package/packages/pi-ai/package.json +1 -1
  375. package/packages/pi-ai/src/models/fake-model.ts +30 -0
  376. package/packages/pi-ai/src/models/index.ts +9 -0
  377. package/packages/pi-ai/src/providers/fake.ts +376 -0
  378. package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
  379. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  380. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +74 -0
  381. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  382. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -0
  383. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  384. package/packages/pi-coding-agent/dist/core/extensions/runner.js +14 -1
  385. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  386. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +97 -0
  387. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  388. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  389. package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
  390. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  391. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +4 -0
  392. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  393. package/packages/pi-coding-agent/dist/core/settings-manager.js +8 -0
  394. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  395. package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  396. package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
  397. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  398. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
  399. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
  400. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +67 -14
  401. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  402. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +26 -0
  403. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
  404. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +112 -0
  405. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
  406. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
  407. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
  408. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +51 -0
  409. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -0
  410. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  411. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  412. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  413. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
  414. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  415. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
  416. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  417. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
  418. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  419. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +27 -6
  420. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  421. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +16 -0
  422. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  423. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +112 -18
  424. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  425. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  426. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +60 -1
  427. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  428. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +40 -1
  429. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  430. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +1 -0
  431. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  432. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
  433. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  434. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  435. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +12 -1
  436. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  437. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +54 -10
  438. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  439. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
  440. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
  441. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  442. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
  443. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
  444. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
  445. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
  446. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  447. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  448. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
  449. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  450. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  451. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  452. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +18 -1
  453. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  454. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  455. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +36 -27
  456. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  457. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
  458. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
  459. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
  460. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
  461. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
  462. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
  463. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +48 -0
  464. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
  465. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +1 -512
  466. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  467. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js +3 -7
  468. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
  469. package/packages/pi-coding-agent/package.json +2 -1
  470. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +87 -0
  471. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +108 -0
  472. package/packages/pi-coding-agent/src/core/extensions/runner.ts +16 -1
  473. package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
  474. package/packages/pi-coding-agent/src/core/settings-manager.ts +12 -0
  475. package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
  476. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
  477. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +100 -16
  478. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +59 -0
  479. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +160 -0
  480. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +1 -0
  481. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
  482. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  483. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +41 -9
  484. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +124 -18
  485. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +43 -1
  486. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +75 -1
  487. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
  488. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
  489. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +75 -9
  490. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
  491. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
  492. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
  493. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +32 -2
  494. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +36 -27
  495. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +65 -0
  496. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -0
  497. package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +3 -336
  498. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  499. package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
  500. package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
  501. package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
  502. package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
  503. package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
  504. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  505. package/packages/pi-tui/dist/index.d.ts +1 -0
  506. package/packages/pi-tui/dist/index.d.ts.map +1 -1
  507. package/packages/pi-tui/dist/index.js +2 -0
  508. package/packages/pi-tui/dist/index.js.map +1 -1
  509. package/packages/pi-tui/dist/style.d.ts +41 -0
  510. package/packages/pi-tui/dist/style.d.ts.map +1 -0
  511. package/packages/pi-tui/dist/style.js +158 -0
  512. package/packages/pi-tui/dist/style.js.map +1 -0
  513. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  514. package/packages/pi-tui/dist/tui.js +1 -0
  515. package/packages/pi-tui/dist/tui.js.map +1 -1
  516. package/packages/pi-tui/package.json +1 -1
  517. package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
  518. package/packages/pi-tui/src/__tests__/tui.test.ts +29 -3
  519. package/packages/pi-tui/src/index.ts +9 -0
  520. package/packages/pi-tui/src/style.ts +225 -0
  521. package/packages/pi-tui/src/tui.ts +1 -0
  522. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  523. package/packages/rpc-client/README.md +3 -3
  524. package/packages/rpc-client/dist/index.d.ts +1 -1
  525. package/packages/rpc-client/dist/index.d.ts.map +1 -1
  526. package/packages/rpc-client/dist/index.js.map +1 -1
  527. package/packages/rpc-client/dist/rpc-client.d.ts +2 -6
  528. package/packages/rpc-client/dist/rpc-client.d.ts.map +1 -1
  529. package/packages/rpc-client/dist/rpc-client.js.map +1 -1
  530. package/packages/rpc-client/dist/rpc-types.d.ts +1 -565
  531. package/packages/rpc-client/dist/rpc-types.d.ts.map +1 -1
  532. package/packages/rpc-client/dist/rpc-types.js +3 -11
  533. package/packages/rpc-client/dist/rpc-types.js.map +1 -1
  534. package/packages/rpc-client/package.json +4 -1
  535. package/packages/rpc-client/src/index.ts +1 -1
  536. package/packages/rpc-client/src/rpc-client.ts +3 -6
  537. package/packages/rpc-client/src/rpc-types.ts +3 -398
  538. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  539. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  540. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  541. package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
  542. package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  543. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  544. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  545. package/pkg/dist/modes/interactive/theme/theme.js +18 -1
  546. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  547. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  548. package/pkg/dist/modes/interactive/theme/themes.js +36 -27
  549. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  550. package/pkg/package.json +1 -1
  551. package/src/resources/extensions/github-sync/templates.ts +93 -88
  552. package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
  553. package/src/resources/extensions/github-sync/tests/templates.test.ts +10 -2
  554. package/src/resources/extensions/gsd/auto/contracts.ts +87 -0
  555. package/src/resources/extensions/gsd/auto/custom-verify-retry-store.ts +72 -0
  556. package/src/resources/extensions/gsd/auto/loop-deps.ts +10 -3
  557. package/src/resources/extensions/gsd/auto/loop.ts +416 -596
  558. package/src/resources/extensions/gsd/auto/orchestrator.ts +161 -0
  559. package/src/resources/extensions/gsd/auto/phases.ts +88 -9
  560. package/src/resources/extensions/gsd/auto/run-unit.ts +24 -14
  561. package/src/resources/extensions/gsd/auto/session.ts +11 -0
  562. package/src/resources/extensions/gsd/auto/workflow-custom-engine-dispatch-outcome.ts +28 -0
  563. package/src/resources/extensions/gsd/auto/workflow-custom-engine-iteration.ts +52 -0
  564. package/src/resources/extensions/gsd/auto/workflow-custom-engine-reconcile-outcome.ts +58 -0
  565. package/src/resources/extensions/gsd/auto/workflow-custom-engine-reconcile.ts +71 -0
  566. package/src/resources/extensions/gsd/auto/workflow-custom-engine-retry.ts +90 -0
  567. package/src/resources/extensions/gsd/auto/workflow-custom-engine-verify-outcome.ts +50 -0
  568. package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +97 -0
  569. package/src/resources/extensions/gsd/auto/workflow-dispatch-ledger.ts +45 -0
  570. package/src/resources/extensions/gsd/auto/workflow-iteration-completion.ts +26 -0
  571. package/src/resources/extensions/gsd/auto/workflow-journal-reporter.ts +33 -0
  572. package/src/resources/extensions/gsd/auto/workflow-kernel.ts +520 -0
  573. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +58 -0
  574. package/src/resources/extensions/gsd/auto/workflow-phase-reporter.ts +22 -0
  575. package/src/resources/extensions/gsd/auto/workflow-session-lock.ts +68 -0
  576. package/src/resources/extensions/gsd/auto/workflow-sidecar-iteration.ts +46 -0
  577. package/src/resources/extensions/gsd/auto/workflow-sidecar-queue.ts +46 -0
  578. package/src/resources/extensions/gsd/auto/workflow-turn-reporter.ts +68 -0
  579. package/src/resources/extensions/gsd/auto/workflow-unit-dispatch.ts +89 -0
  580. package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +38 -0
  581. package/src/resources/extensions/gsd/auto-artifact-paths.ts +2 -2
  582. package/src/resources/extensions/gsd/auto-dashboard.ts +61 -8
  583. package/src/resources/extensions/gsd/auto-dispatch.ts +18 -0
  584. package/src/resources/extensions/gsd/auto-prompts.ts +276 -31
  585. package/src/resources/extensions/gsd/auto-recovery.ts +211 -59
  586. package/src/resources/extensions/gsd/auto-runtime-state.ts +7 -0
  587. package/src/resources/extensions/gsd/auto-start.ts +9 -7
  588. package/src/resources/extensions/gsd/auto-verification.ts +5 -1
  589. package/src/resources/extensions/gsd/auto-worktree.ts +85 -36
  590. package/src/resources/extensions/gsd/auto.ts +179 -2
  591. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +30 -2
  592. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +11 -0
  593. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -2
  594. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +79 -52
  595. package/src/resources/extensions/gsd/bootstrap/tests/write-gate-shouldblock-basepath.test.ts +97 -0
  596. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +143 -5
  597. package/src/resources/extensions/gsd/commands/context.ts +1 -1
  598. package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
  599. package/src/resources/extensions/gsd/commands-ship.ts +24 -51
  600. package/src/resources/extensions/gsd/commands-workflow-templates.ts +13 -0
  601. package/src/resources/extensions/gsd/component-loader.ts +5 -11
  602. package/src/resources/extensions/gsd/custom-workflow-engine.ts +29 -0
  603. package/src/resources/extensions/gsd/db-adapter.ts +75 -0
  604. package/src/resources/extensions/gsd/db-base-schema.ts +383 -0
  605. package/src/resources/extensions/gsd/db-connection-cache.ts +45 -0
  606. package/src/resources/extensions/gsd/db-coordination-schema.ts +109 -0
  607. package/src/resources/extensions/gsd/db-decision-requirement-rows.ts +77 -0
  608. package/src/resources/extensions/gsd/db-gate-rows.ts +19 -0
  609. package/src/resources/extensions/gsd/db-lightweight-query-rows.ts +50 -0
  610. package/src/resources/extensions/gsd/db-memory-fts-schema.ts +66 -0
  611. package/src/resources/extensions/gsd/db-migration-backup.ts +34 -0
  612. package/src/resources/extensions/gsd/db-migration-steps.ts +451 -0
  613. package/src/resources/extensions/gsd/db-milestone-artifact-rows.ts +70 -0
  614. package/src/resources/extensions/gsd/db-open-state.ts +47 -0
  615. package/src/resources/extensions/gsd/db-provider.ts +148 -0
  616. package/src/resources/extensions/gsd/db-runtime-kv-schema.ts +30 -0
  617. package/src/resources/extensions/gsd/db-schema-metadata.ts +33 -0
  618. package/src/resources/extensions/gsd/db-task-slice-rows.ts +146 -0
  619. package/src/resources/extensions/gsd/db-transaction.ts +76 -0
  620. package/src/resources/extensions/gsd/db-verification-evidence-rows.ts +14 -0
  621. package/src/resources/extensions/gsd/db-verification-evidence-schema.ts +22 -0
  622. package/src/resources/extensions/gsd/escalation.ts +3 -1
  623. package/src/resources/extensions/gsd/graph.ts +12 -5
  624. package/src/resources/extensions/gsd/gsd-db.ts +379 -1660
  625. package/src/resources/extensions/gsd/guided-flow.ts +49 -2
  626. package/src/resources/extensions/gsd/interrupted-session.ts +1 -0
  627. package/src/resources/extensions/gsd/legacy-telemetry.ts +99 -0
  628. package/src/resources/extensions/gsd/markdown-renderer.ts +4 -1
  629. package/src/resources/extensions/gsd/model-router.ts +10 -6
  630. package/src/resources/extensions/gsd/notification-widget.ts +25 -4
  631. package/src/resources/extensions/gsd/paths.ts +6 -1
  632. package/src/resources/extensions/gsd/post-execution-checks.ts +35 -7
  633. package/src/resources/extensions/gsd/pr-evidence.ts +182 -0
  634. package/src/resources/extensions/gsd/pre-execution-checks.ts +4 -1
  635. package/src/resources/extensions/gsd/preferences-types.ts +23 -4
  636. package/src/resources/extensions/gsd/preferences-validation.ts +3 -3
  637. package/src/resources/extensions/gsd/process-task-path.ts +81 -0
  638. package/src/resources/extensions/gsd/prompt-loader.ts +9 -5
  639. package/src/resources/extensions/gsd/prompts/complete-milestone.md +32 -30
  640. package/src/resources/extensions/gsd/prompts/complete-slice.md +23 -34
  641. package/src/resources/extensions/gsd/prompts/discuss-headless.md +50 -96
  642. package/src/resources/extensions/gsd/prompts/discuss.md +81 -181
  643. package/src/resources/extensions/gsd/prompts/execute-task.md +40 -67
  644. package/src/resources/extensions/gsd/prompts/forensics.md +41 -84
  645. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +29 -39
  646. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +30 -65
  647. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +25 -52
  648. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +36 -36
  649. package/src/resources/extensions/gsd/prompts/guided-research-project.md +20 -38
  650. package/src/resources/extensions/gsd/prompts/plan-milestone.md +45 -59
  651. package/src/resources/extensions/gsd/prompts/plan-slice.md +25 -87
  652. package/src/resources/extensions/gsd/prompts/queue.md +46 -53
  653. package/src/resources/extensions/gsd/prompts/refine-slice.md +23 -23
  654. package/src/resources/extensions/gsd/prompts/research-slice.md +23 -23
  655. package/src/resources/extensions/gsd/prompts/rethink.md +10 -10
  656. package/src/resources/extensions/gsd/prompts/system.md +65 -107
  657. package/src/resources/extensions/gsd/prompts/triage-captures.md +15 -15
  658. package/src/resources/extensions/gsd/prompts/validate-milestone.md +24 -24
  659. package/src/resources/extensions/gsd/prompts/worktree-merge.md +35 -35
  660. package/src/resources/extensions/gsd/state.ts +6 -3
  661. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +38 -0
  662. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +98 -0
  663. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +117 -0
  664. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +353 -0
  665. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +19 -0
  666. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +277 -1
  667. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +39 -0
  668. package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +3 -0
  669. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +2 -2
  670. package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +203 -0
  671. package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +148 -0
  672. package/src/resources/extensions/gsd/tests/commands-eval-review.test.ts +2 -2
  673. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
  674. package/src/resources/extensions/gsd/tests/commands-ship-eval-warn.test.ts +3 -2
  675. package/src/resources/extensions/gsd/tests/complete-milestone-prompt-rendering.test.ts +47 -0
  676. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +19 -5
  677. package/src/resources/extensions/gsd/tests/component-loader.test.ts +2 -9
  678. package/src/resources/extensions/gsd/tests/current-directory-root-homedir-fallback.test.ts +63 -0
  679. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +144 -0
  680. package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +139 -0
  681. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +50 -0
  682. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +3 -3
  683. package/src/resources/extensions/gsd/tests/db-adapter.test.ts +82 -0
  684. package/src/resources/extensions/gsd/tests/db-base-schema.test.ts +62 -0
  685. package/src/resources/extensions/gsd/tests/db-connection-cache.test.ts +60 -0
  686. package/src/resources/extensions/gsd/tests/db-coordination-schema.test.ts +39 -0
  687. package/src/resources/extensions/gsd/tests/db-decision-requirement-rows.test.ts +135 -0
  688. package/src/resources/extensions/gsd/tests/db-gate-rows.test.ts +53 -0
  689. package/src/resources/extensions/gsd/tests/db-lightweight-query-rows.test.ts +45 -0
  690. package/src/resources/extensions/gsd/tests/db-memory-fts-schema.test.ts +86 -0
  691. package/src/resources/extensions/gsd/tests/db-migration-backup.test.ts +105 -0
  692. package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
  693. package/src/resources/extensions/gsd/tests/db-migration-steps.test.ts +159 -0
  694. package/src/resources/extensions/gsd/tests/db-milestone-artifact-rows.test.ts +53 -0
  695. package/src/resources/extensions/gsd/tests/db-open-state.test.ts +56 -0
  696. package/src/resources/extensions/gsd/tests/db-provider.test.ts +105 -0
  697. package/src/resources/extensions/gsd/tests/db-runtime-kv-schema.test.ts +37 -0
  698. package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +115 -0
  699. package/src/resources/extensions/gsd/tests/db-task-slice-rows.test.ts +128 -0
  700. package/src/resources/extensions/gsd/tests/db-transaction.test.ts +110 -0
  701. package/src/resources/extensions/gsd/tests/db-verification-evidence-schema.test.ts +76 -0
  702. package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +42 -0
  703. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +63 -2
  704. package/src/resources/extensions/gsd/tests/discuss-headless-rendering.test.ts +37 -0
  705. package/src/resources/extensions/gsd/tests/execute-summary-save-empty-project.test.ts +109 -0
  706. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +59 -0
  707. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-basic.md +52 -0
  708. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
  709. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
  710. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
  711. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +36 -0
  712. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +10 -0
  713. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +139 -0
  714. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +43 -0
  715. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +41 -0
  716. package/src/resources/extensions/gsd/tests/guided-discuss-requirements-prompt-rendering.test.ts +45 -0
  717. package/src/resources/extensions/gsd/tests/guided-flow-prompt-consolidation.test.ts +14 -0
  718. package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
  719. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +79 -0
  720. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +37 -0
  721. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +5 -3
  722. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +134 -0
  723. package/src/resources/extensions/gsd/tests/legacy-component-format-telemetry.test.ts +62 -0
  724. package/src/resources/extensions/gsd/tests/legacy-telemetry.test.ts +144 -0
  725. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +40 -16
  726. package/src/resources/extensions/gsd/tests/model-router.test.ts +33 -12
  727. package/src/resources/extensions/gsd/tests/notification-store.test.ts +8 -0
  728. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +40 -1
  729. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +8 -0
  730. package/src/resources/extensions/gsd/tests/paused-session-via-db.test.ts +2 -0
  731. package/src/resources/extensions/gsd/tests/plan-milestone-rendering.test.ts +45 -0
  732. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +65 -16
  733. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +27 -0
  734. package/src/resources/extensions/gsd/tests/post-execution-checks.test.ts +46 -0
  735. package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
  736. package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
  737. package/src/resources/extensions/gsd/tests/pr-evidence.test.ts +79 -0
  738. package/src/resources/extensions/gsd/tests/pre-exec-gate-loop.test.ts +3 -0
  739. package/src/resources/extensions/gsd/tests/process-task-path.test.ts +51 -0
  740. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +16 -1
  741. package/src/resources/extensions/gsd/tests/queue-prompt-rendering.test.ts +37 -0
  742. package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +85 -0
  743. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +2 -0
  744. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +46 -2
  745. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +59 -0
  746. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +32 -9
  747. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +42 -4
  748. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +32 -0
  749. package/src/resources/extensions/gsd/tests/uok-contracts.test.ts +109 -1
  750. package/src/resources/extensions/gsd/tests/uok-kernel-path.test.ts +12 -0
  751. package/src/resources/extensions/gsd/tests/uok-loop-adapter-writer.test.ts +98 -0
  752. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
  753. package/src/resources/extensions/gsd/tests/workflow-custom-engine-dispatch-outcome.test.ts +55 -0
  754. package/src/resources/extensions/gsd/tests/workflow-custom-engine-iteration.test.ts +93 -0
  755. package/src/resources/extensions/gsd/tests/workflow-custom-engine-reconcile-outcome.test.ts +108 -0
  756. package/src/resources/extensions/gsd/tests/workflow-custom-engine-reconcile.test.ts +146 -0
  757. package/src/resources/extensions/gsd/tests/workflow-custom-engine-retry.test.ts +136 -0
  758. package/src/resources/extensions/gsd/tests/workflow-custom-engine-verify-outcome.test.ts +95 -0
  759. package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +158 -0
  760. package/src/resources/extensions/gsd/tests/workflow-dispatch-ledger.test.ts +82 -0
  761. package/src/resources/extensions/gsd/tests/workflow-iteration-completion.test.ts +44 -0
  762. package/src/resources/extensions/gsd/tests/workflow-journal-reporter.test.ts +49 -0
  763. package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +607 -0
  764. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +20 -4
  765. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +71 -0
  766. package/src/resources/extensions/gsd/tests/workflow-phase-reporter.test.ts +40 -0
  767. package/src/resources/extensions/gsd/tests/workflow-session-lock.test.ts +135 -0
  768. package/src/resources/extensions/gsd/tests/workflow-sidecar-iteration.test.ts +110 -0
  769. package/src/resources/extensions/gsd/tests/workflow-sidecar-queue.test.ts +116 -0
  770. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +21 -0
  771. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +164 -3
  772. package/src/resources/extensions/gsd/tests/workflow-turn-reporter.test.ts +87 -0
  773. package/src/resources/extensions/gsd/tests/workflow-unit-dispatch.test.ts +160 -0
  774. package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +123 -0
  775. package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
  776. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +3 -0
  777. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +17 -33
  778. package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +179 -0
  779. package/src/resources/extensions/gsd/tools/complete-milestone.ts +15 -9
  780. package/src/resources/extensions/gsd/tools/complete-task.ts +4 -1
  781. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +90 -2
  782. package/src/resources/extensions/gsd/unit-context-composer.ts +49 -0
  783. package/src/resources/extensions/gsd/unit-context-manifest.ts +34 -0
  784. package/src/resources/extensions/gsd/uok/audit.ts +25 -9
  785. package/src/resources/extensions/gsd/uok/contracts.ts +105 -0
  786. package/src/resources/extensions/gsd/uok/dispatch-envelope.ts +4 -0
  787. package/src/resources/extensions/gsd/uok/kernel.ts +10 -3
  788. package/src/resources/extensions/gsd/uok/loop-adapter.ts +60 -45
  789. package/src/resources/extensions/gsd/uok/plan-v2.ts +5 -1
  790. package/src/resources/extensions/gsd/uok/timeline.ts +158 -0
  791. package/src/resources/extensions/gsd/workflow-logger.ts +13 -13
  792. package/src/resources/extensions/gsd/workflow-manifest.ts +6 -15
  793. package/src/resources/extensions/gsd/workflow-projections.ts +5 -1
  794. package/src/resources/extensions/gsd/workflow-templates.ts +11 -0
  795. package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
  796. package/src/resources/extensions/shared/gsd-phase-state.ts +56 -3
  797. package/src/resources/extensions/shared/interview-ui.ts +18 -5
  798. package/src/resources/extensions/shared/tests/gsd-phase-state.test.ts +43 -1
  799. package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +41 -0
  800. package/dist/web/standalone/.next/server/chunks/6336.js +0 -1
  801. package/dist/web/standalone/.next/static/chunks/app/page-ff639266d978f2a0.js +0 -1
  802. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  803. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  804. /package/dist/web/standalone/.next/static/{J-CU-p_sp45CJHT3R9TJS → vIAZSyxIuvqNkCvXt9oqb}/_buildManifest.js +0 -0
  805. /package/dist/web/standalone/.next/static/{J-CU-p_sp45CJHT3R9TJS → vIAZSyxIuvqNkCvXt9oqb}/_ssgManifest.js +0 -0
@@ -1,3 +1,5 @@
1
+ // Project/App: GSD-2
2
+ // File Purpose: GSD database facade, schema, migrations, and single-writer write API.
1
3
  // GSD Database Abstraction Layer
2
4
  // Provides a SQLite database with provider fallback chain:
3
5
  // node:sqlite (built-in) → better-sqlite3 (npm) → null (unavailable)
@@ -25,264 +27,32 @@ import { dirname } from "node:path";
25
27
  import { GSDError, GSD_STALE_STATE } from "./errors.js";
26
28
  import { getGateIdsForTurn } from "./gate-registry.js";
27
29
  import { logError, logWarning } from "./workflow-logger.js";
30
+ import { createDbAdapter } from "./db-adapter.js";
31
+ import { createBaseSchemaObjects } from "./db-base-schema.js";
32
+ import { createCoordinationTablesV24 } from "./db-coordination-schema.js";
33
+ import { createDbConnectionCache } from "./db-connection-cache.js";
34
+ import { emptyTaskStatusCounts, rowToActiveTaskSummary, rowToIdStatusSummary, rowToTaskStatusCounts, rowsToStringColumn, } from "./db-lightweight-query-rows.js";
35
+ import { rowToActiveDecision, rowToActiveRequirement, rowToDecision, rowToRequirement, rowsToRequirementCounts, } from "./db-decision-requirement-rows.js";
36
+ import { rowToGate } from "./db-gate-rows.js";
37
+ import { rowToArtifact, rowToMilestone } from "./db-milestone-artifact-rows.js";
38
+ import { backupDatabaseBeforeMigration } from "./db-migration-backup.js";
39
+ import { applyMigrationV2Artifacts, applyMigrationV3Memories, applyMigrationV4DecisionMadeBy, applyMigrationV5HierarchyTables, applyMigrationV6SliceSummaries, applyMigrationV7Dependencies, applyMigrationV8PlanningFields, applyMigrationV9Ordering, applyMigrationV10ReplanTrigger, applyMigrationV11TaskPlanning, applyMigrationV12QualityGates, applyMigrationV13HotPathIndexes, applyMigrationV14SliceDependencies, applyMigrationV15AuditTables, applyMigrationV16EscalationSource, applyMigrationV17TaskEscalation, applyMigrationV18MemorySources, applyMigrationV19MemoryFts, applyMigrationV20MemoryRelations, applyMigrationV21StructuredMemories, applyMigrationV22QualityGateRepair, applyMigrationV23MilestoneQueue, applyMigrationV26MilestoneCommitAttributions, } from "./db-migration-steps.js";
40
+ import { isMemoriesFtsAvailableSchema, tryCreateMemoriesFtsSchema } from "./db-memory-fts-schema.js";
41
+ import { createDbOpenState } from "./db-open-state.js";
42
+ import { createRuntimeKvTableV25 } from "./db-runtime-kv-schema.js";
43
+ import { getCurrentSchemaVersion, recordSchemaVersion } from "./db-schema-metadata.js";
44
+ import { rowToSlice, rowToTask } from "./db-task-slice-rows.js";
45
+ import { createDbTransactionRunner } from "./db-transaction.js";
46
+ import { ensureVerificationEvidenceDedupIndex } from "./db-verification-evidence-schema.js";
47
+ import { createSqliteProviderLoader, suppressSqliteWarning } from "./db-provider.js";
28
48
  const _require = createRequire(import.meta.url);
29
- const BETTER_SQLITE3_PACKAGE = ["better", "sqlite3"].join("-");
30
- let providerName = null;
31
- let providerModule = null;
32
- let loadAttempted = false;
33
- function suppressSqliteWarning() {
34
- const origEmit = process.emit;
35
- // Override via loose cast: Node's overloaded emit signature is not directly assignable.
36
- process.emit = function (event, ...args) {
37
- if (event === "warning" &&
38
- args[0] &&
39
- typeof args[0] === "object" &&
40
- "name" in args[0] &&
41
- args[0].name === "ExperimentalWarning" &&
42
- "message" in args[0] &&
43
- typeof args[0].message === "string" &&
44
- args[0].message.includes("SQLite")) {
45
- return false;
46
- }
47
- return origEmit.apply(process, [event, ...args]);
48
- };
49
- }
50
- function loadProvider() {
51
- if (loadAttempted)
52
- return;
53
- loadAttempted = true;
54
- try {
55
- suppressSqliteWarning();
56
- const mod = _require("node:sqlite");
57
- if (mod.DatabaseSync) {
58
- providerModule = mod;
59
- providerName = "node:sqlite";
60
- return;
61
- }
62
- }
63
- catch {
64
- // unavailable
65
- }
66
- try {
67
- const mod = _require(BETTER_SQLITE3_PACKAGE);
68
- if (typeof mod === "function" || (mod && mod.default)) {
69
- providerModule = mod.default || mod;
70
- providerName = "better-sqlite3";
71
- return;
72
- }
73
- }
74
- catch {
75
- // unavailable
76
- }
77
- const nodeMajor = parseInt(process.versions.node.split(".")[0], 10);
78
- const versionHint = nodeMajor < 22
79
- ? ` GSD requires Node >= 22.0.0 (current: v${process.versions.node}). Upgrade Node to fix this.`
80
- : "";
81
- process.stderr.write(`gsd-db: No SQLite provider available (tried node:sqlite, better-sqlite3).${versionHint}\n`);
82
- }
83
- function normalizeRow(row) {
84
- if (row == null)
85
- return undefined;
86
- if (Object.getPrototypeOf(row) === null) {
87
- return { ...row };
88
- }
89
- return row;
90
- }
91
- function normalizeRows(rows) {
92
- return rows.map((r) => normalizeRow(r));
93
- }
94
- function createAdapter(rawDb) {
95
- const db = rawDb;
96
- const stmtCache = new Map();
97
- function wrapStmt(raw) {
98
- return {
99
- run(...params) {
100
- return raw.run(...params);
101
- },
102
- get(...params) {
103
- return normalizeRow(raw.get(...params));
104
- },
105
- all(...params) {
106
- return normalizeRows(raw.all(...params));
107
- },
108
- };
109
- }
110
- return {
111
- exec(sql) {
112
- db.exec(sql);
113
- },
114
- prepare(sql) {
115
- let cached = stmtCache.get(sql);
116
- if (cached)
117
- return cached;
118
- cached = wrapStmt(db.prepare(sql));
119
- stmtCache.set(sql, cached);
120
- return cached;
121
- },
122
- close() {
123
- stmtCache.clear();
124
- db.close();
125
- },
126
- };
127
- }
128
- function openRawDb(path) {
129
- loadProvider();
130
- if (!providerModule || !providerName)
131
- return null;
132
- if (providerName === "node:sqlite") {
133
- const { DatabaseSync } = providerModule;
134
- return new DatabaseSync(path);
135
- }
136
- const Database = providerModule;
137
- return new Database(path);
138
- }
139
- export const SCHEMA_VERSION = 25;
140
- function indexExists(db, name) {
141
- return !!db.prepare("SELECT 1 as present FROM sqlite_master WHERE type = 'index' AND name = ?").get(name);
142
- }
143
- /**
144
- * Create the v24 coordination tables (workers, milestone_leases,
145
- * unit_dispatches, cancellation_requests, command_queue) and their indexes.
146
- *
147
- * Idempotent — uses IF NOT EXISTS throughout. Called from both the
148
- * fresh-install path and the v24 migration block in migrateSchema().
149
- *
150
- * Single-host invariant: these tables coordinate concurrent auto-mode
151
- * workers via shared SQLite WAL on local disk only. NFS / network
152
- * filesystems break the coordination semantics — multi-host execution
153
- * needs a real coordinator (etcd, Postgres) and is out of scope.
154
- */
155
- function createCoordinationTablesV24(db) {
156
- const ddl = [
157
- `CREATE TABLE IF NOT EXISTS workers (
158
- worker_id TEXT PRIMARY KEY,
159
- host TEXT NOT NULL,
160
- pid INTEGER NOT NULL,
161
- started_at TEXT NOT NULL,
162
- version TEXT NOT NULL,
163
- last_heartbeat_at TEXT NOT NULL,
164
- status TEXT NOT NULL,
165
- project_root_realpath TEXT NOT NULL
166
- )`,
167
- `CREATE TABLE IF NOT EXISTS milestone_leases (
168
- milestone_id TEXT PRIMARY KEY,
169
- worker_id TEXT NOT NULL,
170
- fencing_token INTEGER NOT NULL,
171
- acquired_at TEXT NOT NULL,
172
- expires_at TEXT NOT NULL,
173
- status TEXT NOT NULL,
174
- FOREIGN KEY (worker_id) REFERENCES workers(worker_id),
175
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
176
- )`,
177
- `CREATE TABLE IF NOT EXISTS unit_dispatches (
178
- id INTEGER PRIMARY KEY AUTOINCREMENT,
179
- trace_id TEXT NOT NULL,
180
- turn_id TEXT,
181
- worker_id TEXT NOT NULL,
182
- milestone_lease_token INTEGER NOT NULL,
183
- milestone_id TEXT NOT NULL,
184
- slice_id TEXT,
185
- task_id TEXT,
186
- unit_type TEXT NOT NULL,
187
- unit_id TEXT NOT NULL,
188
- status TEXT NOT NULL,
189
- attempt_n INTEGER NOT NULL DEFAULT 1,
190
- started_at TEXT NOT NULL,
191
- ended_at TEXT,
192
- exit_reason TEXT,
193
- error_summary TEXT,
194
- verification_evidence_id INTEGER,
195
- next_run_at TEXT,
196
- retry_after_ms INTEGER,
197
- max_attempts INTEGER NOT NULL DEFAULT 3,
198
- last_error_code TEXT,
199
- last_error_at TEXT,
200
- FOREIGN KEY (worker_id) REFERENCES workers(worker_id),
201
- FOREIGN KEY (verification_evidence_id) REFERENCES verification_evidence(id)
202
- )`,
203
- `CREATE TABLE IF NOT EXISTS cancellation_requests (
204
- id INTEGER PRIMARY KEY AUTOINCREMENT,
205
- requested_at TEXT NOT NULL,
206
- requested_by TEXT NOT NULL,
207
- scope TEXT NOT NULL,
208
- scope_id TEXT NOT NULL,
209
- dispatch_id INTEGER,
210
- reason TEXT NOT NULL,
211
- status TEXT NOT NULL,
212
- acked_at TEXT,
213
- acked_worker_id TEXT,
214
- FOREIGN KEY (dispatch_id) REFERENCES unit_dispatches(id),
215
- FOREIGN KEY (acked_worker_id) REFERENCES workers(worker_id)
216
- )`,
217
- `CREATE TABLE IF NOT EXISTS command_queue (
218
- id INTEGER PRIMARY KEY AUTOINCREMENT,
219
- target_worker TEXT,
220
- command TEXT NOT NULL,
221
- args_json TEXT NOT NULL DEFAULT '{}',
222
- enqueued_at TEXT NOT NULL,
223
- claimed_at TEXT,
224
- claimed_by TEXT,
225
- completed_at TEXT,
226
- result_json TEXT
227
- )`,
228
- ];
229
- for (const stmt of ddl)
230
- db.exec(stmt);
231
- // Indexes — created here so both fresh-install and v24-migration paths
232
- // produce identical structure.
233
- db.exec("CREATE INDEX IF NOT EXISTS idx_unit_dispatches_active ON unit_dispatches(milestone_id, status)");
234
- db.exec("CREATE INDEX IF NOT EXISTS idx_unit_dispatches_trace ON unit_dispatches(trace_id, turn_id)");
235
- // Partial unique index — prevents two workers from claiming the same
236
- // unit concurrently. Codex review MEDIUM B2: enforces double-claim guard
237
- // at the DB level.
238
- db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_unit_dispatches_active_per_unit "
239
- + "ON unit_dispatches(unit_id) WHERE status IN ('claimed','running')");
240
- // command_queue index — SQLite indexes NULLs in B-trees, so this single
241
- // index serves both targeted (target_worker = ?) and broadcast
242
- // (target_worker IS NULL) queries. Codex review LOW B4 documented.
243
- db.exec("CREATE INDEX IF NOT EXISTS idx_command_queue_pending ON command_queue(target_worker, claimed_at)");
244
- }
245
- /**
246
- * Create the v25 runtime_kv table. Idempotent — uses IF NOT EXISTS.
247
- *
248
- * STRICT INVARIANT: runtime_kv is NON-CORRECTNESS-CRITICAL. UI cursors,
249
- * dashboard caches, last-seen-version markers, resume cursors, and other
250
- * "soft" state are OK. Anything that drives auto-mode control flow gets
251
- * typed columns in unit_dispatches / workers / milestone_leases — never
252
- * a bag of JSON in runtime_kv.
253
- *
254
- * Scope partitioning: ('global', '', key) for project-wide values;
255
- * ('worker', worker_id, key) for per-worker state (resume cursors);
256
- * ('milestone', milestone_id, key) for per-milestone soft state.
257
- */
258
- function createRuntimeKvTableV25(db) {
259
- db.exec(`
260
- CREATE TABLE IF NOT EXISTS runtime_kv (
261
- scope TEXT NOT NULL,
262
- scope_id TEXT NOT NULL DEFAULT '',
263
- key TEXT NOT NULL,
264
- value_json TEXT NOT NULL,
265
- updated_at TEXT NOT NULL,
266
- PRIMARY KEY (scope, scope_id, key)
267
- )
268
- `);
269
- }
270
- function dedupeVerificationEvidenceRows(db) {
271
- db.exec(`
272
- DELETE FROM verification_evidence
273
- WHERE rowid NOT IN (
274
- SELECT MIN(rowid)
275
- FROM verification_evidence
276
- GROUP BY task_id, slice_id, milestone_id, command, verdict
277
- )
278
- `);
279
- }
280
- function ensureVerificationEvidenceDedupIndex(db) {
281
- if (indexExists(db, "idx_verification_evidence_dedup"))
282
- return;
283
- dedupeVerificationEvidenceRows(db);
284
- db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_verification_evidence_dedup ON verification_evidence(task_id, slice_id, milestone_id, command, verdict)");
285
- }
49
+ const providerLoader = createSqliteProviderLoader({
50
+ requireModule: (id) => _require(id),
51
+ suppressSqliteWarning,
52
+ nodeVersion: process.versions.node,
53
+ writeStderr: (message) => process.stderr.write(message),
54
+ });
55
+ export const SCHEMA_VERSION = 26;
286
56
  function initSchema(db, fileBacked) {
287
57
  if (fileBacked)
288
58
  db.exec("PRAGMA journal_mode=WAL");
@@ -300,344 +70,10 @@ function initSchema(db, fileBacked) {
300
70
  db.exec("PRAGMA foreign_keys = ON");
301
71
  db.exec("BEGIN");
302
72
  try {
303
- db.exec(`
304
- CREATE TABLE IF NOT EXISTS schema_version (
305
- version INTEGER NOT NULL,
306
- applied_at TEXT NOT NULL
307
- )
308
- `);
309
- db.exec(`
310
- CREATE TABLE IF NOT EXISTS decisions (
311
- seq INTEGER PRIMARY KEY AUTOINCREMENT,
312
- id TEXT NOT NULL UNIQUE,
313
- when_context TEXT NOT NULL DEFAULT '',
314
- scope TEXT NOT NULL DEFAULT '',
315
- decision TEXT NOT NULL DEFAULT '',
316
- choice TEXT NOT NULL DEFAULT '',
317
- rationale TEXT NOT NULL DEFAULT '',
318
- revisable TEXT NOT NULL DEFAULT '',
319
- made_by TEXT NOT NULL DEFAULT 'agent',
320
- source TEXT NOT NULL DEFAULT 'discussion', -- ADR-011 P2: 'discussion' | 'planning' | 'escalation'
321
- superseded_by TEXT DEFAULT NULL
322
- )
323
- `);
324
- db.exec(`
325
- CREATE TABLE IF NOT EXISTS requirements (
326
- id TEXT PRIMARY KEY,
327
- class TEXT NOT NULL DEFAULT '',
328
- status TEXT NOT NULL DEFAULT '',
329
- description TEXT NOT NULL DEFAULT '',
330
- why TEXT NOT NULL DEFAULT '',
331
- source TEXT NOT NULL DEFAULT '',
332
- primary_owner TEXT NOT NULL DEFAULT '',
333
- supporting_slices TEXT NOT NULL DEFAULT '',
334
- validation TEXT NOT NULL DEFAULT '',
335
- notes TEXT NOT NULL DEFAULT '',
336
- full_content TEXT NOT NULL DEFAULT '',
337
- superseded_by TEXT DEFAULT NULL
338
- )
339
- `);
340
- db.exec(`
341
- CREATE TABLE IF NOT EXISTS artifacts (
342
- path TEXT PRIMARY KEY,
343
- artifact_type TEXT NOT NULL DEFAULT '',
344
- milestone_id TEXT DEFAULT NULL,
345
- slice_id TEXT DEFAULT NULL,
346
- task_id TEXT DEFAULT NULL,
347
- full_content TEXT NOT NULL DEFAULT '',
348
- imported_at TEXT NOT NULL DEFAULT ''
349
- )
350
- `);
351
- db.exec(`
352
- CREATE TABLE IF NOT EXISTS memories (
353
- seq INTEGER PRIMARY KEY AUTOINCREMENT,
354
- id TEXT NOT NULL UNIQUE,
355
- category TEXT NOT NULL,
356
- content TEXT NOT NULL,
357
- confidence REAL NOT NULL DEFAULT 0.8,
358
- source_unit_type TEXT,
359
- source_unit_id TEXT,
360
- created_at TEXT NOT NULL,
361
- updated_at TEXT NOT NULL,
362
- superseded_by TEXT DEFAULT NULL,
363
- hit_count INTEGER NOT NULL DEFAULT 0,
364
- scope TEXT NOT NULL DEFAULT 'project',
365
- tags TEXT NOT NULL DEFAULT '[]',
366
- structured_fields TEXT DEFAULT NULL
367
- )
368
- `);
369
- db.exec(`
370
- CREATE TABLE IF NOT EXISTS memory_processed_units (
371
- unit_key TEXT PRIMARY KEY,
372
- activity_file TEXT,
373
- processed_at TEXT NOT NULL
374
- )
375
- `);
376
- db.exec(`
377
- CREATE TABLE IF NOT EXISTS memory_sources (
378
- id TEXT PRIMARY KEY,
379
- kind TEXT NOT NULL,
380
- uri TEXT,
381
- title TEXT,
382
- content TEXT NOT NULL,
383
- content_hash TEXT NOT NULL UNIQUE,
384
- imported_at TEXT NOT NULL,
385
- scope TEXT NOT NULL DEFAULT 'project',
386
- tags TEXT NOT NULL DEFAULT '[]'
387
- )
388
- `);
389
- db.exec(`
390
- CREATE TABLE IF NOT EXISTS memory_embeddings (
391
- memory_id TEXT PRIMARY KEY,
392
- model TEXT NOT NULL,
393
- dim INTEGER NOT NULL,
394
- vector BLOB NOT NULL,
395
- updated_at TEXT NOT NULL
396
- )
397
- `);
398
- db.exec(`
399
- CREATE TABLE IF NOT EXISTS memory_relations (
400
- from_id TEXT NOT NULL,
401
- to_id TEXT NOT NULL,
402
- rel TEXT NOT NULL,
403
- confidence REAL NOT NULL DEFAULT 0.8,
404
- created_at TEXT NOT NULL,
405
- PRIMARY KEY (from_id, to_id, rel)
406
- )
407
- `);
408
- // FTS5 virtual table mirroring memories.content for fast keyword search.
409
- // Optional — if the SQLite build lacks FTS5, we fall back to LIKE scans.
410
- tryCreateMemoriesFts(db);
411
- db.exec(`
412
- CREATE TABLE IF NOT EXISTS milestones (
413
- id TEXT PRIMARY KEY,
414
- title TEXT NOT NULL DEFAULT '',
415
- status TEXT NOT NULL DEFAULT 'active',
416
- depends_on TEXT NOT NULL DEFAULT '[]',
417
- created_at TEXT NOT NULL DEFAULT '',
418
- completed_at TEXT DEFAULT NULL,
419
- vision TEXT NOT NULL DEFAULT '',
420
- success_criteria TEXT NOT NULL DEFAULT '[]',
421
- key_risks TEXT NOT NULL DEFAULT '[]',
422
- proof_strategy TEXT NOT NULL DEFAULT '[]',
423
- verification_contract TEXT NOT NULL DEFAULT '',
424
- verification_integration TEXT NOT NULL DEFAULT '',
425
- verification_operational TEXT NOT NULL DEFAULT '',
426
- verification_uat TEXT NOT NULL DEFAULT '',
427
- definition_of_done TEXT NOT NULL DEFAULT '[]',
428
- requirement_coverage TEXT NOT NULL DEFAULT '',
429
- boundary_map_markdown TEXT NOT NULL DEFAULT '',
430
- sequence INTEGER DEFAULT 0
431
- )
432
- `);
433
- db.exec(`
434
- CREATE TABLE IF NOT EXISTS slices (
435
- milestone_id TEXT NOT NULL,
436
- id TEXT NOT NULL,
437
- title TEXT NOT NULL DEFAULT '',
438
- status TEXT NOT NULL DEFAULT 'pending',
439
- risk TEXT NOT NULL DEFAULT 'medium',
440
- depends TEXT NOT NULL DEFAULT '[]',
441
- demo TEXT NOT NULL DEFAULT '',
442
- created_at TEXT NOT NULL DEFAULT '',
443
- completed_at TEXT DEFAULT NULL,
444
- full_summary_md TEXT NOT NULL DEFAULT '',
445
- full_uat_md TEXT NOT NULL DEFAULT '',
446
- goal TEXT NOT NULL DEFAULT '',
447
- success_criteria TEXT NOT NULL DEFAULT '',
448
- proof_level TEXT NOT NULL DEFAULT '',
449
- integration_closure TEXT NOT NULL DEFAULT '',
450
- observability_impact TEXT NOT NULL DEFAULT '',
451
- sequence INTEGER DEFAULT 0, -- Ordering hint: tools may set this to control execution order
452
- replan_triggered_at TEXT DEFAULT NULL,
453
- is_sketch INTEGER NOT NULL DEFAULT 0, -- ADR-011: 1 = slice is a sketch awaiting refinement
454
- sketch_scope TEXT NOT NULL DEFAULT '', -- ADR-011: 2-3 sentence rough scope from plan-milestone
455
- PRIMARY KEY (milestone_id, id),
456
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
457
- )
458
- `);
459
- db.exec(`
460
- CREATE TABLE IF NOT EXISTS tasks (
461
- milestone_id TEXT NOT NULL,
462
- slice_id TEXT NOT NULL,
463
- id TEXT NOT NULL,
464
- title TEXT NOT NULL DEFAULT '',
465
- status TEXT NOT NULL DEFAULT 'pending',
466
- one_liner TEXT NOT NULL DEFAULT '',
467
- narrative TEXT NOT NULL DEFAULT '',
468
- verification_result TEXT NOT NULL DEFAULT '',
469
- duration TEXT NOT NULL DEFAULT '',
470
- completed_at TEXT DEFAULT NULL,
471
- blocker_discovered INTEGER DEFAULT 0,
472
- blocker_source TEXT NOT NULL DEFAULT '', -- ADR-011 P2: provenance for blocker_discovered (e.g. 'reject-escalation')
473
- escalation_pending INTEGER NOT NULL DEFAULT 0, -- ADR-011 P2: pause-on-escalation flag
474
- escalation_awaiting_review INTEGER NOT NULL DEFAULT 0, -- ADR-011 P2: artifact exists but continueWithDefault=true (no pause)
475
- escalation_artifact_path TEXT DEFAULT NULL, -- ADR-011 P2: path to T##-ESCALATION.json
476
- escalation_override_applied_at TEXT DEFAULT NULL, -- ADR-011 P2: DB claim lock for idempotent override injection
477
- deviations TEXT NOT NULL DEFAULT '',
478
- known_issues TEXT NOT NULL DEFAULT '',
479
- key_files TEXT NOT NULL DEFAULT '[]',
480
- key_decisions TEXT NOT NULL DEFAULT '[]',
481
- full_summary_md TEXT NOT NULL DEFAULT '',
482
- description TEXT NOT NULL DEFAULT '',
483
- estimate TEXT NOT NULL DEFAULT '',
484
- files TEXT NOT NULL DEFAULT '[]',
485
- verify TEXT NOT NULL DEFAULT '',
486
- inputs TEXT NOT NULL DEFAULT '[]',
487
- expected_output TEXT NOT NULL DEFAULT '[]',
488
- observability_impact TEXT NOT NULL DEFAULT '',
489
- full_plan_md TEXT NOT NULL DEFAULT '',
490
- sequence INTEGER DEFAULT 0, -- Ordering hint: tools may set this to control execution order
491
- PRIMARY KEY (milestone_id, slice_id, id),
492
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
493
- )
494
- `);
495
- db.exec(`
496
- CREATE TABLE IF NOT EXISTS verification_evidence (
497
- id INTEGER PRIMARY KEY AUTOINCREMENT,
498
- task_id TEXT NOT NULL DEFAULT '',
499
- slice_id TEXT NOT NULL DEFAULT '',
500
- milestone_id TEXT NOT NULL DEFAULT '',
501
- command TEXT NOT NULL DEFAULT '',
502
- exit_code INTEGER DEFAULT 0,
503
- verdict TEXT NOT NULL DEFAULT '',
504
- duration_ms INTEGER DEFAULT 0,
505
- created_at TEXT NOT NULL DEFAULT '',
506
- FOREIGN KEY (milestone_id, slice_id, task_id) REFERENCES tasks(milestone_id, slice_id, id)
507
- )
508
- `);
509
- db.exec(`
510
- CREATE TABLE IF NOT EXISTS replan_history (
511
- id INTEGER PRIMARY KEY AUTOINCREMENT,
512
- milestone_id TEXT NOT NULL DEFAULT '',
513
- slice_id TEXT DEFAULT NULL,
514
- task_id TEXT DEFAULT NULL,
515
- summary TEXT NOT NULL DEFAULT '',
516
- previous_artifact_path TEXT DEFAULT NULL,
517
- replacement_artifact_path TEXT DEFAULT NULL,
518
- created_at TEXT NOT NULL DEFAULT '',
519
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
520
- )
521
- `);
522
- db.exec(`
523
- CREATE TABLE IF NOT EXISTS assessments (
524
- path TEXT PRIMARY KEY,
525
- milestone_id TEXT NOT NULL DEFAULT '',
526
- slice_id TEXT DEFAULT NULL,
527
- task_id TEXT DEFAULT NULL,
528
- status TEXT NOT NULL DEFAULT '',
529
- scope TEXT NOT NULL DEFAULT '',
530
- full_content TEXT NOT NULL DEFAULT '',
531
- created_at TEXT NOT NULL DEFAULT '',
532
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
533
- )
534
- `);
535
- db.exec(`
536
- CREATE TABLE IF NOT EXISTS quality_gates (
537
- milestone_id TEXT NOT NULL,
538
- slice_id TEXT NOT NULL,
539
- gate_id TEXT NOT NULL,
540
- scope TEXT NOT NULL DEFAULT 'slice',
541
- task_id TEXT NOT NULL DEFAULT '',
542
- status TEXT NOT NULL DEFAULT 'pending',
543
- verdict TEXT NOT NULL DEFAULT '',
544
- rationale TEXT NOT NULL DEFAULT '',
545
- findings TEXT NOT NULL DEFAULT '',
546
- evaluated_at TEXT DEFAULT NULL,
547
- PRIMARY KEY (milestone_id, slice_id, gate_id, task_id),
548
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
549
- )
550
- `);
551
- // Slice dependency junction table (v14)
552
- db.exec(`
553
- CREATE TABLE IF NOT EXISTS slice_dependencies (
554
- milestone_id TEXT NOT NULL,
555
- slice_id TEXT NOT NULL,
556
- depends_on_slice_id TEXT NOT NULL,
557
- PRIMARY KEY (milestone_id, slice_id, depends_on_slice_id),
558
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id),
559
- FOREIGN KEY (milestone_id, depends_on_slice_id) REFERENCES slices(milestone_id, id)
560
- )
561
- `);
562
- db.exec(`
563
- CREATE TABLE IF NOT EXISTS gate_runs (
564
- id INTEGER PRIMARY KEY AUTOINCREMENT,
565
- trace_id TEXT NOT NULL,
566
- turn_id TEXT NOT NULL,
567
- gate_id TEXT NOT NULL,
568
- gate_type TEXT NOT NULL DEFAULT '',
569
- unit_type TEXT DEFAULT NULL,
570
- unit_id TEXT DEFAULT NULL,
571
- milestone_id TEXT DEFAULT NULL,
572
- slice_id TEXT DEFAULT NULL,
573
- task_id TEXT DEFAULT NULL,
574
- outcome TEXT NOT NULL DEFAULT 'pass',
575
- failure_class TEXT NOT NULL DEFAULT 'none',
576
- rationale TEXT NOT NULL DEFAULT '',
577
- findings TEXT NOT NULL DEFAULT '',
578
- attempt INTEGER NOT NULL DEFAULT 1,
579
- max_attempts INTEGER NOT NULL DEFAULT 1,
580
- retryable INTEGER NOT NULL DEFAULT 0,
581
- evaluated_at TEXT NOT NULL DEFAULT ''
582
- )
583
- `);
584
- db.exec(`
585
- CREATE TABLE IF NOT EXISTS turn_git_transactions (
586
- trace_id TEXT NOT NULL,
587
- turn_id TEXT NOT NULL,
588
- unit_type TEXT DEFAULT NULL,
589
- unit_id TEXT DEFAULT NULL,
590
- stage TEXT NOT NULL DEFAULT 'turn-start',
591
- action TEXT NOT NULL DEFAULT 'status-only',
592
- push INTEGER NOT NULL DEFAULT 0,
593
- status TEXT NOT NULL DEFAULT 'ok',
594
- error TEXT DEFAULT NULL,
595
- metadata_json TEXT NOT NULL DEFAULT '{}',
596
- updated_at TEXT NOT NULL DEFAULT '',
597
- PRIMARY KEY (trace_id, turn_id, stage)
598
- )
599
- `);
600
- db.exec(`
601
- CREATE TABLE IF NOT EXISTS audit_events (
602
- event_id TEXT PRIMARY KEY,
603
- trace_id TEXT NOT NULL,
604
- turn_id TEXT DEFAULT NULL,
605
- caused_by TEXT DEFAULT NULL,
606
- category TEXT NOT NULL,
607
- type TEXT NOT NULL,
608
- ts TEXT NOT NULL,
609
- payload_json TEXT NOT NULL DEFAULT '{}'
610
- )
611
- `);
612
- db.exec(`
613
- CREATE TABLE IF NOT EXISTS audit_turn_index (
614
- trace_id TEXT NOT NULL,
615
- turn_id TEXT NOT NULL,
616
- first_ts TEXT NOT NULL,
617
- last_ts TEXT NOT NULL,
618
- event_count INTEGER NOT NULL DEFAULT 0,
619
- PRIMARY KEY (trace_id, turn_id)
620
- )
621
- `);
622
- db.exec("CREATE INDEX IF NOT EXISTS idx_memories_active ON memories(superseded_by)");
623
- db.exec("CREATE INDEX IF NOT EXISTS idx_replan_history_milestone ON replan_history(milestone_id, created_at)");
624
- // v13 indexes — hot-path dispatch queries
625
- db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_active ON tasks(milestone_id, slice_id, status)");
626
- db.exec("CREATE INDEX IF NOT EXISTS idx_slices_active ON slices(milestone_id, status)");
627
- db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
628
- db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
629
- db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
630
- ensureVerificationEvidenceDedupIndex(db);
631
- // v14 index — slice dependency lookups
632
- db.exec("CREATE INDEX IF NOT EXISTS idx_slice_deps_target ON slice_dependencies(milestone_id, depends_on_slice_id)");
633
- db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_turn ON gate_runs(trace_id, turn_id)");
634
- db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_lookup ON gate_runs(milestone_id, slice_id, task_id, gate_id)");
635
- db.exec("CREATE INDEX IF NOT EXISTS idx_turn_git_tx_turn ON turn_git_transactions(trace_id, turn_id)");
636
- db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_trace ON audit_events(trace_id, ts)");
637
- db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_turn ON audit_events(trace_id, turn_id, ts)");
638
- db.exec(`CREATE VIEW IF NOT EXISTS active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL`);
639
- db.exec(`CREATE VIEW IF NOT EXISTS active_requirements AS SELECT * FROM requirements WHERE superseded_by IS NULL`);
640
- db.exec(`CREATE VIEW IF NOT EXISTS active_memories AS SELECT * FROM memories WHERE superseded_by IS NULL`);
73
+ createBaseSchemaObjects(db, {
74
+ tryCreateMemoriesFts,
75
+ ensureVerificationEvidenceDedupIndex,
76
+ });
641
77
  const existing = db.prepare("SELECT count(*) as cnt FROM schema_version").get();
642
78
  if (existing && existing["cnt"] === 0) {
643
79
  createCoordinationTablesV24(db);
@@ -652,10 +88,7 @@ function initSchema(db, fileBacked) {
652
88
  db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_scope ON memory_sources(scope)");
653
89
  db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_from ON memory_relations(from_id)");
654
90
  db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_to ON memory_relations(to_id)");
655
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
656
- ":version": SCHEMA_VERSION,
657
- ":applied_at": new Date().toISOString(),
658
- });
91
+ recordSchemaVersion(db, SCHEMA_VERSION);
659
92
  }
660
93
  db.exec("COMMIT");
661
94
  }
@@ -665,10 +98,6 @@ function initSchema(db, fileBacked) {
665
98
  }
666
99
  migrateSchema(db);
667
100
  }
668
- function columnExists(db, table, column) {
669
- const rows = db.prepare(`PRAGMA table_info(${table})`).all();
670
- return rows.some((row) => row["name"] === column);
671
- }
672
101
  /**
673
102
  * Create the FTS5 virtual table for memories plus the triggers that keep it
674
103
  * in sync with the base table. FTS5 may be unavailable on stripped-down
@@ -676,304 +105,74 @@ function columnExists(db, table, column) {
676
105
  * to LIKE-based scans in `memory-store.queryMemoriesRanked`.
677
106
  */
678
107
  export function tryCreateMemoriesFts(db) {
679
- try {
680
- db.exec(`
681
- CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts
682
- USING fts5(content, content='memories', content_rowid='seq', tokenize='porter unicode61')
683
- `);
684
- // Triggers mirror inserts / updates / deletes on the base memories table.
685
- db.exec(`
686
- CREATE TRIGGER IF NOT EXISTS memories_ai
687
- AFTER INSERT ON memories BEGIN
688
- INSERT INTO memories_fts(rowid, content) VALUES (new.seq, new.content);
689
- END
690
- `);
691
- db.exec(`
692
- CREATE TRIGGER IF NOT EXISTS memories_ad
693
- AFTER DELETE ON memories BEGIN
694
- INSERT INTO memories_fts(memories_fts, rowid, content) VALUES ('delete', old.seq, old.content);
695
- END
696
- `);
697
- db.exec(`
698
- CREATE TRIGGER IF NOT EXISTS memories_au
699
- AFTER UPDATE OF content ON memories BEGIN
700
- INSERT INTO memories_fts(memories_fts, rowid, content) VALUES ('delete', old.seq, old.content);
701
- INSERT INTO memories_fts(rowid, content) VALUES (new.seq, new.content);
702
- END
703
- `);
704
- return true;
705
- }
706
- catch (err) {
707
- logWarning("db", `FTS5 unavailable — memory queries will use LIKE fallback: ${err.message}`);
708
- return false;
709
- }
108
+ return tryCreateMemoriesFtsSchema(db, {
109
+ onUnavailable: (message) => logWarning("db", message),
110
+ });
710
111
  }
711
112
  export function isMemoriesFtsAvailable(db) {
712
- try {
713
- const row = db
714
- .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='memories_fts'")
715
- .get();
716
- return !!row;
717
- }
718
- catch {
719
- return false;
720
- }
113
+ return isMemoriesFtsAvailableSchema(db);
721
114
  }
722
- function ensureColumn(db, table, column, ddl) {
723
- if (!columnExists(db, table, column))
724
- db.exec(ddl);
115
+ function backfillMemoriesFts(db) {
116
+ db.exec(`INSERT INTO memories_fts(rowid, content) SELECT seq, content FROM memories`);
117
+ }
118
+ function copyQualityGateRowsToRepairedTable(db) {
119
+ db.exec(`
120
+ INSERT OR IGNORE INTO quality_gates_new
121
+ (milestone_id, slice_id, gate_id, scope, task_id, status, verdict, rationale, findings, evaluated_at)
122
+ SELECT milestone_id, slice_id, gate_id, scope, COALESCE(task_id, ''), status, verdict, rationale, findings, evaluated_at
123
+ FROM quality_gates
124
+ `);
725
125
  }
726
126
  function migrateSchema(db) {
727
- const row = db.prepare("SELECT MAX(version) as v FROM schema_version").get();
728
- const currentVersion = row ? row["v"] : 0;
127
+ const currentVersion = getCurrentSchemaVersion(db);
729
128
  if (currentVersion >= SCHEMA_VERSION)
730
129
  return;
731
- // Backup database before migration so a mid-migration crash doesn't
732
- // leave a partially-migrated DB with no recovery path.
733
- // WAL-safe: checkpoint first to flush WAL into the main DB file, then copy.
734
- if (currentPath && currentPath !== ":memory:" && existsSync(currentPath)) {
735
- try {
736
- const backupPath = `${currentPath}.backup-v${currentVersion}`;
737
- if (!existsSync(backupPath)) {
738
- // Flush WAL to main DB file before copying — without this, the backup
739
- // may be missing committed data that only exists in the -wal file.
740
- try {
741
- db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
742
- }
743
- catch { /* checkpoint is best-effort */ }
744
- copyFileSync(currentPath, backupPath);
745
- }
746
- }
747
- catch (backupErr) {
748
- // Log but proceed — blocking migration leaves the DB stuck at an old
749
- // schema version permanently on read-only or full filesystems.
750
- logWarning("db", `Pre-migration backup failed: ${backupErr instanceof Error ? backupErr.message : String(backupErr)}`);
751
- }
752
- }
130
+ backupDatabaseBeforeMigration(db, currentPath, currentVersion, {
131
+ existsSync,
132
+ copyFileSync,
133
+ logWarning,
134
+ });
753
135
  db.exec("BEGIN");
754
136
  try {
755
137
  if (currentVersion < 2) {
756
- db.exec(`
757
- CREATE TABLE IF NOT EXISTS artifacts (
758
- path TEXT PRIMARY KEY,
759
- artifact_type TEXT NOT NULL DEFAULT '',
760
- milestone_id TEXT DEFAULT NULL,
761
- slice_id TEXT DEFAULT NULL,
762
- task_id TEXT DEFAULT NULL,
763
- full_content TEXT NOT NULL DEFAULT '',
764
- imported_at TEXT NOT NULL DEFAULT ''
765
- )
766
- `);
767
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
768
- ":version": 2,
769
- ":applied_at": new Date().toISOString(),
770
- });
138
+ applyMigrationV2Artifacts(db);
139
+ recordSchemaVersion(db, 2);
771
140
  }
772
141
  if (currentVersion < 3) {
773
- db.exec(`
774
- CREATE TABLE IF NOT EXISTS memories (
775
- seq INTEGER PRIMARY KEY AUTOINCREMENT,
776
- id TEXT NOT NULL UNIQUE,
777
- category TEXT NOT NULL,
778
- content TEXT NOT NULL,
779
- confidence REAL NOT NULL DEFAULT 0.8,
780
- source_unit_type TEXT,
781
- source_unit_id TEXT,
782
- created_at TEXT NOT NULL,
783
- updated_at TEXT NOT NULL,
784
- superseded_by TEXT DEFAULT NULL,
785
- hit_count INTEGER NOT NULL DEFAULT 0
786
- )
787
- `);
788
- db.exec(`
789
- CREATE TABLE IF NOT EXISTS memory_processed_units (
790
- unit_key TEXT PRIMARY KEY,
791
- activity_file TEXT,
792
- processed_at TEXT NOT NULL
793
- )
794
- `);
795
- db.exec("CREATE INDEX IF NOT EXISTS idx_memories_active ON memories(superseded_by)");
796
- db.exec("DROP VIEW IF EXISTS active_memories");
797
- db.exec("CREATE VIEW active_memories AS SELECT * FROM memories WHERE superseded_by IS NULL");
798
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
799
- ":version": 3,
800
- ":applied_at": new Date().toISOString(),
801
- });
142
+ applyMigrationV3Memories(db);
143
+ recordSchemaVersion(db, 3);
802
144
  }
803
145
  if (currentVersion < 4) {
804
- ensureColumn(db, "decisions", "made_by", `ALTER TABLE decisions ADD COLUMN made_by TEXT NOT NULL DEFAULT 'agent'`);
805
- db.exec("DROP VIEW IF EXISTS active_decisions");
806
- db.exec("CREATE VIEW active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL");
807
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
808
- ":version": 4,
809
- ":applied_at": new Date().toISOString(),
810
- });
146
+ applyMigrationV4DecisionMadeBy(db);
147
+ recordSchemaVersion(db, 4);
811
148
  }
812
149
  if (currentVersion < 5) {
813
- db.exec(`
814
- CREATE TABLE IF NOT EXISTS milestones (
815
- id TEXT PRIMARY KEY,
816
- title TEXT NOT NULL DEFAULT '',
817
- status TEXT NOT NULL DEFAULT 'active',
818
- created_at TEXT NOT NULL,
819
- completed_at TEXT DEFAULT NULL
820
- )
821
- `);
822
- db.exec(`
823
- CREATE TABLE IF NOT EXISTS slices (
824
- milestone_id TEXT NOT NULL,
825
- id TEXT NOT NULL,
826
- title TEXT NOT NULL DEFAULT '',
827
- status TEXT NOT NULL DEFAULT 'pending',
828
- risk TEXT NOT NULL DEFAULT 'medium',
829
- created_at TEXT NOT NULL DEFAULT '',
830
- completed_at TEXT DEFAULT NULL,
831
- PRIMARY KEY (milestone_id, id),
832
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
833
- )
834
- `);
835
- db.exec(`
836
- CREATE TABLE IF NOT EXISTS tasks (
837
- milestone_id TEXT NOT NULL,
838
- slice_id TEXT NOT NULL,
839
- id TEXT NOT NULL,
840
- title TEXT NOT NULL DEFAULT '',
841
- status TEXT NOT NULL DEFAULT 'pending',
842
- one_liner TEXT NOT NULL DEFAULT '',
843
- narrative TEXT NOT NULL DEFAULT '',
844
- verification_result TEXT NOT NULL DEFAULT '',
845
- duration TEXT NOT NULL DEFAULT '',
846
- completed_at TEXT DEFAULT NULL,
847
- blocker_discovered INTEGER DEFAULT 0,
848
- deviations TEXT NOT NULL DEFAULT '',
849
- known_issues TEXT NOT NULL DEFAULT '',
850
- key_files TEXT NOT NULL DEFAULT '[]',
851
- key_decisions TEXT NOT NULL DEFAULT '[]',
852
- full_summary_md TEXT NOT NULL DEFAULT '',
853
- PRIMARY KEY (milestone_id, slice_id, id),
854
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
855
- )
856
- `);
857
- db.exec(`
858
- CREATE TABLE IF NOT EXISTS verification_evidence (
859
- id INTEGER PRIMARY KEY AUTOINCREMENT,
860
- task_id TEXT NOT NULL DEFAULT '',
861
- slice_id TEXT NOT NULL DEFAULT '',
862
- milestone_id TEXT NOT NULL DEFAULT '',
863
- command TEXT NOT NULL DEFAULT '',
864
- exit_code INTEGER DEFAULT 0,
865
- verdict TEXT NOT NULL DEFAULT '',
866
- duration_ms INTEGER DEFAULT 0,
867
- created_at TEXT NOT NULL DEFAULT '',
868
- FOREIGN KEY (milestone_id, slice_id, task_id) REFERENCES tasks(milestone_id, slice_id, id)
869
- )
870
- `);
871
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
872
- ":version": 5,
873
- ":applied_at": new Date().toISOString(),
874
- });
150
+ applyMigrationV5HierarchyTables(db);
151
+ recordSchemaVersion(db, 5);
875
152
  }
876
153
  if (currentVersion < 6) {
877
- ensureColumn(db, "slices", "full_summary_md", `ALTER TABLE slices ADD COLUMN full_summary_md TEXT NOT NULL DEFAULT ''`);
878
- ensureColumn(db, "slices", "full_uat_md", `ALTER TABLE slices ADD COLUMN full_uat_md TEXT NOT NULL DEFAULT ''`);
879
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
880
- ":version": 6,
881
- ":applied_at": new Date().toISOString(),
882
- });
154
+ applyMigrationV6SliceSummaries(db);
155
+ recordSchemaVersion(db, 6);
883
156
  }
884
157
  if (currentVersion < 7) {
885
- ensureColumn(db, "slices", "depends", `ALTER TABLE slices ADD COLUMN depends TEXT NOT NULL DEFAULT '[]'`);
886
- ensureColumn(db, "slices", "demo", `ALTER TABLE slices ADD COLUMN demo TEXT NOT NULL DEFAULT ''`);
887
- ensureColumn(db, "milestones", "depends_on", `ALTER TABLE milestones ADD COLUMN depends_on TEXT NOT NULL DEFAULT '[]'`);
888
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
889
- ":version": 7,
890
- ":applied_at": new Date().toISOString(),
891
- });
158
+ applyMigrationV7Dependencies(db);
159
+ recordSchemaVersion(db, 7);
892
160
  }
893
161
  if (currentVersion < 8) {
894
- ensureColumn(db, "milestones", "vision", `ALTER TABLE milestones ADD COLUMN vision TEXT NOT NULL DEFAULT ''`);
895
- ensureColumn(db, "milestones", "success_criteria", `ALTER TABLE milestones ADD COLUMN success_criteria TEXT NOT NULL DEFAULT '[]'`);
896
- ensureColumn(db, "milestones", "key_risks", `ALTER TABLE milestones ADD COLUMN key_risks TEXT NOT NULL DEFAULT '[]'`);
897
- ensureColumn(db, "milestones", "proof_strategy", `ALTER TABLE milestones ADD COLUMN proof_strategy TEXT NOT NULL DEFAULT '[]'`);
898
- ensureColumn(db, "milestones", "verification_contract", `ALTER TABLE milestones ADD COLUMN verification_contract TEXT NOT NULL DEFAULT ''`);
899
- ensureColumn(db, "milestones", "verification_integration", `ALTER TABLE milestones ADD COLUMN verification_integration TEXT NOT NULL DEFAULT ''`);
900
- ensureColumn(db, "milestones", "verification_operational", `ALTER TABLE milestones ADD COLUMN verification_operational TEXT NOT NULL DEFAULT ''`);
901
- ensureColumn(db, "milestones", "verification_uat", `ALTER TABLE milestones ADD COLUMN verification_uat TEXT NOT NULL DEFAULT ''`);
902
- ensureColumn(db, "milestones", "definition_of_done", `ALTER TABLE milestones ADD COLUMN definition_of_done TEXT NOT NULL DEFAULT '[]'`);
903
- ensureColumn(db, "milestones", "requirement_coverage", `ALTER TABLE milestones ADD COLUMN requirement_coverage TEXT NOT NULL DEFAULT ''`);
904
- ensureColumn(db, "milestones", "boundary_map_markdown", `ALTER TABLE milestones ADD COLUMN boundary_map_markdown TEXT NOT NULL DEFAULT ''`);
905
- ensureColumn(db, "slices", "goal", `ALTER TABLE slices ADD COLUMN goal TEXT NOT NULL DEFAULT ''`);
906
- ensureColumn(db, "slices", "success_criteria", `ALTER TABLE slices ADD COLUMN success_criteria TEXT NOT NULL DEFAULT ''`);
907
- ensureColumn(db, "slices", "proof_level", `ALTER TABLE slices ADD COLUMN proof_level TEXT NOT NULL DEFAULT ''`);
908
- ensureColumn(db, "slices", "integration_closure", `ALTER TABLE slices ADD COLUMN integration_closure TEXT NOT NULL DEFAULT ''`);
909
- ensureColumn(db, "slices", "observability_impact", `ALTER TABLE slices ADD COLUMN observability_impact TEXT NOT NULL DEFAULT ''`);
910
- ensureColumn(db, "tasks", "description", `ALTER TABLE tasks ADD COLUMN description TEXT NOT NULL DEFAULT ''`);
911
- ensureColumn(db, "tasks", "estimate", `ALTER TABLE tasks ADD COLUMN estimate TEXT NOT NULL DEFAULT ''`);
912
- ensureColumn(db, "tasks", "files", `ALTER TABLE tasks ADD COLUMN files TEXT NOT NULL DEFAULT '[]'`);
913
- ensureColumn(db, "tasks", "verify", `ALTER TABLE tasks ADD COLUMN verify TEXT NOT NULL DEFAULT ''`);
914
- ensureColumn(db, "tasks", "inputs", `ALTER TABLE tasks ADD COLUMN inputs TEXT NOT NULL DEFAULT '[]'`);
915
- ensureColumn(db, "tasks", "expected_output", `ALTER TABLE tasks ADD COLUMN expected_output TEXT NOT NULL DEFAULT '[]'`);
916
- ensureColumn(db, "tasks", "observability_impact", `ALTER TABLE tasks ADD COLUMN observability_impact TEXT NOT NULL DEFAULT ''`);
917
- db.exec(`
918
- CREATE TABLE IF NOT EXISTS replan_history (
919
- id INTEGER PRIMARY KEY AUTOINCREMENT,
920
- milestone_id TEXT NOT NULL DEFAULT '',
921
- slice_id TEXT DEFAULT NULL,
922
- task_id TEXT DEFAULT NULL,
923
- summary TEXT NOT NULL DEFAULT '',
924
- previous_artifact_path TEXT DEFAULT NULL,
925
- replacement_artifact_path TEXT DEFAULT NULL,
926
- created_at TEXT NOT NULL DEFAULT '',
927
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
928
- )
929
- `);
930
- db.exec(`
931
- CREATE TABLE IF NOT EXISTS assessments (
932
- path TEXT PRIMARY KEY,
933
- milestone_id TEXT NOT NULL DEFAULT '',
934
- slice_id TEXT DEFAULT NULL,
935
- task_id TEXT DEFAULT NULL,
936
- status TEXT NOT NULL DEFAULT '',
937
- scope TEXT NOT NULL DEFAULT '',
938
- full_content TEXT NOT NULL DEFAULT '',
939
- created_at TEXT NOT NULL DEFAULT '',
940
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
941
- )
942
- `);
943
- db.exec("CREATE INDEX IF NOT EXISTS idx_replan_history_milestone ON replan_history(milestone_id, created_at)");
944
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
945
- ":version": 8,
946
- ":applied_at": new Date().toISOString(),
947
- });
162
+ applyMigrationV8PlanningFields(db);
163
+ recordSchemaVersion(db, 8);
948
164
  }
949
165
  if (currentVersion < 9) {
950
- ensureColumn(db, "slices", "sequence", `ALTER TABLE slices ADD COLUMN sequence INTEGER DEFAULT 0`);
951
- ensureColumn(db, "tasks", "sequence", `ALTER TABLE tasks ADD COLUMN sequence INTEGER DEFAULT 0`);
952
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
953
- ":version": 9,
954
- ":applied_at": new Date().toISOString(),
955
- });
166
+ applyMigrationV9Ordering(db);
167
+ recordSchemaVersion(db, 9);
956
168
  }
957
169
  if (currentVersion < 10) {
958
- ensureColumn(db, "slices", "replan_triggered_at", `ALTER TABLE slices ADD COLUMN replan_triggered_at TEXT DEFAULT NULL`);
959
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
960
- ":version": 10,
961
- ":applied_at": new Date().toISOString(),
962
- });
170
+ applyMigrationV10ReplanTrigger(db);
171
+ recordSchemaVersion(db, 10);
963
172
  }
964
173
  if (currentVersion < 11) {
965
- ensureColumn(db, "tasks", "full_plan_md", `ALTER TABLE tasks ADD COLUMN full_plan_md TEXT NOT NULL DEFAULT ''`);
966
- // Add unique constraint to replan_history for idempotency:
967
- // one replan record per blocker task per slice per milestone.
968
- db.exec(`
969
- CREATE UNIQUE INDEX IF NOT EXISTS idx_replan_history_unique
970
- ON replan_history(milestone_id, slice_id, task_id)
971
- WHERE slice_id IS NOT NULL AND task_id IS NOT NULL
972
- `);
973
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
974
- ":version": 11,
975
- ":applied_at": new Date().toISOString(),
976
- });
174
+ applyMigrationV11TaskPlanning(db);
175
+ recordSchemaVersion(db, 11);
977
176
  }
978
177
  if (currentVersion < 12) {
979
178
  // NOTE: The original DDL used COALESCE(task_id, '') in the PRIMARY KEY
@@ -981,295 +180,57 @@ function migrateSchema(db) {
981
180
  // DBs that migrate through v12. The corrected DDL uses
982
181
  // task_id TEXT NOT NULL DEFAULT '' with a plain column list PK. DBs that
983
182
  // were created with the broken DDL are repaired by the v22 migration below.
984
- db.exec(`
985
- CREATE TABLE IF NOT EXISTS quality_gates (
986
- milestone_id TEXT NOT NULL,
987
- slice_id TEXT NOT NULL,
988
- gate_id TEXT NOT NULL,
989
- scope TEXT NOT NULL DEFAULT 'slice',
990
- task_id TEXT NOT NULL DEFAULT '',
991
- status TEXT NOT NULL DEFAULT 'pending',
992
- verdict TEXT NOT NULL DEFAULT '',
993
- rationale TEXT NOT NULL DEFAULT '',
994
- findings TEXT NOT NULL DEFAULT '',
995
- evaluated_at TEXT DEFAULT NULL,
996
- PRIMARY KEY (milestone_id, slice_id, gate_id, task_id),
997
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
998
- )
999
- `);
1000
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1001
- ":version": 12,
1002
- ":applied_at": new Date().toISOString(),
1003
- });
183
+ applyMigrationV12QualityGates(db);
184
+ recordSchemaVersion(db, 12);
1004
185
  }
1005
186
  if (currentVersion < 13) {
1006
- // Hot-path indexes for auto-loop dispatch queries
1007
- db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_active ON tasks(milestone_id, slice_id, status)");
1008
- db.exec("CREATE INDEX IF NOT EXISTS idx_slices_active ON slices(milestone_id, status)");
1009
- db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
1010
- db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
1011
- db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
1012
- ensureVerificationEvidenceDedupIndex(db);
1013
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1014
- ":version": 13,
1015
- ":applied_at": new Date().toISOString(),
1016
- });
187
+ applyMigrationV13HotPathIndexes(db, ensureVerificationEvidenceDedupIndex);
188
+ recordSchemaVersion(db, 13);
1017
189
  }
1018
190
  if (currentVersion < 14) {
1019
- db.exec(`
1020
- CREATE TABLE IF NOT EXISTS slice_dependencies (
1021
- milestone_id TEXT NOT NULL,
1022
- slice_id TEXT NOT NULL,
1023
- depends_on_slice_id TEXT NOT NULL,
1024
- PRIMARY KEY (milestone_id, slice_id, depends_on_slice_id),
1025
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id),
1026
- FOREIGN KEY (milestone_id, depends_on_slice_id) REFERENCES slices(milestone_id, id)
1027
- )
1028
- `);
1029
- db.exec("CREATE INDEX IF NOT EXISTS idx_slice_deps_target ON slice_dependencies(milestone_id, depends_on_slice_id)");
1030
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1031
- ":version": 14,
1032
- ":applied_at": new Date().toISOString(),
1033
- });
191
+ applyMigrationV14SliceDependencies(db);
192
+ recordSchemaVersion(db, 14);
1034
193
  }
1035
194
  if (currentVersion < 15) {
1036
- db.exec(`
1037
- CREATE TABLE IF NOT EXISTS gate_runs (
1038
- id INTEGER PRIMARY KEY AUTOINCREMENT,
1039
- trace_id TEXT NOT NULL,
1040
- turn_id TEXT NOT NULL,
1041
- gate_id TEXT NOT NULL,
1042
- gate_type TEXT NOT NULL DEFAULT '',
1043
- unit_type TEXT DEFAULT NULL,
1044
- unit_id TEXT DEFAULT NULL,
1045
- milestone_id TEXT DEFAULT NULL,
1046
- slice_id TEXT DEFAULT NULL,
1047
- task_id TEXT DEFAULT NULL,
1048
- outcome TEXT NOT NULL DEFAULT 'pass',
1049
- failure_class TEXT NOT NULL DEFAULT 'none',
1050
- rationale TEXT NOT NULL DEFAULT '',
1051
- findings TEXT NOT NULL DEFAULT '',
1052
- attempt INTEGER NOT NULL DEFAULT 1,
1053
- max_attempts INTEGER NOT NULL DEFAULT 1,
1054
- retryable INTEGER NOT NULL DEFAULT 0,
1055
- evaluated_at TEXT NOT NULL DEFAULT ''
1056
- )
1057
- `);
1058
- db.exec(`
1059
- CREATE TABLE IF NOT EXISTS turn_git_transactions (
1060
- trace_id TEXT NOT NULL,
1061
- turn_id TEXT NOT NULL,
1062
- unit_type TEXT DEFAULT NULL,
1063
- unit_id TEXT DEFAULT NULL,
1064
- stage TEXT NOT NULL DEFAULT 'turn-start',
1065
- action TEXT NOT NULL DEFAULT 'status-only',
1066
- push INTEGER NOT NULL DEFAULT 0,
1067
- status TEXT NOT NULL DEFAULT 'ok',
1068
- error TEXT DEFAULT NULL,
1069
- metadata_json TEXT NOT NULL DEFAULT '{}',
1070
- updated_at TEXT NOT NULL DEFAULT '',
1071
- PRIMARY KEY (trace_id, turn_id, stage)
1072
- )
1073
- `);
1074
- db.exec(`
1075
- CREATE TABLE IF NOT EXISTS audit_events (
1076
- event_id TEXT PRIMARY KEY,
1077
- trace_id TEXT NOT NULL,
1078
- turn_id TEXT DEFAULT NULL,
1079
- caused_by TEXT DEFAULT NULL,
1080
- category TEXT NOT NULL,
1081
- type TEXT NOT NULL,
1082
- ts TEXT NOT NULL,
1083
- payload_json TEXT NOT NULL DEFAULT '{}'
1084
- )
1085
- `);
1086
- db.exec(`
1087
- CREATE TABLE IF NOT EXISTS audit_turn_index (
1088
- trace_id TEXT NOT NULL,
1089
- turn_id TEXT NOT NULL,
1090
- first_ts TEXT NOT NULL,
1091
- last_ts TEXT NOT NULL,
1092
- event_count INTEGER NOT NULL DEFAULT 0,
1093
- PRIMARY KEY (trace_id, turn_id)
1094
- )
1095
- `);
1096
- db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_turn ON gate_runs(trace_id, turn_id)");
1097
- db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_lookup ON gate_runs(milestone_id, slice_id, task_id, gate_id)");
1098
- db.exec("CREATE INDEX IF NOT EXISTS idx_turn_git_tx_turn ON turn_git_transactions(trace_id, turn_id)");
1099
- db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_trace ON audit_events(trace_id, ts)");
1100
- db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_turn ON audit_events(trace_id, turn_id, ts)");
1101
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1102
- ":version": 15,
1103
- ":applied_at": new Date().toISOString(),
1104
- });
195
+ applyMigrationV15AuditTables(db);
196
+ recordSchemaVersion(db, 15);
1105
197
  }
1106
198
  if (currentVersion < 16) {
1107
- // ADR-011 Phase 1: sketch-then-refine progressive planning — sketch columns on slices.
1108
- ensureColumn(db, "slices", "is_sketch", `ALTER TABLE slices ADD COLUMN is_sketch INTEGER NOT NULL DEFAULT 0`);
1109
- ensureColumn(db, "slices", "sketch_scope", `ALTER TABLE slices ADD COLUMN sketch_scope TEXT NOT NULL DEFAULT ''`);
1110
- // ADR-011 Phase 2: decisions can now be sourced from escalation resolutions.
1111
- ensureColumn(db, "decisions", "source", `ALTER TABLE decisions ADD COLUMN source TEXT NOT NULL DEFAULT 'discussion'`);
1112
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1113
- ":version": 16,
1114
- ":applied_at": new Date().toISOString(),
1115
- });
199
+ applyMigrationV16EscalationSource(db);
200
+ recordSchemaVersion(db, 16);
1116
201
  }
1117
202
  if (currentVersion < 17) {
1118
- // ADR-011 Phase 2: mid-execution escalation — columns on the tasks table.
1119
- ensureColumn(db, "tasks", "blocker_source", `ALTER TABLE tasks ADD COLUMN blocker_source TEXT NOT NULL DEFAULT ''`);
1120
- ensureColumn(db, "tasks", "escalation_pending", `ALTER TABLE tasks ADD COLUMN escalation_pending INTEGER NOT NULL DEFAULT 0`);
1121
- ensureColumn(db, "tasks", "escalation_awaiting_review", `ALTER TABLE tasks ADD COLUMN escalation_awaiting_review INTEGER NOT NULL DEFAULT 0`);
1122
- ensureColumn(db, "tasks", "escalation_artifact_path", `ALTER TABLE tasks ADD COLUMN escalation_artifact_path TEXT DEFAULT NULL`);
1123
- ensureColumn(db, "tasks", "escalation_override_applied_at", `ALTER TABLE tasks ADD COLUMN escalation_override_applied_at TEXT DEFAULT NULL`);
1124
- db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_escalation_pending ON tasks(milestone_id, slice_id, escalation_pending)");
1125
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1126
- ":version": 17,
1127
- ":applied_at": new Date().toISOString(),
1128
- });
203
+ applyMigrationV17TaskEscalation(db);
204
+ recordSchemaVersion(db, 17);
1129
205
  }
1130
206
  if (currentVersion < 18) {
1131
- // Memory system Phase 2: scope + tags on memories, plus memory_sources
1132
- // table for raw ingested content (notes, files, URLs, artifacts).
1133
- ensureColumn(db, "memories", "scope", `ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'project'`);
1134
- ensureColumn(db, "memories", "tags", `ALTER TABLE memories ADD COLUMN tags TEXT NOT NULL DEFAULT '[]'`);
1135
- db.exec(`
1136
- CREATE TABLE IF NOT EXISTS memory_sources (
1137
- id TEXT PRIMARY KEY,
1138
- kind TEXT NOT NULL,
1139
- uri TEXT,
1140
- title TEXT,
1141
- content TEXT NOT NULL,
1142
- content_hash TEXT NOT NULL UNIQUE,
1143
- imported_at TEXT NOT NULL,
1144
- scope TEXT NOT NULL DEFAULT 'project',
1145
- tags TEXT NOT NULL DEFAULT '[]'
1146
- )
1147
- `);
1148
- // If memory_sources already existed before v18 (created by an earlier
1149
- // version of initSchema that lacked scope/tags), add the missing columns.
1150
- ensureColumn(db, "memory_sources", "scope", `ALTER TABLE memory_sources ADD COLUMN scope TEXT NOT NULL DEFAULT 'project'`);
1151
- ensureColumn(db, "memory_sources", "tags", `ALTER TABLE memory_sources ADD COLUMN tags TEXT NOT NULL DEFAULT '[]'`);
1152
- db.exec("CREATE INDEX IF NOT EXISTS idx_memories_scope ON memories(scope)");
1153
- db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_kind ON memory_sources(kind)");
1154
- db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_scope ON memory_sources(scope)");
1155
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1156
- ":version": 18,
1157
- ":applied_at": new Date().toISOString(),
1158
- });
207
+ applyMigrationV18MemorySources(db);
208
+ recordSchemaVersion(db, 18);
1159
209
  }
1160
210
  if (currentVersion < 19) {
1161
- // Memory system Phase 3: embeddings + FTS5 for hybrid retrieval.
1162
- db.exec(`
1163
- CREATE TABLE IF NOT EXISTS memory_embeddings (
1164
- memory_id TEXT PRIMARY KEY,
1165
- model TEXT NOT NULL,
1166
- dim INTEGER NOT NULL,
1167
- vector BLOB NOT NULL,
1168
- updated_at TEXT NOT NULL
1169
- )
1170
- `);
1171
- tryCreateMemoriesFts(db);
1172
- // Backfill FTS5 with any existing memories (triggers only cover future writes).
1173
- if (isMemoriesFtsAvailable(db)) {
1174
- try {
1175
- db.exec(`INSERT INTO memories_fts(rowid, content) SELECT seq, content FROM memories`);
1176
- }
1177
- catch (err) {
1178
- logWarning("db", `FTS5 backfill failed: ${err.message}`);
1179
- }
1180
- }
1181
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1182
- ":version": 19,
1183
- ":applied_at": new Date().toISOString(),
211
+ applyMigrationV19MemoryFts(db, {
212
+ tryCreateMemoriesFts,
213
+ isMemoriesFtsAvailable,
214
+ backfillMemoriesFts,
215
+ logWarning,
1184
216
  });
217
+ recordSchemaVersion(db, 19);
1185
218
  }
1186
219
  if (currentVersion < 20) {
1187
- // Memory system Phase 4: knowledge-graph relations between memories.
1188
- db.exec(`
1189
- CREATE TABLE IF NOT EXISTS memory_relations (
1190
- from_id TEXT NOT NULL,
1191
- to_id TEXT NOT NULL,
1192
- rel TEXT NOT NULL,
1193
- confidence REAL NOT NULL DEFAULT 0.8,
1194
- created_at TEXT NOT NULL,
1195
- PRIMARY KEY (from_id, to_id, rel)
1196
- )
1197
- `);
1198
- db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_from ON memory_relations(from_id)");
1199
- db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_to ON memory_relations(to_id)");
1200
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1201
- ":version": 20,
1202
- ":applied_at": new Date().toISOString(),
1203
- });
220
+ applyMigrationV20MemoryRelations(db);
221
+ recordSchemaVersion(db, 20);
1204
222
  }
1205
223
  if (currentVersion < 21) {
1206
- // ADR-013 Step 2: preserve structured fields (gsd_save_decision's
1207
- // scope/decision/choice/rationale/made_by/revisable) on memories rows so
1208
- // the eventual decisions->memories cutover does not lose schema fidelity.
1209
- // Nullable JSON column — existing rows stay NULL until backfilled in Step 5.
1210
- // Use ensureColumn for race-safety (matches v15-v18 pattern; bare ALTER
1211
- // throws "duplicate column" on the loser of a concurrent open race even
1212
- // though the transaction wrapper protects the schema_version row).
1213
- ensureColumn(db, "memories", "structured_fields", "ALTER TABLE memories ADD COLUMN structured_fields TEXT DEFAULT NULL");
1214
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1215
- ":version": 21,
1216
- ":applied_at": new Date().toISOString(),
1217
- });
224
+ applyMigrationV21StructuredMemories(db);
225
+ recordSchemaVersion(db, 21);
1218
226
  }
1219
227
  if (currentVersion < 22) {
1220
- // v22: Repair quality_gates tables that were created by the broken v12
1221
- // migration (which used COALESCE(task_id, '') as a PK expression — invalid
1222
- // SQLite DDL). Those DBs have task_id nullable (dflt_value NULL, notnull 0).
1223
- // Rebuild the table with the correct schema, migrating existing rows via
1224
- // COALESCE so no data is lost.
1225
- const qgInfo = db.prepare("PRAGMA table_info(quality_gates)").all();
1226
- const taskIdCol = qgInfo.find((r) => r["name"] === "task_id");
1227
- const needsRepair = taskIdCol && (taskIdCol["notnull"] === 0 || taskIdCol["notnull"] === "0");
1228
- if (needsRepair) {
1229
- db.exec(`
1230
- CREATE TABLE quality_gates_new (
1231
- milestone_id TEXT NOT NULL,
1232
- slice_id TEXT NOT NULL,
1233
- gate_id TEXT NOT NULL,
1234
- scope TEXT NOT NULL DEFAULT 'slice',
1235
- task_id TEXT NOT NULL DEFAULT '',
1236
- status TEXT NOT NULL DEFAULT 'pending',
1237
- verdict TEXT NOT NULL DEFAULT '',
1238
- rationale TEXT NOT NULL DEFAULT '',
1239
- findings TEXT NOT NULL DEFAULT '',
1240
- evaluated_at TEXT DEFAULT NULL,
1241
- PRIMARY KEY (milestone_id, slice_id, gate_id, task_id),
1242
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
1243
- )
1244
- `);
1245
- db.exec(`
1246
- INSERT OR IGNORE INTO quality_gates_new
1247
- (milestone_id, slice_id, gate_id, scope, task_id, status, verdict, rationale, findings, evaluated_at)
1248
- SELECT milestone_id, slice_id, gate_id, scope, COALESCE(task_id, ''), status, verdict, rationale, findings, evaluated_at
1249
- FROM quality_gates
1250
- `);
1251
- db.exec("DROP TABLE quality_gates");
1252
- db.exec("ALTER TABLE quality_gates_new RENAME TO quality_gates");
1253
- db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
1254
- }
1255
- // Ensure scope column exists on quality_gates and assessments (guard
1256
- // against DBs that somehow lack it after a partial migration).
1257
- ensureColumn(db, "quality_gates", "scope", "ALTER TABLE quality_gates ADD COLUMN scope TEXT NOT NULL DEFAULT 'slice'");
1258
- ensureColumn(db, "assessments", "scope", "ALTER TABLE assessments ADD COLUMN scope TEXT NOT NULL DEFAULT ''");
1259
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1260
- ":version": 22,
1261
- ":applied_at": new Date().toISOString(),
1262
- });
228
+ applyMigrationV22QualityGateRepair(db, { copyQualityGateRowsToRepairedTable });
229
+ recordSchemaVersion(db, 22);
1263
230
  }
1264
231
  if (currentVersion < 23) {
1265
- // v23: milestone queue ordering moves into the canonical DB. The
1266
- // historical QUEUE-ORDER.json file remains a projection, but runtime
1267
- // derivation must not read it as authoritative state.
1268
- ensureColumn(db, "milestones", "sequence", "ALTER TABLE milestones ADD COLUMN sequence INTEGER DEFAULT 0");
1269
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1270
- ":version": 23,
1271
- ":applied_at": new Date().toISOString(),
1272
- });
232
+ applyMigrationV23MilestoneQueue(db);
233
+ recordSchemaVersion(db, 23);
1273
234
  }
1274
235
  if (currentVersion < 24) {
1275
236
  // v24: auto-mode coordination tables. See createCoordinationTablesV24
@@ -1277,19 +238,17 @@ function migrateSchema(db) {
1277
238
  // helper runs in the fresh-install path); for upgraded DBs this is
1278
239
  // the only place these tables get created.
1279
240
  createCoordinationTablesV24(db);
1280
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1281
- ":version": 24,
1282
- ":applied_at": new Date().toISOString(),
1283
- });
241
+ recordSchemaVersion(db, 24);
1284
242
  }
1285
243
  if (currentVersion < 25) {
1286
244
  // v25: runtime_kv non-correctness-critical key-value storage. See
1287
245
  // createRuntimeKvTableV25 for the full schema + invariants.
1288
246
  createRuntimeKvTableV25(db);
1289
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1290
- ":version": 25,
1291
- ":applied_at": new Date().toISOString(),
1292
- });
247
+ recordSchemaVersion(db, 25);
248
+ }
249
+ if (currentVersion < 26) {
250
+ applyMigrationV26MilestoneCommitAttributions(db);
251
+ recordSchemaVersion(db, 26);
1293
252
  }
1294
253
  db.exec("COMMIT");
1295
254
  }
@@ -1302,9 +261,7 @@ let currentDb = null;
1302
261
  let currentPath = null;
1303
262
  let currentPid = 0;
1304
263
  let _exitHandlerRegistered = false;
1305
- let _dbOpenAttempted = false;
1306
- let _lastDbError = null;
1307
- let _lastDbPhase = null;
264
+ const _dbOpenState = createDbOpenState();
1308
265
  /**
1309
266
  * Identity key of the workspace whose connection is currently active
1310
267
  * (currentDb). Set by openDatabaseByWorkspace(); null when the active
@@ -1324,10 +281,33 @@ let _currentIdentityKey = null;
1324
281
  * The cache allows fast re-activation of a previously opened connection when
1325
282
  * callers switch between known workspaces via openDatabaseByWorkspace().
1326
283
  */
1327
- const _dbCache = new Map();
284
+ const _dbCache = createDbConnectionCache();
1328
285
  /** Test helper: expose the internal cache for inspection. Not for production use. */
1329
286
  export function _getDbCache() {
1330
- return _dbCache;
287
+ return _dbCache.asReadonlyMap();
288
+ }
289
+ function closeCachedConnection(entry, source) {
290
+ try {
291
+ entry.db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
292
+ }
293
+ catch (e) {
294
+ if (source === "workspace")
295
+ logWarning("db", `WAL checkpoint (byWorkspace) failed: ${e.message}`);
296
+ }
297
+ try {
298
+ entry.db.exec("PRAGMA incremental_vacuum(64)");
299
+ }
300
+ catch (e) {
301
+ if (source === "workspace")
302
+ logWarning("db", `incremental vacuum (byWorkspace) failed: ${e.message}`);
303
+ }
304
+ try {
305
+ entry.db.close();
306
+ }
307
+ catch (e) {
308
+ if (source === "workspace")
309
+ logWarning("db", `database close (byWorkspace) failed: ${e.message}`);
310
+ }
1331
311
  }
1332
312
  /**
1333
313
  * Close and evict every entry in the workspace connection cache, then call
@@ -1339,23 +319,7 @@ export function _getDbCache() {
1339
319
  */
1340
320
  export function closeAllDatabases() {
1341
321
  // Close all non-active cached connections first.
1342
- for (const [key, entry] of _dbCache) {
1343
- if (entry.db === currentDb)
1344
- continue; // handled by closeDatabase() below
1345
- _dbCache.delete(key);
1346
- try {
1347
- entry.db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
1348
- }
1349
- catch { /* best-effort */ }
1350
- try {
1351
- entry.db.exec("PRAGMA incremental_vacuum(64)");
1352
- }
1353
- catch { /* best-effort */ }
1354
- try {
1355
- entry.db.close();
1356
- }
1357
- catch { /* best-effort */ }
1358
- }
322
+ _dbCache.closeNonActive(currentDb, (entry) => closeCachedConnection(entry, "all"));
1359
323
  closeDatabase();
1360
324
  }
1361
325
  /**
@@ -1383,7 +347,7 @@ export function openDatabaseByWorkspace(workspace) {
1383
347
  currentDb = cached.db;
1384
348
  currentPath = cached.dbPath;
1385
349
  currentPid = process.pid;
1386
- _dbOpenAttempted = true;
350
+ _dbOpenState.markAttempted();
1387
351
  _currentIdentityKey = key;
1388
352
  return true;
1389
353
  }
@@ -1472,29 +436,12 @@ export function closeDatabaseByWorkspace(workspace) {
1472
436
  }
1473
437
  else {
1474
438
  // Connection was displaced by a later open; close the adapter directly.
1475
- try {
1476
- cached.db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
1477
- }
1478
- catch (e) {
1479
- logWarning("db", `WAL checkpoint (byWorkspace) failed: ${e.message}`);
1480
- }
1481
- try {
1482
- cached.db.exec("PRAGMA incremental_vacuum(64)");
1483
- }
1484
- catch (e) {
1485
- logWarning("db", `incremental vacuum (byWorkspace) failed: ${e.message}`);
1486
- }
1487
- try {
1488
- cached.db.close();
1489
- }
1490
- catch (e) {
1491
- logWarning("db", `database close (byWorkspace) failed: ${e.message}`);
1492
- }
439
+ closeCachedConnection(cached, "workspace");
1493
440
  }
1494
441
  }
1495
442
  export function getDbProvider() {
1496
- loadProvider();
1497
- return providerName;
443
+ providerLoader.load();
444
+ return providerLoader.getProviderName();
1498
445
  }
1499
446
  export function isDbAvailable() {
1500
447
  return currentDb !== null;
@@ -1506,59 +453,46 @@ export function isDbAvailable() {
1506
453
  * trigger a false degraded-mode warning.
1507
454
  */
1508
455
  export function wasDbOpenAttempted() {
1509
- return _dbOpenAttempted;
456
+ return _dbOpenState.snapshot().attempted;
1510
457
  }
1511
458
  export function getDbStatus() {
1512
- loadProvider();
459
+ providerLoader.load();
460
+ const openState = _dbOpenState.snapshot();
1513
461
  return {
1514
462
  available: currentDb !== null,
1515
- provider: providerName,
1516
- attempted: _dbOpenAttempted,
1517
- lastError: _lastDbError,
1518
- lastPhase: _lastDbPhase,
463
+ provider: providerLoader.getProviderName(),
464
+ attempted: openState.attempted,
465
+ lastError: openState.lastError,
466
+ lastPhase: openState.lastPhase,
1519
467
  };
1520
468
  }
1521
469
  export function openDatabase(path) {
1522
- _dbOpenAttempted = true;
470
+ _dbOpenState.markAttempted();
1523
471
  if (currentDb && currentPath !== path)
1524
472
  closeDatabase();
1525
473
  if (currentDb && currentPath === path)
1526
474
  return true;
1527
475
  // Reset error state only when a new open attempt is actually going to run.
1528
- _lastDbError = null;
1529
- _lastDbPhase = null;
476
+ _dbOpenState.clearError();
1530
477
  let rawDb;
1531
- let fallbackProvider = null;
1532
- let fallbackModule = null;
478
+ let fallbackOpen = null;
1533
479
  try {
1534
- rawDb = openRawDb(path);
480
+ rawDb = providerLoader.openRaw(path);
1535
481
  }
1536
482
  catch (primaryErr) {
1537
- _lastDbPhase = "open";
1538
- _lastDbError = primaryErr instanceof Error ? primaryErr : new Error(String(primaryErr));
483
+ _dbOpenState.recordError("open", primaryErr);
1539
484
  // node:sqlite loaded but failed to open this file — try better-sqlite3 as fallback.
1540
- if (providerName === "node:sqlite") {
1541
- try {
1542
- const mod = _require(BETTER_SQLITE3_PACKAGE);
1543
- const Db = (mod && mod.default) ? mod.default : mod;
1544
- if (typeof Db === "function") {
1545
- rawDb = new Db(path);
1546
- fallbackProvider = "better-sqlite3";
1547
- fallbackModule = Db;
1548
- _lastDbError = null;
1549
- _lastDbPhase = null;
1550
- }
1551
- }
1552
- catch {
1553
- // fallback unavailable; surface original error
1554
- }
485
+ fallbackOpen = providerLoader.tryOpenBetterSqliteFallback(path);
486
+ if (fallbackOpen) {
487
+ rawDb = fallbackOpen.rawDb;
488
+ _dbOpenState.clearError();
1555
489
  }
1556
490
  if (!rawDb)
1557
491
  throw primaryErr;
1558
492
  }
1559
493
  if (!rawDb)
1560
494
  return false;
1561
- const adapter = createAdapter(rawDb);
495
+ const adapter = createDbAdapter(rawDb);
1562
496
  const fileBacked = path !== ":memory:";
1563
497
  try {
1564
498
  initSchema(adapter, fileBacked);
@@ -1573,8 +507,7 @@ export function openDatabase(path) {
1573
507
  process.stderr.write("gsd-db: recovered corrupt database via VACUUM\n");
1574
508
  }
1575
509
  catch (retryErr) {
1576
- _lastDbPhase = "vacuum-recovery";
1577
- _lastDbError = retryErr instanceof Error ? retryErr : new Error(String(retryErr));
510
+ _dbOpenState.recordError("vacuum-recovery", retryErr);
1578
511
  try {
1579
512
  adapter.close();
1580
513
  }
@@ -1585,8 +518,7 @@ export function openDatabase(path) {
1585
518
  }
1586
519
  }
1587
520
  else {
1588
- _lastDbPhase = "initSchema";
1589
- _lastDbError = err instanceof Error ? err : new Error(String(err));
521
+ _dbOpenState.recordError("initSchema", err);
1590
522
  try {
1591
523
  adapter.close();
1592
524
  }
@@ -1597,10 +529,8 @@ export function openDatabase(path) {
1597
529
  }
1598
530
  }
1599
531
  // Commit fallback provider switch only after open + schema both succeeded.
1600
- if (fallbackProvider) {
1601
- providerName = fallbackProvider;
1602
- providerModule = fallbackModule;
1603
- }
532
+ if (fallbackOpen)
533
+ providerLoader.commitFallback(fallbackOpen);
1604
534
  currentDb = adapter;
1605
535
  currentPath = path;
1606
536
  currentPid = process.pid;
@@ -1649,9 +579,36 @@ export function closeDatabase() {
1649
579
  }
1650
580
  // Reset session-scoped state unconditionally so stale error info from a
1651
581
  // failed open doesn't persist into the next open attempt or status check.
1652
- _dbOpenAttempted = false;
1653
- _lastDbError = null;
1654
- _lastDbPhase = null;
582
+ _dbOpenState.reset();
583
+ }
584
+ /**
585
+ * Re-open the active database connection from disk.
586
+ *
587
+ * Auto-mode can observe artifacts written by a workflow server running in a
588
+ * different process before its long-lived singleton has re-synchronized. The
589
+ * recovery path uses this to force the next state derivation to read from the
590
+ * current on-disk database instead of continuing with a possibly stale handle.
591
+ */
592
+ export function refreshOpenDatabaseFromDisk() {
593
+ if (!currentDb || !currentPath)
594
+ return false;
595
+ if (currentPath === ":memory:")
596
+ return false;
597
+ const dbPath = currentPath;
598
+ const identityKey = _currentIdentityKey;
599
+ try {
600
+ closeDatabase();
601
+ const opened = openDatabase(dbPath);
602
+ if (opened && identityKey && currentDb) {
603
+ _dbCache.set(identityKey, { dbPath, db: currentDb });
604
+ _currentIdentityKey = identityKey;
605
+ }
606
+ return opened;
607
+ }
608
+ catch (e) {
609
+ logWarning("db", `database refresh failed: ${e.message}`);
610
+ return false;
611
+ }
1655
612
  }
1656
613
  /** Run a full VACUUM — call sparingly (e.g. after milestone completion). */
1657
614
  export function vacuumDatabase() {
@@ -1675,7 +632,15 @@ export function checkpointDatabase() {
1675
632
  logWarning("db", `WAL checkpoint failed: ${e.message}`);
1676
633
  }
1677
634
  }
1678
- let _txDepth = 0;
635
+ const _transactionRunner = createDbTransactionRunner();
636
+ function createTransactionControls(db) {
637
+ return {
638
+ begin: () => db.exec("BEGIN"),
639
+ beginRead: () => db.exec("BEGIN DEFERRED"),
640
+ commit: () => db.exec("COMMIT"),
641
+ rollback: () => db.exec("ROLLBACK"),
642
+ };
643
+ }
1679
644
  /**
1680
645
  * Whether the current call is running inside an active SQLite transaction.
1681
646
  * Statement-time recovery paths (e.g. VACUUM retry on a malformed memory
@@ -1683,36 +648,12 @@ let _txDepth = 0;
1683
648
  * and would mask the original error with a secondary "cannot VACUUM" throw.
1684
649
  */
1685
650
  export function isInTransaction() {
1686
- return _txDepth > 0;
651
+ return _transactionRunner.isInTransaction();
1687
652
  }
1688
653
  export function transaction(fn) {
1689
654
  if (!currentDb)
1690
655
  throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1691
- // Re-entrant: if already inside a transaction, just run fn() without
1692
- // starting a new one. SQLite does not support nested BEGIN/COMMIT.
1693
- if (_txDepth > 0) {
1694
- _txDepth++;
1695
- try {
1696
- return fn();
1697
- }
1698
- finally {
1699
- _txDepth--;
1700
- }
1701
- }
1702
- currentDb.exec("BEGIN");
1703
- _txDepth++;
1704
- try {
1705
- const result = fn();
1706
- currentDb.exec("COMMIT");
1707
- return result;
1708
- }
1709
- catch (err) {
1710
- currentDb.exec("ROLLBACK");
1711
- throw err;
1712
- }
1713
- finally {
1714
- _txDepth--;
1715
- }
656
+ return _transactionRunner.transaction(createTransactionControls(currentDb), fn);
1716
657
  }
1717
658
  /**
1718
659
  * Wrap a block of reads in a DEFERRED transaction so that all SELECTs observe
@@ -1724,39 +665,14 @@ export function transaction(fn) {
1724
665
  export function readTransaction(fn) {
1725
666
  if (!currentDb)
1726
667
  throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1727
- if (_txDepth > 0) {
1728
- _txDepth++;
1729
- try {
1730
- return fn();
1731
- }
1732
- finally {
1733
- _txDepth--;
1734
- }
1735
- }
1736
- currentDb.exec("BEGIN DEFERRED");
1737
- _txDepth++;
1738
- try {
1739
- const result = fn();
1740
- currentDb.exec("COMMIT");
1741
- return result;
1742
- }
1743
- catch (err) {
1744
- try {
1745
- currentDb.exec("ROLLBACK");
1746
- }
1747
- catch (rollbackErr) {
1748
- // A failed ROLLBACK after a failed read is a split-brain signal —
1749
- // the transaction is in an indeterminate state. Surface it via the
1750
- // logger instead of swallowing it.
1751
- logError("db", "snapshotState ROLLBACK failed", {
1752
- error: rollbackErr.message,
1753
- });
1754
- }
1755
- throw err;
1756
- }
1757
- finally {
1758
- _txDepth--;
1759
- }
668
+ return _transactionRunner.readTransaction(createTransactionControls(currentDb), fn, (rollbackErr) => {
669
+ // A failed ROLLBACK after a failed read is a split-brain signal —
670
+ // the transaction is in an indeterminate state. Surface it via the
671
+ // logger instead of swallowing it.
672
+ logError("db", "snapshotState ROLLBACK failed", {
673
+ error: rollbackErr.message,
674
+ });
675
+ });
1760
676
  }
1761
677
  export function insertDecision(d) {
1762
678
  if (!currentDb)
@@ -1781,37 +697,13 @@ export function getDecisionById(id) {
1781
697
  const row = currentDb.prepare("SELECT * FROM decisions WHERE id = ?").get(id);
1782
698
  if (!row)
1783
699
  return null;
1784
- return {
1785
- seq: row["seq"],
1786
- id: row["id"],
1787
- when_context: row["when_context"],
1788
- scope: row["scope"],
1789
- decision: row["decision"],
1790
- choice: row["choice"],
1791
- rationale: row["rationale"],
1792
- revisable: row["revisable"],
1793
- made_by: row["made_by"] ?? "agent",
1794
- source: row["source"] ?? "discussion",
1795
- superseded_by: row["superseded_by"] ?? null,
1796
- };
700
+ return rowToDecision(row);
1797
701
  }
1798
702
  export function getActiveDecisions() {
1799
703
  if (!currentDb)
1800
704
  return [];
1801
705
  const rows = currentDb.prepare("SELECT * FROM active_decisions").all();
1802
- return rows.map((row) => ({
1803
- seq: row["seq"],
1804
- id: row["id"],
1805
- when_context: row["when_context"],
1806
- scope: row["scope"],
1807
- decision: row["decision"],
1808
- choice: row["choice"],
1809
- rationale: row["rationale"],
1810
- revisable: row["revisable"],
1811
- made_by: row["made_by"] ?? "agent",
1812
- source: row["source"] ?? "discussion",
1813
- superseded_by: null,
1814
- }));
706
+ return rows.map(rowToActiveDecision);
1815
707
  }
1816
708
  export function insertRequirement(r) {
1817
709
  if (!currentDb)
@@ -1838,39 +730,13 @@ export function getRequirementById(id) {
1838
730
  const row = currentDb.prepare("SELECT * FROM requirements WHERE id = ?").get(id);
1839
731
  if (!row)
1840
732
  return null;
1841
- return {
1842
- id: row["id"],
1843
- class: row["class"],
1844
- status: row["status"],
1845
- description: row["description"],
1846
- why: row["why"],
1847
- source: row["source"],
1848
- primary_owner: row["primary_owner"],
1849
- supporting_slices: row["supporting_slices"],
1850
- validation: row["validation"],
1851
- notes: row["notes"],
1852
- full_content: row["full_content"],
1853
- superseded_by: row["superseded_by"] ?? null,
1854
- };
733
+ return rowToRequirement(row);
1855
734
  }
1856
735
  export function getActiveRequirements() {
1857
736
  if (!currentDb)
1858
737
  return [];
1859
738
  const rows = currentDb.prepare("SELECT * FROM active_requirements").all();
1860
- return rows.map((row) => ({
1861
- id: row["id"],
1862
- class: row["class"],
1863
- status: row["status"],
1864
- description: row["description"],
1865
- why: row["why"],
1866
- source: row["source"],
1867
- primary_owner: row["primary_owner"],
1868
- supporting_slices: row["supporting_slices"],
1869
- validation: row["validation"],
1870
- notes: row["notes"],
1871
- full_content: row["full_content"],
1872
- superseded_by: null,
1873
- }));
739
+ return rows.map(rowToActiveRequirement);
1874
740
  }
1875
741
  export function getRequirementCounts() {
1876
742
  if (!currentDb) {
@@ -1879,23 +745,7 @@ export function getRequirementCounts() {
1879
745
  const rows = currentDb
1880
746
  .prepare("SELECT lower(status) as status, COUNT(*) as count FROM requirements GROUP BY lower(status)")
1881
747
  .all();
1882
- const counts = { active: 0, validated: 0, deferred: 0, outOfScope: 0, blocked: 0, total: 0 };
1883
- for (const row of rows) {
1884
- const status = String(row["status"] ?? "");
1885
- const count = Number(row["count"] ?? 0);
1886
- counts.total += count;
1887
- if (status === "active")
1888
- counts.active += count;
1889
- else if (status === "validated")
1890
- counts.validated += count;
1891
- else if (status === "deferred")
1892
- counts.deferred += count;
1893
- else if (status === "out-of-scope" || status === "out_of_scope")
1894
- counts.outOfScope += count;
1895
- else if (status === "blocked")
1896
- counts.blocked += count;
1897
- }
1898
- return counts;
748
+ return rowsToRequirementCounts(rows);
1899
749
  }
1900
750
  export function getDbOwnerPid() {
1901
751
  return currentPid;
@@ -1907,9 +757,7 @@ export function _getAdapter() {
1907
757
  return currentDb;
1908
758
  }
1909
759
  export function _resetProvider() {
1910
- loadAttempted = false;
1911
- providerModule = null;
1912
- providerName = null;
760
+ providerLoader.reset();
1913
761
  }
1914
762
  export function upsertDecision(d) {
1915
763
  if (!currentDb)
@@ -2271,30 +1119,6 @@ export function upsertTaskPlanning(milestoneId, sliceId, taskId, planning) {
2271
1119
  ":full_plan_md": planning.fullPlanMd ?? null,
2272
1120
  });
2273
1121
  }
2274
- function rowToSlice(row) {
2275
- return {
2276
- milestone_id: row["milestone_id"],
2277
- id: row["id"],
2278
- title: row["title"],
2279
- status: row["status"],
2280
- risk: row["risk"],
2281
- depends: JSON.parse(row["depends"] || "[]"),
2282
- demo: row["demo"] ?? "",
2283
- created_at: row["created_at"],
2284
- completed_at: row["completed_at"] ?? null,
2285
- full_summary_md: row["full_summary_md"] ?? "",
2286
- full_uat_md: row["full_uat_md"] ?? "",
2287
- goal: row["goal"] ?? "",
2288
- success_criteria: row["success_criteria"] ?? "",
2289
- proof_level: row["proof_level"] ?? "",
2290
- integration_closure: row["integration_closure"] ?? "",
2291
- observability_impact: row["observability_impact"] ?? "",
2292
- sequence: row["sequence"] ?? 0,
2293
- replan_triggered_at: row["replan_triggered_at"] ?? null,
2294
- is_sketch: row["is_sketch"] ?? 0,
2295
- sketch_scope: row["sketch_scope"] ?? "",
2296
- };
2297
- }
2298
1122
  export function getSlice(milestoneId, sliceId) {
2299
1123
  if (!currentDb)
2300
1124
  return null;
@@ -2324,82 +1148,6 @@ export function setSliceSummaryMd(milestoneId, sliceId, summaryMd, uatMd) {
2324
1148
  throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
2325
1149
  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 });
2326
1150
  }
2327
- function parseTaskArrayColumn(raw) {
2328
- if (typeof raw !== "string" || raw.trim() === "")
2329
- return [];
2330
- try {
2331
- const parsed = JSON.parse(raw);
2332
- if (Array.isArray(parsed))
2333
- return parsed.map((value) => String(value));
2334
- if (parsed === null || parsed === undefined || parsed === "")
2335
- return [];
2336
- return [String(parsed)];
2337
- }
2338
- catch {
2339
- // Older/corrupt rows may contain comma-separated strings instead of JSON.
2340
- return raw
2341
- .split(",")
2342
- .map((value) => value.trim())
2343
- .filter(Boolean);
2344
- }
2345
- }
2346
- function rowToTask(row) {
2347
- const parseTaskArray = (value) => {
2348
- if (Array.isArray(value)) {
2349
- return value.filter((entry) => typeof entry === "string");
2350
- }
2351
- if (typeof value !== "string")
2352
- return [];
2353
- const trimmed = value.trim();
2354
- if (!trimmed)
2355
- return [];
2356
- try {
2357
- const parsed = JSON.parse(trimmed);
2358
- if (Array.isArray(parsed)) {
2359
- return parsed.filter((entry) => typeof entry === "string");
2360
- }
2361
- if (typeof parsed === "string" && parsed.trim()) {
2362
- return [parsed.trim()];
2363
- }
2364
- }
2365
- catch {
2366
- // Older/corrupt DB rows may contain raw comma-separated paths instead of JSON arrays.
2367
- }
2368
- return trimmed.split(",").map((entry) => entry.trim()).filter(Boolean);
2369
- };
2370
- return {
2371
- milestone_id: row["milestone_id"],
2372
- slice_id: row["slice_id"],
2373
- id: row["id"],
2374
- title: row["title"],
2375
- status: row["status"],
2376
- one_liner: row["one_liner"],
2377
- narrative: row["narrative"],
2378
- verification_result: row["verification_result"],
2379
- duration: row["duration"],
2380
- completed_at: row["completed_at"] ?? null,
2381
- blocker_discovered: row["blocker_discovered"] === 1,
2382
- deviations: row["deviations"],
2383
- known_issues: row["known_issues"],
2384
- key_files: parseTaskArrayColumn(row["key_files"]),
2385
- key_decisions: parseTaskArrayColumn(row["key_decisions"]),
2386
- full_summary_md: row["full_summary_md"],
2387
- description: row["description"] ?? "",
2388
- estimate: row["estimate"] ?? "",
2389
- files: parseTaskArray(row["files"]),
2390
- verify: row["verify"] ?? "",
2391
- inputs: parseTaskArray(row["inputs"]),
2392
- expected_output: parseTaskArray(row["expected_output"]),
2393
- observability_impact: row["observability_impact"] ?? "",
2394
- full_plan_md: row["full_plan_md"] ?? "",
2395
- sequence: row["sequence"] ?? 0,
2396
- blocker_source: row["blocker_source"] ?? "",
2397
- escalation_pending: row["escalation_pending"] ?? 0,
2398
- escalation_awaiting_review: row["escalation_awaiting_review"] ?? 0,
2399
- escalation_artifact_path: row["escalation_artifact_path"] ?? null,
2400
- escalation_override_applied_at: row["escalation_override_applied_at"] ?? null,
2401
- };
2402
- }
2403
1151
  export function getTask(milestoneId, sliceId, taskId) {
2404
1152
  if (!currentDb)
2405
1153
  return null;
@@ -2414,6 +1162,47 @@ export function getSliceTasks(milestoneId, sliceId) {
2414
1162
  const rows = currentDb.prepare("SELECT * FROM tasks WHERE milestone_id = :mid AND slice_id = :sid ORDER BY sequence, id").all({ ":mid": milestoneId, ":sid": sliceId });
2415
1163
  return rows.map(rowToTask);
2416
1164
  }
1165
+ export function getCompletedMilestoneTaskFileHints(milestoneId) {
1166
+ if (!currentDb)
1167
+ return [];
1168
+ const rows = currentDb.prepare(`SELECT files, key_files
1169
+ FROM tasks
1170
+ WHERE milestone_id = :mid AND status IN ('complete', 'done')`).all({ ":mid": milestoneId });
1171
+ const hints = new Set();
1172
+ for (const row of rows) {
1173
+ for (const raw of [row["files"], row["key_files"]]) {
1174
+ for (const file of parseStringArrayColumn(raw)) {
1175
+ const normalized = normalizeRepoPath(file);
1176
+ if (normalized)
1177
+ hints.add(normalized);
1178
+ }
1179
+ }
1180
+ }
1181
+ return [...hints];
1182
+ }
1183
+ function parseStringArrayColumn(raw) {
1184
+ if (Array.isArray(raw))
1185
+ return raw.filter((entry) => typeof entry === "string");
1186
+ if (typeof raw !== "string")
1187
+ return [];
1188
+ const trimmed = raw.trim();
1189
+ if (!trimmed)
1190
+ return [];
1191
+ try {
1192
+ const parsed = JSON.parse(trimmed);
1193
+ if (Array.isArray(parsed))
1194
+ return parsed.filter((entry) => typeof entry === "string");
1195
+ if (typeof parsed === "string")
1196
+ return [parsed];
1197
+ }
1198
+ catch {
1199
+ return trimmed.split(",");
1200
+ }
1201
+ return [];
1202
+ }
1203
+ function normalizeRepoPath(file) {
1204
+ return file.trim().replace(/\\/g, "/").replace(/^\.\/+/, "");
1205
+ }
2417
1206
  // ─── ADR-011 Phase 2 escalation helpers ──────────────────────────────────
2418
1207
  /** Set pause-on-escalation state on a completed task. Mutually exclusive with awaiting_review. */
2419
1208
  export function setTaskEscalationPending(milestoneId, sliceId, taskId, artifactPath) {
@@ -2524,39 +1313,6 @@ export function getVerificationEvidence(milestoneId, sliceId, taskId) {
2524
1313
  const rows = currentDb.prepare("SELECT * FROM verification_evidence WHERE milestone_id = :mid AND slice_id = :sid AND task_id = :tid ORDER BY id").all({ ":mid": milestoneId, ":sid": sliceId, ":tid": taskId });
2525
1314
  return rows;
2526
1315
  }
2527
- function rowToMilestone(row) {
2528
- return {
2529
- id: row["id"],
2530
- title: row["title"],
2531
- status: row["status"],
2532
- depends_on: JSON.parse(row["depends_on"] || "[]"),
2533
- created_at: row["created_at"],
2534
- completed_at: row["completed_at"] ?? null,
2535
- vision: row["vision"] ?? "",
2536
- success_criteria: JSON.parse(row["success_criteria"] || "[]"),
2537
- key_risks: JSON.parse(row["key_risks"] || "[]"),
2538
- proof_strategy: JSON.parse(row["proof_strategy"] || "[]"),
2539
- verification_contract: row["verification_contract"] ?? "",
2540
- verification_integration: row["verification_integration"] ?? "",
2541
- verification_operational: row["verification_operational"] ?? "",
2542
- verification_uat: row["verification_uat"] ?? "",
2543
- definition_of_done: JSON.parse(row["definition_of_done"] || "[]"),
2544
- requirement_coverage: row["requirement_coverage"] ?? "",
2545
- boundary_map_markdown: row["boundary_map_markdown"] ?? "",
2546
- sequence: Number(row["sequence"] ?? 0),
2547
- };
2548
- }
2549
- function rowToArtifact(row) {
2550
- return {
2551
- path: row["path"],
2552
- artifact_type: row["artifact_type"],
2553
- milestone_id: row["milestone_id"] ?? null,
2554
- slice_id: row["slice_id"] ?? null,
2555
- task_id: row["task_id"] ?? null,
2556
- full_content: row["full_content"],
2557
- imported_at: row["imported_at"],
2558
- };
2559
- }
2560
1316
  export function getAllMilestones() {
2561
1317
  if (!currentDb)
2562
1318
  return [];
@@ -2656,13 +1412,13 @@ export function getActiveMilestoneIdFromDb() {
2656
1412
  const row = currentDb.prepare("SELECT id, status FROM milestones WHERE status NOT IN ('complete', 'parked') ORDER BY id LIMIT 1").get();
2657
1413
  if (!row)
2658
1414
  return null;
2659
- return { id: row["id"], status: row["status"] };
1415
+ return rowToIdStatusSummary(row);
2660
1416
  }
2661
1417
  /** Fast slice status check — avoids deserializing JSON depends/planning fields. */
2662
1418
  export function getSliceStatusSummary(milestoneId) {
2663
1419
  if (!currentDb)
2664
1420
  return [];
2665
- 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"] }));
1421
+ return currentDb.prepare("SELECT id, status FROM slices WHERE milestone_id = :mid ORDER BY sequence, id").all({ ":mid": milestoneId }).map(rowToIdStatusSummary);
2666
1422
  }
2667
1423
  /** Fast task status check — avoids deserializing JSON arrays and large text fields. */
2668
1424
  export function getActiveTaskIdFromDb(milestoneId, sliceId) {
@@ -2671,20 +1427,18 @@ export function getActiveTaskIdFromDb(milestoneId, sliceId) {
2671
1427
  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 });
2672
1428
  if (!row)
2673
1429
  return null;
2674
- return { id: row["id"], status: row["status"], title: row["title"] };
1430
+ return rowToActiveTaskSummary(row);
2675
1431
  }
2676
1432
  /** Count tasks by status for a slice — useful for progress reporting without full row load. */
2677
1433
  export function getSliceTaskCounts(milestoneId, sliceId) {
2678
1434
  if (!currentDb)
2679
- return { total: 0, done: 0, pending: 0 };
1435
+ return emptyTaskStatusCounts();
2680
1436
  const row = currentDb.prepare(`SELECT
2681
1437
  COUNT(*) as total,
2682
1438
  SUM(CASE WHEN status IN ('complete', 'done') THEN 1 ELSE 0 END) as done,
2683
1439
  SUM(CASE WHEN status NOT IN ('complete', 'done') THEN 1 ELSE 0 END) as pending
2684
1440
  FROM tasks WHERE milestone_id = :mid AND slice_id = :sid`).get({ ":mid": milestoneId, ":sid": sliceId });
2685
- if (!row)
2686
- return { total: 0, done: 0, pending: 0 };
2687
- return { total: row["total"] ?? 0, done: row["done"] ?? 0, pending: row["pending"] ?? 0 };
1441
+ return rowToTaskStatusCounts(row);
2688
1442
  }
2689
1443
  // ─── Slice Dependencies (junction table) ─────────────────────────────────
2690
1444
  /** Sync the slice_dependencies junction table from a slice's JSON depends array. */
@@ -2700,7 +1454,8 @@ export function syncSliceDependencies(milestoneId, sliceId, depends) {
2700
1454
  export function getDependentSlices(milestoneId, sliceId) {
2701
1455
  if (!currentDb)
2702
1456
  return [];
2703
- 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"]);
1457
+ const rows = currentDb.prepare("SELECT slice_id FROM slice_dependencies WHERE milestone_id = :mid AND depends_on_slice_id = :sid").all({ ":mid": milestoneId, ":sid": sliceId });
1458
+ return rowsToStringColumn(rows, "slice_id");
2704
1459
  }
2705
1460
  // ─── Worktree DB Helpers ──────────────────────────────────────────────────
2706
1461
  export function copyWorktreeDb(srcDbPath, destDbPath) {
@@ -3025,6 +1780,7 @@ export function deleteMilestone(milestoneId) {
3025
1780
  currentDb.prepare(`DELETE FROM replan_history WHERE milestone_id = :mid`).run({ ":mid": milestoneId });
3026
1781
  currentDb.prepare(`DELETE FROM assessments WHERE milestone_id = :mid`).run({ ":mid": milestoneId });
3027
1782
  currentDb.prepare(`DELETE FROM artifacts WHERE milestone_id = :mid`).run({ ":mid": milestoneId });
1783
+ currentDb.prepare(`DELETE FROM milestone_commit_attributions WHERE milestone_id = :mid`).run({ ":mid": milestoneId });
3028
1784
  currentDb.prepare(`DELETE FROM milestone_leases WHERE milestone_id = :mid`).run({ ":mid": milestoneId });
3029
1785
  currentDb.prepare(`DELETE FROM milestones WHERE id = :mid`).run({ ":mid": milestoneId });
3030
1786
  });
@@ -3070,20 +1826,6 @@ export function getLatestAssessmentByScope(milestoneId, scope) {
3070
1826
  return row ?? null;
3071
1827
  }
3072
1828
  // ─── Quality Gates ───────────────────────────────────────────────────────
3073
- function rowToGate(row) {
3074
- return {
3075
- milestone_id: row["milestone_id"],
3076
- slice_id: row["slice_id"],
3077
- gate_id: row["gate_id"],
3078
- scope: row["scope"],
3079
- task_id: row["task_id"] ?? "",
3080
- status: row["status"],
3081
- verdict: row["status"] === "pending" ? null : row["verdict"],
3082
- rationale: row["rationale"] || "",
3083
- findings: row["findings"] || "",
3084
- evaluated_at: row["evaluated_at"] ?? null,
3085
- };
3086
- }
3087
1829
  export function insertGateRow(g) {
3088
1830
  if (!currentDb)
3089
1831
  throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
@@ -3266,6 +2008,59 @@ export function upsertTurnGitTransaction(entry) {
3266
2008
  ":updated_at": entry.updatedAt,
3267
2009
  });
3268
2010
  }
2011
+ export function getMilestoneCommitAttributionShas(milestoneId) {
2012
+ if (!currentDb)
2013
+ return [];
2014
+ const rows = currentDb.prepare(`SELECT commit_sha
2015
+ FROM milestone_commit_attributions
2016
+ WHERE milestone_id = :mid
2017
+ ORDER BY created_at, commit_sha`).all({ ":mid": milestoneId });
2018
+ return rows
2019
+ .map((row) => typeof row["commit_sha"] === "string" ? row["commit_sha"] : "")
2020
+ .filter(Boolean);
2021
+ }
2022
+ export function recordMilestoneCommitAttribution(entry) {
2023
+ if (!currentDb)
2024
+ return;
2025
+ transaction(() => {
2026
+ currentDb.prepare(`INSERT OR REPLACE INTO milestone_commit_attributions (
2027
+ commit_sha, milestone_id, slice_id, task_id, source, confidence, files_json, created_at
2028
+ ) VALUES (
2029
+ :commit_sha, :milestone_id, :slice_id, :task_id, :source, :confidence, :files_json, :created_at
2030
+ )`).run({
2031
+ ":commit_sha": entry.commitSha,
2032
+ ":milestone_id": entry.milestoneId,
2033
+ ":slice_id": entry.sliceId ?? null,
2034
+ ":task_id": entry.taskId ?? null,
2035
+ ":source": entry.source,
2036
+ ":confidence": entry.confidence,
2037
+ ":files_json": JSON.stringify(entry.files),
2038
+ ":created_at": entry.createdAt,
2039
+ });
2040
+ currentDb.prepare(`INSERT OR IGNORE INTO audit_events (
2041
+ event_id, trace_id, turn_id, caused_by, category, type, ts, payload_json
2042
+ ) VALUES (
2043
+ :event_id, :trace_id, :turn_id, :caused_by, :category, :type, :ts, :payload_json
2044
+ )`).run({
2045
+ ":event_id": `milestone-commit-attribution:${entry.milestoneId}:${entry.commitSha}`,
2046
+ ":trace_id": "milestone-commit-attribution",
2047
+ ":turn_id": null,
2048
+ ":caused_by": null,
2049
+ ":category": "git",
2050
+ ":type": "milestone-commit-attribution-recorded",
2051
+ ":ts": entry.createdAt,
2052
+ ":payload_json": JSON.stringify({
2053
+ commitSha: entry.commitSha,
2054
+ milestoneId: entry.milestoneId,
2055
+ sliceId: entry.sliceId ?? null,
2056
+ taskId: entry.taskId ?? null,
2057
+ source: entry.source,
2058
+ confidence: entry.confidence,
2059
+ files: entry.files,
2060
+ }),
2061
+ });
2062
+ });
2063
+ }
3269
2064
  export function insertAuditEvent(entry) {
3270
2065
  if (!currentDb)
3271
2066
  return;
@@ -3352,6 +2147,7 @@ export function clearEngineHierarchy() {
3352
2147
  currentDb.exec("DELETE FROM slice_dependencies");
3353
2148
  currentDb.exec("DELETE FROM assessments");
3354
2149
  currentDb.exec("DELETE FROM replan_history");
2150
+ currentDb.exec("DELETE FROM milestone_commit_attributions");
3355
2151
  currentDb.exec("DELETE FROM tasks");
3356
2152
  currentDb.exec("DELETE FROM slices");
3357
2153
  currentDb.exec("DELETE FROM milestone_leases");