gsd-pi 2.80.0 → 2.81.0-dev.3cddbbba2

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 (1345) hide show
  1. package/README.md +47 -59
  2. package/dist/claude-cli-check.d.ts +30 -0
  3. package/dist/claude-cli-check.js +18 -7
  4. package/dist/cli.js +0 -19
  5. package/dist/headless-query.d.ts +10 -0
  6. package/dist/headless-query.js +6 -4
  7. package/dist/loader-entrypoint.d.ts +8 -0
  8. package/dist/loader-entrypoint.js +27 -0
  9. package/dist/loader.js +2 -11
  10. package/dist/mcp-server.d.ts +1 -0
  11. package/dist/mcp-server.js +6 -3
  12. package/dist/resources/.managed-resources-content-hash +1 -1
  13. package/dist/resources/GSD-WORKFLOW.md +2 -2
  14. package/dist/resources/extensions/claude-code-cli/readiness.js +18 -7
  15. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +40 -3
  16. package/dist/resources/extensions/github-sync/sync.js +4 -1
  17. package/dist/resources/extensions/github-sync/templates.js +90 -74
  18. package/dist/resources/extensions/gsd/auto/contracts.js +2 -0
  19. package/dist/resources/extensions/gsd/auto/custom-verify-retry-store.js +53 -0
  20. package/dist/resources/extensions/gsd/auto/loop.js +566 -526
  21. package/dist/resources/extensions/gsd/auto/orchestrator.js +48 -4
  22. package/dist/resources/extensions/gsd/auto/phases.js +402 -157
  23. package/dist/resources/extensions/gsd/auto/resolve.js +29 -0
  24. package/dist/resources/extensions/gsd/auto/run-unit.js +105 -46
  25. package/dist/resources/extensions/gsd/auto/session.js +18 -1
  26. package/dist/resources/extensions/gsd/auto/unit-runner-events.js +7 -0
  27. package/dist/resources/extensions/gsd/auto/verification-retry-policy.js +43 -0
  28. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-dispatch-outcome.js +12 -0
  29. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-iteration.js +24 -0
  30. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-reconcile-outcome.js +33 -0
  31. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-reconcile.js +26 -0
  32. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-retry.js +49 -0
  33. package/dist/resources/extensions/gsd/auto/workflow-custom-engine-verify-outcome.js +25 -0
  34. package/dist/resources/extensions/gsd/auto/workflow-dispatch-claim.js +80 -0
  35. package/dist/resources/extensions/gsd/auto/workflow-dispatch-ledger.js +26 -0
  36. package/dist/resources/extensions/gsd/auto/workflow-iteration-completion.js +10 -0
  37. package/dist/resources/extensions/gsd/auto/workflow-journal-reporter.js +16 -0
  38. package/dist/resources/extensions/gsd/auto/workflow-kernel.js +263 -0
  39. package/dist/resources/extensions/gsd/auto/workflow-memory-pressure.js +36 -0
  40. package/dist/resources/extensions/gsd/auto/workflow-phase-reporter.js +9 -0
  41. package/dist/resources/extensions/gsd/auto/workflow-session-lock.js +35 -0
  42. package/dist/resources/extensions/gsd/auto/workflow-sidecar-iteration.js +24 -0
  43. package/dist/resources/extensions/gsd/auto/workflow-sidecar-queue.js +26 -0
  44. package/dist/resources/extensions/gsd/auto/workflow-turn-reporter.js +36 -0
  45. package/dist/resources/extensions/gsd/auto/workflow-unit-dispatch.js +44 -0
  46. package/dist/resources/extensions/gsd/auto/workflow-worker-heartbeat.js +23 -0
  47. package/dist/resources/extensions/gsd/auto-dashboard.js +248 -187
  48. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +5 -32
  49. package/dist/resources/extensions/gsd/auto-dispatch.js +40 -11
  50. package/dist/resources/extensions/gsd/auto-post-unit.js +129 -89
  51. package/dist/resources/extensions/gsd/auto-prompts.js +382 -20
  52. package/dist/resources/extensions/gsd/auto-recovery.js +197 -9
  53. package/dist/resources/extensions/gsd/auto-runtime-state.js +5 -0
  54. package/dist/resources/extensions/gsd/auto-start.js +253 -19
  55. package/dist/resources/extensions/gsd/auto-supervisor.js +8 -1
  56. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +2 -2
  57. package/dist/resources/extensions/gsd/auto-unit-closeout.js +33 -5
  58. package/dist/resources/extensions/gsd/auto-verification.js +14 -17
  59. package/dist/resources/extensions/gsd/auto-worktree.js +324 -374
  60. package/dist/resources/extensions/gsd/auto.js +502 -130
  61. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +147 -12
  62. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +54 -37
  63. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -10
  64. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +30 -20
  65. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +4 -1
  66. package/dist/resources/extensions/gsd/bootstrap/memory-tools.js +6 -4
  67. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +5 -3
  68. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +1 -1
  69. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +356 -58
  70. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +4 -8
  71. package/dist/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.js +4 -0
  72. package/dist/resources/extensions/gsd/bootstrap/system-context.js +82 -23
  73. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +147 -2
  74. package/dist/resources/extensions/gsd/clean-root-preflight.js +65 -9
  75. package/dist/resources/extensions/gsd/commands/dispatcher.js +5 -0
  76. package/dist/resources/extensions/gsd/commands/handlers/notifications-handler.js +4 -10
  77. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  78. package/dist/resources/extensions/gsd/commands-config.js +1 -1
  79. package/dist/resources/extensions/gsd/commands-eval-review.js +2 -2
  80. package/dist/resources/extensions/gsd/commands-extract-learnings.js +17 -12
  81. package/dist/resources/extensions/gsd/commands-handlers.js +23 -9
  82. package/dist/resources/extensions/gsd/commands-ship.js +23 -46
  83. package/dist/resources/extensions/gsd/commands-workflow-templates.js +12 -7
  84. package/dist/resources/extensions/gsd/component-loader.js +5 -11
  85. package/dist/resources/extensions/gsd/context-budget.js +37 -2
  86. package/dist/resources/extensions/gsd/crash-recovery.js +56 -10
  87. package/dist/resources/extensions/gsd/custom-workflow-engine.js +25 -1
  88. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  89. package/dist/resources/extensions/gsd/db/unit-dispatches.js +92 -0
  90. package/dist/resources/extensions/gsd/db-adapter.js +47 -0
  91. package/dist/resources/extensions/gsd/db-base-schema.js +353 -0
  92. package/dist/resources/extensions/gsd/db-connection-cache.js +31 -0
  93. package/dist/resources/extensions/gsd/db-coordination-schema.js +104 -0
  94. package/dist/resources/extensions/gsd/db-decision-requirement-rows.js +71 -0
  95. package/dist/resources/extensions/gsd/db-gate-rows.js +16 -0
  96. package/dist/resources/extensions/gsd/db-lightweight-query-rows.js +29 -0
  97. package/dist/resources/extensions/gsd/db-memory-fts-schema.js +56 -0
  98. package/dist/resources/extensions/gsd/db-migration-backup.js +22 -0
  99. package/dist/resources/extensions/gsd/db-migration-steps.js +416 -0
  100. package/dist/resources/extensions/gsd/db-milestone-artifact-rows.js +35 -0
  101. package/dist/resources/extensions/gsd/db-open-state.js +32 -0
  102. package/dist/resources/extensions/gsd/db-provider.js +108 -0
  103. package/dist/resources/extensions/gsd/db-runtime-kv-schema.js +27 -0
  104. package/dist/resources/extensions/gsd/db-schema-metadata.js +23 -0
  105. package/dist/resources/extensions/gsd/db-task-slice-rows.js +86 -0
  106. package/dist/resources/extensions/gsd/db-transaction.js +63 -0
  107. package/dist/resources/extensions/gsd/db-verification-evidence-rows.js +3 -0
  108. package/dist/resources/extensions/gsd/db-verification-evidence-schema.js +19 -0
  109. package/dist/resources/extensions/gsd/detection.js +106 -0
  110. package/dist/resources/extensions/gsd/ecosystem/gsd-extension-api.js +2 -0
  111. package/dist/resources/extensions/gsd/escalation.js +2 -0
  112. package/dist/resources/extensions/gsd/git-service.js +75 -6
  113. package/dist/resources/extensions/gsd/graph.js +9 -3
  114. package/dist/resources/extensions/gsd/gsd-db.js +331 -1535
  115. package/dist/resources/extensions/gsd/guided-flow.js +149 -48
  116. package/dist/resources/extensions/gsd/health-widget-core.js +1 -1
  117. package/dist/resources/extensions/gsd/health-widget.js +6 -9
  118. package/dist/resources/extensions/gsd/init-wizard.js +4 -1
  119. package/dist/resources/extensions/gsd/legacy-telemetry.js +70 -0
  120. package/dist/resources/extensions/gsd/markdown-renderer.js +2 -0
  121. package/dist/resources/extensions/gsd/memory-store.js +69 -12
  122. package/dist/resources/extensions/gsd/migrate/command.js +40 -1
  123. package/dist/resources/extensions/gsd/migration-auto-check.js +87 -0
  124. package/dist/resources/extensions/gsd/model-router.js +9 -6
  125. package/dist/resources/extensions/gsd/native-git-bridge.js +46 -22
  126. package/dist/resources/extensions/gsd/notification-overlay.js +35 -40
  127. package/dist/resources/extensions/gsd/notification-widget.js +21 -3
  128. package/dist/resources/extensions/gsd/orphan-stash-audit.js +101 -0
  129. package/dist/resources/extensions/gsd/parallel-merge.js +53 -30
  130. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +25 -33
  131. package/dist/resources/extensions/gsd/parallel-orchestrator.js +13 -3
  132. package/dist/resources/extensions/gsd/planning-path-scope.js +26 -0
  133. package/dist/resources/extensions/gsd/post-execution-checks.js +2 -0
  134. package/dist/resources/extensions/gsd/pr-evidence.js +117 -0
  135. package/dist/resources/extensions/gsd/pre-execution-checks.js +24 -0
  136. package/dist/resources/extensions/gsd/process-task-path.js +61 -0
  137. package/dist/resources/extensions/gsd/prompt-loader.js +37 -7
  138. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +41 -35
  139. package/dist/resources/extensions/gsd/prompts/complete-slice.md +25 -34
  140. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +70 -98
  141. package/dist/resources/extensions/gsd/prompts/discuss.md +101 -183
  142. package/dist/resources/extensions/gsd/prompts/execute-task.md +42 -67
  143. package/dist/resources/extensions/gsd/prompts/forensics.md +41 -84
  144. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +29 -39
  145. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +30 -65
  146. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +25 -52
  147. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +36 -36
  148. package/dist/resources/extensions/gsd/prompts/guided-research-project.md +20 -38
  149. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  150. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +47 -59
  151. package/dist/resources/extensions/gsd/prompts/plan-slice.md +25 -87
  152. package/dist/resources/extensions/gsd/prompts/queue.md +46 -53
  153. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -5
  154. package/dist/resources/extensions/gsd/prompts/refine-slice.md +23 -23
  155. package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  156. package/dist/resources/extensions/gsd/prompts/research-slice.md +23 -23
  157. package/dist/resources/extensions/gsd/prompts/rethink.md +10 -10
  158. package/dist/resources/extensions/gsd/prompts/system.md +65 -107
  159. package/dist/resources/extensions/gsd/prompts/triage-captures.md +15 -15
  160. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +24 -24
  161. package/dist/resources/extensions/gsd/prompts/worktree-merge.md +35 -35
  162. package/dist/resources/extensions/gsd/quick.js +34 -2
  163. package/dist/resources/extensions/gsd/recovery-classification.js +94 -0
  164. package/dist/resources/extensions/gsd/safety/evidence-collector.js +10 -2
  165. package/dist/resources/extensions/gsd/slice-cadence.js +45 -2
  166. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +15 -9
  167. package/dist/resources/extensions/gsd/state-reconciliation.js +27 -0
  168. package/dist/resources/extensions/gsd/state.js +4 -0
  169. package/dist/resources/extensions/gsd/tool-contract.js +50 -0
  170. package/dist/resources/extensions/gsd/tools/complete-milestone.js +20 -16
  171. package/dist/resources/extensions/gsd/tools/complete-task.js +3 -1
  172. package/dist/resources/extensions/gsd/tools/context-mode-tool-result.js +15 -0
  173. package/dist/resources/extensions/gsd/tools/exec-search-tool.js +5 -0
  174. package/dist/resources/extensions/gsd/tools/exec-tool.js +3 -15
  175. package/dist/resources/extensions/gsd/tools/memory-tools.js +1 -0
  176. package/dist/resources/extensions/gsd/tools/plan-slice.js +9 -0
  177. package/dist/resources/extensions/gsd/tools/plan-task.js +9 -0
  178. package/dist/resources/extensions/gsd/tools/resume-tool.js +5 -0
  179. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +7 -2
  180. package/dist/resources/extensions/gsd/tui/render-kit.js +74 -0
  181. package/dist/resources/extensions/gsd/unit-context-composer.js +12 -3
  182. package/dist/resources/extensions/gsd/unit-runtime.js +22 -0
  183. package/dist/resources/extensions/gsd/uok/kernel.js +8 -3
  184. package/dist/resources/extensions/gsd/uok/plan-v2.js +2 -0
  185. package/dist/resources/extensions/gsd/watch/header-renderer.js +92 -69
  186. package/dist/resources/extensions/gsd/watch/splash-palette.js +10 -0
  187. package/dist/resources/extensions/gsd/workflow-logger.js +13 -13
  188. package/dist/resources/extensions/gsd/workflow-manifest.js +2 -0
  189. package/dist/resources/extensions/gsd/workflow-mcp.js +2 -2
  190. package/dist/resources/extensions/gsd/workflow-projections.js +2 -0
  191. package/dist/resources/extensions/gsd/workflow-protocol.js +131 -0
  192. package/dist/resources/extensions/gsd/workflow-templates.js +9 -0
  193. package/dist/resources/extensions/gsd/working-output-messages.js +64 -0
  194. package/dist/resources/extensions/gsd/worktree-lifecycle.js +1364 -0
  195. package/dist/resources/extensions/gsd/worktree-manager.js +16 -14
  196. package/dist/resources/extensions/gsd/worktree-safety.js +119 -0
  197. package/dist/resources/extensions/gsd/worktree-state-projection.js +317 -0
  198. package/dist/resources/extensions/gsd/worktree-telemetry.js +3 -1
  199. package/dist/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  200. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  201. package/dist/web/standalone/.next/BUILD_ID +1 -1
  202. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  203. package/dist/web/standalone/.next/build-manifest.json +4 -4
  204. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  205. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  206. package/dist/web/standalone/.next/required-server-files.json +4 -4
  207. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  208. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  210. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  211. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  212. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  213. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  214. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  215. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  216. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  217. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  218. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  219. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  220. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  221. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  222. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  223. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  224. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  225. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  226. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  227. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  228. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  229. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  230. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  231. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  232. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  233. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  234. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  235. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  236. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  237. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  238. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  239. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  240. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  241. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  242. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  243. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  244. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  245. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  246. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  247. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  248. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  249. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  250. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  251. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  252. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  253. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  254. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  255. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  256. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  257. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  258. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  259. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  260. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  261. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  262. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  263. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  264. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  265. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  266. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  267. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  268. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  269. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  270. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  271. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  272. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  273. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  274. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  275. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  276. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  277. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  278. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  279. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  280. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  281. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  282. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  283. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  284. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  285. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  286. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  287. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  288. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  289. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  290. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  291. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  292. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  293. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  294. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  295. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  296. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  297. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  298. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  299. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  300. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  301. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  302. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  303. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  304. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  305. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  306. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  307. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  308. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  309. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  310. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  311. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  312. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  313. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  314. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  315. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  316. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  317. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  318. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  319. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  320. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  321. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  322. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  323. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  324. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  325. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  326. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  327. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  328. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  329. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  330. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  331. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  332. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  333. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  334. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  335. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  336. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  337. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  338. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  339. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  340. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  341. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  342. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  343. package/dist/web/standalone/.next/server/app/index.html +1 -1
  344. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  345. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  346. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  347. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  348. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  349. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  350. package/dist/web/standalone/.next/server/app/page.js +2 -2
  351. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  352. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  353. package/dist/web/standalone/.next/server/chunks/167.js +2 -0
  354. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  355. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  356. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  357. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  358. package/dist/web/standalone/.next/server/middleware.js +2 -2
  359. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  360. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  361. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  362. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  363. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  364. package/dist/web/standalone/.next/static/chunks/8359.e059d86b255fce1c.js +10 -0
  365. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  366. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  367. package/dist/web/standalone/.next/static/chunks/app/page-752f1e2ebdaa3e45.js +1 -0
  368. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  369. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  370. package/dist/web/standalone/.next/static/chunks/{webpack-d82dbee6356c1733.js → webpack-de742b64187e13fe.js} +1 -1
  371. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  372. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  373. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  374. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  375. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  376. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  377. package/dist/web/standalone/package.json +1 -0
  378. package/dist/web/standalone/server.js +1 -1
  379. package/dist/welcome-screen.d.ts +2 -7
  380. package/dist/welcome-screen.js +68 -75
  381. package/package.json +20 -9
  382. package/packages/contracts/dist/index.d.ts +3 -0
  383. package/packages/contracts/dist/index.d.ts.map +1 -0
  384. package/packages/contracts/dist/index.js +5 -0
  385. package/packages/contracts/dist/index.js.map +1 -0
  386. package/packages/contracts/dist/rpc.d.ts +549 -0
  387. package/packages/contracts/dist/rpc.d.ts.map +1 -0
  388. package/packages/contracts/dist/rpc.js +53 -0
  389. package/packages/contracts/dist/rpc.js.map +1 -0
  390. package/packages/contracts/dist/rpc.test.d.ts +2 -0
  391. package/packages/contracts/dist/rpc.test.d.ts.map +1 -0
  392. package/packages/contracts/dist/rpc.test.js +47 -0
  393. package/packages/contracts/dist/rpc.test.js.map +1 -0
  394. package/packages/contracts/dist/workflow.d.ts +180 -0
  395. package/packages/contracts/dist/workflow.d.ts.map +1 -0
  396. package/packages/contracts/dist/workflow.js +201 -0
  397. package/packages/contracts/dist/workflow.js.map +1 -0
  398. package/packages/contracts/package.json +39 -0
  399. package/packages/contracts/src/index.ts +5 -0
  400. package/packages/contracts/src/rpc.test.ts +72 -0
  401. package/packages/contracts/src/rpc.ts +286 -0
  402. package/packages/contracts/src/workflow.ts +213 -0
  403. package/packages/contracts/tsconfig.json +25 -0
  404. package/packages/daemon/package.json +3 -2
  405. package/packages/daemon/src/event-bridge.test.ts +2 -1
  406. package/packages/daemon/src/event-bridge.ts +1 -1
  407. package/packages/daemon/src/event-formatter.test.ts +1 -2
  408. package/packages/daemon/src/event-formatter.ts +1 -2
  409. package/packages/daemon/src/session-manager.ts +2 -2
  410. package/packages/daemon/src/types.ts +3 -18
  411. package/packages/mcp-server/dist/server.d.ts +13 -0
  412. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  413. package/packages/mcp-server/dist/server.js +77 -0
  414. package/packages/mcp-server/dist/server.js.map +1 -1
  415. package/packages/mcp-server/dist/session-manager.js +1 -1
  416. package/packages/mcp-server/dist/session-manager.js.map +1 -1
  417. package/packages/mcp-server/dist/types.d.ts +3 -11
  418. package/packages/mcp-server/dist/types.d.ts.map +1 -1
  419. package/packages/mcp-server/dist/types.js.map +1 -1
  420. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -1
  421. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  422. package/packages/mcp-server/dist/workflow-tools.js +24 -57
  423. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  424. package/packages/mcp-server/package.json +3 -2
  425. package/packages/mcp-server/src/mcp-server.test.ts +138 -0
  426. package/packages/mcp-server/src/server.ts +99 -1
  427. package/packages/mcp-server/src/session-manager.ts +2 -2
  428. package/packages/mcp-server/src/types.ts +7 -18
  429. package/packages/mcp-server/src/workflow-tools.test.ts +75 -2
  430. package/packages/mcp-server/src/workflow-tools.ts +32 -56
  431. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  432. package/packages/native/package.json +1 -1
  433. package/packages/native/tsconfig.tsbuildinfo +1 -1
  434. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  435. package/packages/pi-agent-core/dist/agent-loop.js +4 -1
  436. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  437. package/packages/pi-agent-core/dist/agent.d.ts +9 -2
  438. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  439. package/packages/pi-agent-core/dist/agent.js +43 -11
  440. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  441. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  442. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  443. package/packages/pi-agent-core/dist/index.js +2 -0
  444. package/packages/pi-agent-core/dist/index.js.map +1 -1
  445. package/packages/pi-agent-core/dist/token-audit.d.ts +47 -0
  446. package/packages/pi-agent-core/dist/token-audit.d.ts.map +1 -0
  447. package/packages/pi-agent-core/dist/token-audit.js +221 -0
  448. package/packages/pi-agent-core/dist/token-audit.js.map +1 -0
  449. package/packages/pi-agent-core/dist/types.d.ts +31 -0
  450. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  451. package/packages/pi-agent-core/dist/types.js.map +1 -1
  452. package/packages/pi-agent-core/package.json +1 -1
  453. package/packages/pi-agent-core/src/agent-loop.test.ts +128 -0
  454. package/packages/pi-agent-core/src/agent-loop.ts +4 -1
  455. package/packages/pi-agent-core/src/agent.ts +52 -11
  456. package/packages/pi-agent-core/src/index.ts +2 -0
  457. package/packages/pi-agent-core/src/token-audit.test.ts +189 -0
  458. package/packages/pi-agent-core/src/token-audit.ts +287 -0
  459. package/packages/pi-agent-core/src/types.ts +26 -10
  460. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  461. package/packages/pi-ai/dist/models/fake-model.d.ts +12 -0
  462. package/packages/pi-ai/dist/models/fake-model.d.ts.map +1 -0
  463. package/packages/pi-ai/dist/models/fake-model.js +27 -0
  464. package/packages/pi-ai/dist/models/fake-model.js.map +1 -0
  465. package/packages/pi-ai/dist/models/index.d.ts.map +1 -1
  466. package/packages/pi-ai/dist/models/index.js +8 -0
  467. package/packages/pi-ai/dist/models/index.js.map +1 -1
  468. package/packages/pi-ai/dist/providers/anthropic-auth.test.js +35 -13
  469. package/packages/pi-ai/dist/providers/anthropic-auth.test.js.map +1 -1
  470. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js +21 -11
  471. package/packages/pi-ai/dist/providers/anthropic-bearer-auth.test.js.map +1 -1
  472. package/packages/pi-ai/dist/providers/anthropic.d.ts +7 -0
  473. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  474. package/packages/pi-ai/dist/providers/anthropic.js +9 -7
  475. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  476. package/packages/pi-ai/dist/providers/fake.d.ts +42 -0
  477. package/packages/pi-ai/dist/providers/fake.d.ts.map +1 -0
  478. package/packages/pi-ai/dist/providers/fake.js +319 -0
  479. package/packages/pi-ai/dist/providers/fake.js.map +1 -0
  480. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js +23 -14
  481. package/packages/pi-ai/dist/providers/minimax-tool-name.test.js.map +1 -1
  482. package/packages/pi-ai/dist/providers/register-builtins.d.ts.map +1 -1
  483. package/packages/pi-ai/dist/providers/register-builtins.js +24 -0
  484. package/packages/pi-ai/dist/providers/register-builtins.js.map +1 -1
  485. package/packages/pi-ai/dist/types.d.ts +2 -0
  486. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  487. package/packages/pi-ai/dist/types.js.map +1 -1
  488. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js +48 -21
  489. package/packages/pi-ai/dist/utils/oauth/github-copilot.test.js.map +1 -1
  490. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js +22 -21
  491. package/packages/pi-ai/dist/utils/oauth/google-antigravity.test.js.map +1 -1
  492. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js +22 -21
  493. package/packages/pi-ai/dist/utils/oauth/google-gemini-cli.test.js.map +1 -1
  494. package/packages/pi-ai/package.json +1 -1
  495. package/packages/pi-ai/src/models/fake-model.ts +30 -0
  496. package/packages/pi-ai/src/models/index.ts +9 -0
  497. package/packages/pi-ai/src/providers/anthropic-auth.test.ts +39 -25
  498. package/packages/pi-ai/src/providers/anthropic-bearer-auth.test.ts +26 -22
  499. package/packages/pi-ai/src/providers/anthropic.ts +22 -9
  500. package/packages/pi-ai/src/providers/fake.ts +376 -0
  501. package/packages/pi-ai/src/providers/minimax-tool-name.test.ts +34 -21
  502. package/packages/pi-ai/src/providers/register-builtins.ts +23 -0
  503. package/packages/pi-ai/src/types.ts +3 -0
  504. package/packages/pi-ai/src/utils/oauth/github-copilot.test.ts +56 -22
  505. package/packages/pi-ai/src/utils/oauth/google-antigravity.test.ts +24 -28
  506. package/packages/pi-ai/src/utils/oauth/google-gemini-cli.test.ts +24 -28
  507. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  508. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js +36 -1
  509. package/packages/pi-coding-agent/dist/core/agent-session-abort-order.test.js.map +1 -1
  510. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js +30 -1
  511. package/packages/pi-coding-agent/dist/core/agent-session-tool-refresh.test.js.map +1 -1
  512. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +21 -2
  513. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  514. package/packages/pi-coding-agent/dist/core/agent-session.js +94 -16
  515. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  516. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js +78 -0
  517. package/packages/pi-coding-agent/dist/core/chat-controller-ordering.test.js.map +1 -1
  518. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +11 -0
  519. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  520. package/packages/pi-coding-agent/dist/core/compaction/compaction.js +9 -0
  521. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  522. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts +2 -0
  523. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.d.ts.map +1 -0
  524. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js +103 -0
  525. package/packages/pi-coding-agent/dist/core/compaction-threshold.test.js.map +1 -0
  526. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts +15 -0
  527. package/packages/pi-coding-agent/dist/core/db-snapshot.d.ts.map +1 -0
  528. package/packages/pi-coding-agent/dist/core/db-snapshot.js +66 -0
  529. package/packages/pi-coding-agent/dist/core/db-snapshot.js.map +1 -0
  530. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts +2 -0
  531. package/packages/pi-coding-agent/dist/core/db-snapshot.test.d.ts.map +1 -0
  532. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js +24 -0
  533. package/packages/pi-coding-agent/dist/core/db-snapshot.test.js.map +1 -0
  534. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  535. package/packages/pi-coding-agent/dist/core/extensions/loader.js +8 -0
  536. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  537. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +5 -0
  538. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  539. package/packages/pi-coding-agent/dist/core/extensions/runner.js +20 -7
  540. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  541. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +102 -3
  542. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  543. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +60 -4
  544. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  545. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  546. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js +2 -0
  547. package/packages/pi-coding-agent/dist/core/hooks-runner.test.js.map +1 -1
  548. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  549. package/packages/pi-coding-agent/dist/core/model-registry.js +5 -0
  550. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  551. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts +2 -0
  552. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.d.ts.map +1 -0
  553. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js +46 -0
  554. package/packages/pi-coding-agent/dist/core/sdk-tool-filter.test.js.map +1 -0
  555. package/packages/pi-coding-agent/dist/core/sdk.d.ts +10 -2
  556. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  557. package/packages/pi-coding-agent/dist/core/sdk.js +81 -4
  558. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  559. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +24 -0
  560. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  561. package/packages/pi-coding-agent/dist/core/settings-manager.js +33 -0
  562. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  563. package/packages/pi-coding-agent/dist/core/skill-tool.test.js +22 -0
  564. package/packages/pi-coding-agent/dist/core/skill-tool.test.js.map +1 -1
  565. package/packages/pi-coding-agent/dist/core/slash-commands.d.ts.map +1 -1
  566. package/packages/pi-coding-agent/dist/core/slash-commands.js +1 -0
  567. package/packages/pi-coding-agent/dist/core/slash-commands.js.map +1 -1
  568. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +6 -7
  569. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  570. package/packages/pi-coding-agent/dist/core/system-prompt.js +2 -3
  571. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  572. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js +22 -56
  573. package/packages/pi-coding-agent/dist/core/tools/bash-spawn-windows.test.js.map +1 -1
  574. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +1 -0
  575. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  576. package/packages/pi-coding-agent/dist/core/tools/bash.js +3 -1
  577. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  578. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts +2 -0
  579. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  580. package/packages/pi-coding-agent/dist/core/tools/edit.js +12 -1
  581. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  582. package/packages/pi-coding-agent/dist/core/tools/find.d.ts +2 -0
  583. package/packages/pi-coding-agent/dist/core/tools/find.d.ts.map +1 -1
  584. package/packages/pi-coding-agent/dist/core/tools/find.js +14 -6
  585. package/packages/pi-coding-agent/dist/core/tools/find.js.map +1 -1
  586. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts +2 -0
  587. package/packages/pi-coding-agent/dist/core/tools/grep.d.ts.map +1 -1
  588. package/packages/pi-coding-agent/dist/core/tools/grep.js +12 -3
  589. package/packages/pi-coding-agent/dist/core/tools/grep.js.map +1 -1
  590. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts +2 -0
  591. package/packages/pi-coding-agent/dist/core/tools/hashline-read.d.ts.map +1 -1
  592. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js +3 -1
  593. package/packages/pi-coding-agent/dist/core/tools/hashline-read.js.map +1 -1
  594. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +2 -1
  595. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  596. package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
  597. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  598. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts +2 -0
  599. package/packages/pi-coding-agent/dist/core/tools/ls.d.ts.map +1 -1
  600. package/packages/pi-coding-agent/dist/core/tools/ls.js +10 -3
  601. package/packages/pi-coding-agent/dist/core/tools/ls.js.map +1 -1
  602. package/packages/pi-coding-agent/dist/core/tools/read.d.ts +2 -0
  603. package/packages/pi-coding-agent/dist/core/tools/read.d.ts.map +1 -1
  604. package/packages/pi-coding-agent/dist/core/tools/read.js +3 -1
  605. package/packages/pi-coding-agent/dist/core/tools/read.js.map +1 -1
  606. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js +7 -62
  607. package/packages/pi-coding-agent/dist/core/tools/spawn-shell-windows.test.js.map +1 -1
  608. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts +2 -0
  609. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.d.ts.map +1 -0
  610. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js +115 -0
  611. package/packages/pi-coding-agent/dist/core/tools/tool-target-metadata.test.js.map +1 -0
  612. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts +19 -0
  613. package/packages/pi-coding-agent/dist/core/tools/tool-target.d.ts.map +1 -0
  614. package/packages/pi-coding-agent/dist/core/tools/tool-target.js +20 -0
  615. package/packages/pi-coding-agent/dist/core/tools/tool-target.js.map +1 -0
  616. package/packages/pi-coding-agent/dist/core/tools/write.d.ts +4 -0
  617. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  618. package/packages/pi-coding-agent/dist/core/tools/write.js +9 -1
  619. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  620. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts +2 -0
  621. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.d.ts.map +1 -0
  622. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js +47 -0
  623. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/assistant-message-design.test.js.map +1 -0
  624. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js +6 -4
  625. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.js.map +1 -1
  626. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js +225 -18
  627. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/tool-execution.test.js.map +1 -1
  628. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts +2 -0
  629. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.d.ts.map +1 -0
  630. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js +40 -0
  631. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/user-message-design.test.js.map +1 -0
  632. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts +25 -0
  633. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.d.ts.map +1 -0
  634. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js +113 -0
  635. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.js.map +1 -0
  636. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts +2 -0
  637. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.d.ts.map +1 -0
  638. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js +58 -0
  639. package/packages/pi-coding-agent/dist/modes/interactive/components/adaptive-layout.test.js.map +1 -0
  640. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  641. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +13 -13
  642. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  643. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts +1 -3
  644. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  645. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js +58 -3
  646. package/packages/pi-coding-agent/dist/modes/interactive/components/bash-execution.js.map +1 -1
  647. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.d.ts.map +1 -1
  648. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js +10 -9
  649. package/packages/pi-coding-agent/dist/modes/interactive/components/chat-frame.js.map +1 -1
  650. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts +2 -2
  651. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.d.ts.map +1 -1
  652. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js +12 -6
  653. package/packages/pi-coding-agent/dist/modes/interactive/components/diff.js.map +1 -1
  654. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  655. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -41
  656. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  657. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +3 -0
  658. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  659. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +11 -0
  660. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  661. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +51 -6
  662. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -1
  663. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +21 -0
  664. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  665. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +302 -56
  666. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  667. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts +35 -0
  668. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.d.ts.map +1 -0
  669. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js +152 -0
  670. package/packages/pi-coding-agent/dist/modes/interactive/components/transcript-design.js.map +1 -0
  671. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts +16 -0
  672. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.d.ts.map +1 -0
  673. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js +73 -0
  674. package/packages/pi-coding-agent/dist/modes/interactive/components/tui-style-kit.js.map +1 -0
  675. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +1 -1
  676. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  677. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +12 -8
  678. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  679. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  680. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +86 -2
  681. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  682. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js +111 -1
  683. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.test.js.map +1 -1
  684. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +1 -0
  685. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  686. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts +1 -0
  687. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  688. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  689. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts +14 -1
  690. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  691. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +77 -11
  692. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  693. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.d.ts.map +1 -1
  694. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js +20 -0
  695. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.js.map +1 -1
  696. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts +2 -0
  697. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.d.ts.map +1 -0
  698. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js +79 -0
  699. package/packages/pi-coding-agent/dist/modes/interactive/slash-command-handlers.test.js.map +1 -0
  700. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  701. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  702. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  703. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  704. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  705. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  706. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js +13 -0
  707. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  708. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  709. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  710. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +123 -2
  711. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  712. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  713. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js +39 -29
  714. package/packages/pi-coding-agent/dist/modes/interactive/theme/themes.js.map +1 -1
  715. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts +11 -0
  716. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.d.ts.map +1 -0
  717. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js +18 -0
  718. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.js.map +1 -0
  719. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts +2 -0
  720. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.d.ts.map +1 -0
  721. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js +51 -0
  722. package/packages/pi-coding-agent/dist/modes/interactive/tui-mode.test.js.map +1 -0
  723. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +1 -1
  724. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  725. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts +1 -512
  726. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  727. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js +3 -7
  728. package/packages/pi-coding-agent/dist/modes/rpc/rpc-types.js.map +1 -1
  729. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts +2 -0
  730. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.d.ts.map +1 -0
  731. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js +28 -0
  732. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage-safety-guard.test.js.map +1 -0
  733. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.d.ts.map +1 -1
  734. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js +3 -2
  735. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.js.map +1 -1
  736. package/packages/pi-coding-agent/package.json +2 -1
  737. package/packages/pi-coding-agent/src/core/agent-session-abort-order.test.ts +40 -1
  738. package/packages/pi-coding-agent/src/core/agent-session-tool-refresh.test.ts +40 -1
  739. package/packages/pi-coding-agent/src/core/agent-session.ts +102 -16
  740. package/packages/pi-coding-agent/src/core/chat-controller-ordering.test.ts +91 -0
  741. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +18 -0
  742. package/packages/pi-coding-agent/src/core/compaction-threshold.test.ts +121 -0
  743. package/packages/pi-coding-agent/src/core/db-snapshot.test.ts +32 -0
  744. package/packages/pi-coding-agent/src/core/db-snapshot.ts +66 -0
  745. package/packages/pi-coding-agent/src/core/extensions/loader.ts +10 -0
  746. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +113 -3
  747. package/packages/pi-coding-agent/src/core/extensions/runner.ts +24 -6
  748. package/packages/pi-coding-agent/src/core/extensions/types.ts +63 -2
  749. package/packages/pi-coding-agent/src/core/hooks-runner.test.ts +2 -0
  750. package/packages/pi-coding-agent/src/core/model-registry.ts +4 -0
  751. package/packages/pi-coding-agent/src/core/sdk-tool-filter.test.ts +60 -0
  752. package/packages/pi-coding-agent/src/core/sdk.ts +92 -4
  753. package/packages/pi-coding-agent/src/core/settings-manager.ts +51 -1
  754. package/packages/pi-coding-agent/src/core/skill-tool.test.ts +28 -0
  755. package/packages/pi-coding-agent/src/core/slash-commands.ts +1 -0
  756. package/packages/pi-coding-agent/src/core/system-prompt.ts +8 -10
  757. package/packages/pi-coding-agent/src/core/tools/bash-spawn-windows.test.ts +22 -66
  758. package/packages/pi-coding-agent/src/core/tools/bash.ts +4 -1
  759. package/packages/pi-coding-agent/src/core/tools/edit.ts +13 -1
  760. package/packages/pi-coding-agent/src/core/tools/find.ts +15 -6
  761. package/packages/pi-coding-agent/src/core/tools/grep.ts +13 -3
  762. package/packages/pi-coding-agent/src/core/tools/hashline-read.ts +4 -1
  763. package/packages/pi-coding-agent/src/core/tools/index.ts +8 -0
  764. package/packages/pi-coding-agent/src/core/tools/ls.ts +11 -3
  765. package/packages/pi-coding-agent/src/core/tools/read.ts +4 -1
  766. package/packages/pi-coding-agent/src/core/tools/spawn-shell-windows.test.ts +11 -72
  767. package/packages/pi-coding-agent/src/core/tools/tool-target-metadata.test.ts +127 -0
  768. package/packages/pi-coding-agent/src/core/tools/tool-target.ts +48 -0
  769. package/packages/pi-coding-agent/src/core/tools/write.ts +14 -2
  770. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/assistant-message-design.test.ts +56 -0
  771. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/chat-frame-compaction-tone.test.ts +7 -5
  772. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/tool-execution.test.ts +325 -20
  773. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/user-message-design.test.ts +48 -0
  774. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.test.ts +66 -0
  775. package/packages/pi-coding-agent/src/modes/interactive/components/adaptive-layout.ts +161 -0
  776. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +14 -13
  777. package/packages/pi-coding-agent/src/modes/interactive/components/bash-execution.ts +64 -3
  778. package/packages/pi-coding-agent/src/modes/interactive/components/chat-frame.ts +10 -9
  779. package/packages/pi-coding-agent/src/modes/interactive/components/diff.ts +13 -7
  780. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +15 -42
  781. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  782. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +71 -9
  783. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +327 -68
  784. package/packages/pi-coding-agent/src/modes/interactive/components/transcript-design.ts +196 -0
  785. package/packages/pi-coding-agent/src/modes/interactive/components/tui-style-kit.ts +94 -0
  786. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +14 -9
  787. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.test.ts +118 -1
  788. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +108 -3
  789. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +1 -0
  790. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode-state.ts +1 -1
  791. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +101 -11
  792. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.test.ts +95 -0
  793. package/packages/pi-coding-agent/src/modes/interactive/slash-command-handlers.ts +24 -1
  794. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-highlight.test.ts +23 -0
  795. package/packages/pi-coding-agent/src/modes/interactive/theme/theme-schema.ts +13 -0
  796. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +138 -3
  797. package/packages/pi-coding-agent/src/modes/interactive/theme/themes.ts +39 -29
  798. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.test.ts +68 -0
  799. package/packages/pi-coding-agent/src/modes/interactive/tui-mode.ts +29 -0
  800. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +1 -1
  801. package/packages/pi-coding-agent/src/modes/rpc/rpc-types.ts +3 -336
  802. package/packages/pi-coding-agent/src/resources/extensions/memory/storage-safety-guard.test.ts +31 -0
  803. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.ts +3 -2
  804. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  805. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js +14 -1
  806. package/packages/pi-tui/dist/__tests__/overlay-layout.test.js.map +1 -1
  807. package/packages/pi-tui/dist/__tests__/style.test.d.ts +2 -0
  808. package/packages/pi-tui/dist/__tests__/style.test.d.ts.map +1 -0
  809. package/packages/pi-tui/dist/__tests__/style.test.js +63 -0
  810. package/packages/pi-tui/dist/__tests__/style.test.js.map +1 -0
  811. package/packages/pi-tui/dist/__tests__/tui.test.js +24 -3
  812. package/packages/pi-tui/dist/__tests__/tui.test.js.map +1 -1
  813. package/packages/pi-tui/dist/index.d.ts +1 -0
  814. package/packages/pi-tui/dist/index.d.ts.map +1 -1
  815. package/packages/pi-tui/dist/index.js +2 -0
  816. package/packages/pi-tui/dist/index.js.map +1 -1
  817. package/packages/pi-tui/dist/overlay-layout.d.ts.map +1 -1
  818. package/packages/pi-tui/dist/overlay-layout.js +9 -6
  819. package/packages/pi-tui/dist/overlay-layout.js.map +1 -1
  820. package/packages/pi-tui/dist/style.d.ts +41 -0
  821. package/packages/pi-tui/dist/style.d.ts.map +1 -0
  822. package/packages/pi-tui/dist/style.js +158 -0
  823. package/packages/pi-tui/dist/style.js.map +1 -0
  824. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  825. package/packages/pi-tui/dist/tui.js +19 -8
  826. package/packages/pi-tui/dist/tui.js.map +1 -1
  827. package/packages/pi-tui/package.json +1 -1
  828. package/packages/pi-tui/src/__tests__/overlay-layout.test.ts +20 -1
  829. package/packages/pi-tui/src/__tests__/style.test.ts +76 -0
  830. package/packages/pi-tui/src/__tests__/tui.test.ts +29 -3
  831. package/packages/pi-tui/src/index.ts +9 -0
  832. package/packages/pi-tui/src/overlay-layout.ts +10 -7
  833. package/packages/pi-tui/src/style.ts +225 -0
  834. package/packages/pi-tui/src/tui.ts +21 -8
  835. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  836. package/packages/rpc-client/README.md +10 -3
  837. package/packages/rpc-client/dist/index.d.ts +1 -1
  838. package/packages/rpc-client/dist/index.d.ts.map +1 -1
  839. package/packages/rpc-client/dist/index.js.map +1 -1
  840. package/packages/rpc-client/dist/rpc-client.d.ts +2 -6
  841. package/packages/rpc-client/dist/rpc-client.d.ts.map +1 -1
  842. package/packages/rpc-client/dist/rpc-client.js.map +1 -1
  843. package/packages/rpc-client/dist/rpc-types.d.ts +1 -565
  844. package/packages/rpc-client/dist/rpc-types.d.ts.map +1 -1
  845. package/packages/rpc-client/dist/rpc-types.js +3 -11
  846. package/packages/rpc-client/dist/rpc-types.js.map +1 -1
  847. package/packages/rpc-client/package.json +4 -1
  848. package/packages/rpc-client/src/index.ts +1 -1
  849. package/packages/rpc-client/src/rpc-client.ts +3 -6
  850. package/packages/rpc-client/src/rpc-types.ts +3 -398
  851. package/packages/rpc-client/tsconfig.tsbuildinfo +1 -1
  852. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts +2 -0
  853. package/pkg/dist/modes/interactive/theme/theme-highlight.test.d.ts.map +1 -0
  854. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js +17 -0
  855. package/pkg/dist/modes/interactive/theme/theme-highlight.test.js.map +1 -0
  856. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts +12 -0
  857. package/pkg/dist/modes/interactive/theme/theme-schema.d.ts.map +1 -1
  858. package/pkg/dist/modes/interactive/theme/theme-schema.js +13 -0
  859. package/pkg/dist/modes/interactive/theme/theme-schema.js.map +1 -1
  860. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  861. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  862. package/pkg/dist/modes/interactive/theme/theme.js +123 -2
  863. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  864. package/pkg/dist/modes/interactive/theme/themes.d.ts.map +1 -1
  865. package/pkg/dist/modes/interactive/theme/themes.js +39 -29
  866. package/pkg/dist/modes/interactive/theme/themes.js.map +1 -1
  867. package/pkg/package.json +1 -1
  868. package/src/resources/GSD-WORKFLOW.md +2 -2
  869. package/src/resources/extensions/claude-code-cli/readiness.ts +25 -7
  870. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +42 -3
  871. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +67 -0
  872. package/src/resources/extensions/github-sync/sync.ts +8 -1
  873. package/src/resources/extensions/github-sync/templates.ts +93 -88
  874. package/src/resources/extensions/github-sync/tests/inline-code.test.ts +66 -0
  875. package/src/resources/extensions/github-sync/tests/sync-source.test.ts +6 -18
  876. package/src/resources/extensions/github-sync/tests/templates.test.ts +10 -2
  877. package/src/resources/extensions/gsd/auto/contracts.ts +19 -2
  878. package/src/resources/extensions/gsd/auto/custom-verify-retry-store.ts +72 -0
  879. package/src/resources/extensions/gsd/auto/loop-deps.ts +20 -16
  880. package/src/resources/extensions/gsd/auto/loop.ts +645 -603
  881. package/src/resources/extensions/gsd/auto/orchestrator.ts +52 -4
  882. package/src/resources/extensions/gsd/auto/phases.ts +546 -222
  883. package/src/resources/extensions/gsd/auto/resolve.ts +42 -1
  884. package/src/resources/extensions/gsd/auto/run-unit.ts +119 -46
  885. package/src/resources/extensions/gsd/auto/session.ts +19 -1
  886. package/src/resources/extensions/gsd/auto/types.ts +3 -0
  887. package/src/resources/extensions/gsd/auto/unit-runner-events.ts +15 -0
  888. package/src/resources/extensions/gsd/auto/verification-retry-policy.ts +82 -0
  889. package/src/resources/extensions/gsd/auto/workflow-custom-engine-dispatch-outcome.ts +28 -0
  890. package/src/resources/extensions/gsd/auto/workflow-custom-engine-iteration.ts +52 -0
  891. package/src/resources/extensions/gsd/auto/workflow-custom-engine-reconcile-outcome.ts +58 -0
  892. package/src/resources/extensions/gsd/auto/workflow-custom-engine-reconcile.ts +71 -0
  893. package/src/resources/extensions/gsd/auto/workflow-custom-engine-retry.ts +90 -0
  894. package/src/resources/extensions/gsd/auto/workflow-custom-engine-verify-outcome.ts +50 -0
  895. package/src/resources/extensions/gsd/auto/workflow-dispatch-claim.ts +159 -0
  896. package/src/resources/extensions/gsd/auto/workflow-dispatch-ledger.ts +45 -0
  897. package/src/resources/extensions/gsd/auto/workflow-iteration-completion.ts +26 -0
  898. package/src/resources/extensions/gsd/auto/workflow-journal-reporter.ts +33 -0
  899. package/src/resources/extensions/gsd/auto/workflow-kernel.ts +520 -0
  900. package/src/resources/extensions/gsd/auto/workflow-memory-pressure.ts +58 -0
  901. package/src/resources/extensions/gsd/auto/workflow-phase-reporter.ts +22 -0
  902. package/src/resources/extensions/gsd/auto/workflow-session-lock.ts +68 -0
  903. package/src/resources/extensions/gsd/auto/workflow-sidecar-iteration.ts +46 -0
  904. package/src/resources/extensions/gsd/auto/workflow-sidecar-queue.ts +46 -0
  905. package/src/resources/extensions/gsd/auto/workflow-turn-reporter.ts +68 -0
  906. package/src/resources/extensions/gsd/auto/workflow-unit-dispatch.ts +89 -0
  907. package/src/resources/extensions/gsd/auto/workflow-worker-heartbeat.ts +51 -0
  908. package/src/resources/extensions/gsd/auto-dashboard.ts +304 -184
  909. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -34
  910. package/src/resources/extensions/gsd/auto-dispatch.ts +48 -1
  911. package/src/resources/extensions/gsd/auto-post-unit.ts +141 -91
  912. package/src/resources/extensions/gsd/auto-prompts.ts +398 -19
  913. package/src/resources/extensions/gsd/auto-recovery.ts +207 -7
  914. package/src/resources/extensions/gsd/auto-runtime-state.ts +5 -0
  915. package/src/resources/extensions/gsd/auto-start.ts +328 -27
  916. package/src/resources/extensions/gsd/auto-supervisor.ts +7 -0
  917. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +2 -2
  918. package/src/resources/extensions/gsd/auto-unit-closeout.ts +51 -0
  919. package/src/resources/extensions/gsd/auto-verification.ts +17 -7
  920. package/src/resources/extensions/gsd/auto-worktree.ts +352 -396
  921. package/src/resources/extensions/gsd/auto.ts +590 -127
  922. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +181 -12
  923. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +56 -37
  924. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +36 -10
  925. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +32 -19
  926. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +5 -1
  927. package/src/resources/extensions/gsd/bootstrap/memory-tools.ts +7 -4
  928. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +6 -3
  929. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +1 -1
  930. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +411 -58
  931. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +5 -8
  932. package/src/resources/extensions/gsd/bootstrap/sanitize-complete-milestone.ts +4 -0
  933. package/src/resources/extensions/gsd/bootstrap/system-context.ts +90 -22
  934. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +153 -2
  935. package/src/resources/extensions/gsd/clean-root-preflight.ts +72 -9
  936. package/src/resources/extensions/gsd/commands/dispatcher.ts +6 -0
  937. package/src/resources/extensions/gsd/commands/handlers/notifications-handler.ts +4 -10
  938. package/src/resources/extensions/gsd/commands/handlers/ops.ts +4 -2
  939. package/src/resources/extensions/gsd/commands-config.ts +1 -1
  940. package/src/resources/extensions/gsd/commands-eval-review.ts +2 -2
  941. package/src/resources/extensions/gsd/commands-extract-learnings.ts +17 -12
  942. package/src/resources/extensions/gsd/commands-handlers.ts +34 -15
  943. package/src/resources/extensions/gsd/commands-ship.ts +24 -51
  944. package/src/resources/extensions/gsd/commands-workflow-templates.ts +13 -0
  945. package/src/resources/extensions/gsd/component-loader.ts +5 -11
  946. package/src/resources/extensions/gsd/context-budget.ts +44 -2
  947. package/src/resources/extensions/gsd/crash-recovery.ts +67 -10
  948. package/src/resources/extensions/gsd/custom-workflow-engine.ts +29 -0
  949. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  950. package/src/resources/extensions/gsd/db/unit-dispatches.ts +107 -0
  951. package/src/resources/extensions/gsd/db-adapter.ts +75 -0
  952. package/src/resources/extensions/gsd/db-base-schema.ts +385 -0
  953. package/src/resources/extensions/gsd/db-connection-cache.ts +45 -0
  954. package/src/resources/extensions/gsd/db-coordination-schema.ts +109 -0
  955. package/src/resources/extensions/gsd/db-decision-requirement-rows.ts +77 -0
  956. package/src/resources/extensions/gsd/db-gate-rows.ts +19 -0
  957. package/src/resources/extensions/gsd/db-lightweight-query-rows.ts +50 -0
  958. package/src/resources/extensions/gsd/db-memory-fts-schema.ts +66 -0
  959. package/src/resources/extensions/gsd/db-migration-backup.ts +34 -0
  960. package/src/resources/extensions/gsd/db-migration-steps.ts +459 -0
  961. package/src/resources/extensions/gsd/db-milestone-artifact-rows.ts +70 -0
  962. package/src/resources/extensions/gsd/db-open-state.ts +47 -0
  963. package/src/resources/extensions/gsd/db-provider.ts +148 -0
  964. package/src/resources/extensions/gsd/db-runtime-kv-schema.ts +30 -0
  965. package/src/resources/extensions/gsd/db-schema-metadata.ts +33 -0
  966. package/src/resources/extensions/gsd/db-task-slice-rows.ts +146 -0
  967. package/src/resources/extensions/gsd/db-transaction.ts +76 -0
  968. package/src/resources/extensions/gsd/db-verification-evidence-rows.ts +14 -0
  969. package/src/resources/extensions/gsd/db-verification-evidence-schema.ts +22 -0
  970. package/src/resources/extensions/gsd/detection.ts +128 -0
  971. package/src/resources/extensions/gsd/ecosystem/gsd-extension-api.ts +3 -0
  972. package/src/resources/extensions/gsd/escalation.ts +3 -1
  973. package/src/resources/extensions/gsd/git-service.ts +89 -10
  974. package/src/resources/extensions/gsd/graph.ts +12 -5
  975. package/src/resources/extensions/gsd/gsd-db.ts +399 -1677
  976. package/src/resources/extensions/gsd/guided-flow.ts +175 -55
  977. package/src/resources/extensions/gsd/health-widget-core.ts +1 -1
  978. package/src/resources/extensions/gsd/health-widget.ts +8 -9
  979. package/src/resources/extensions/gsd/init-wizard.ts +5 -1
  980. package/src/resources/extensions/gsd/journal.ts +2 -0
  981. package/src/resources/extensions/gsd/legacy-telemetry.ts +99 -0
  982. package/src/resources/extensions/gsd/markdown-renderer.ts +4 -1
  983. package/src/resources/extensions/gsd/memory-store.ts +77 -12
  984. package/src/resources/extensions/gsd/migrate/command.ts +47 -1
  985. package/src/resources/extensions/gsd/migration-auto-check.ts +129 -0
  986. package/src/resources/extensions/gsd/model-router.ts +10 -6
  987. package/src/resources/extensions/gsd/native-git-bridge.ts +53 -19
  988. package/src/resources/extensions/gsd/notification-overlay.ts +50 -46
  989. package/src/resources/extensions/gsd/notification-widget.ts +25 -4
  990. package/src/resources/extensions/gsd/orphan-stash-audit.ts +117 -0
  991. package/src/resources/extensions/gsd/parallel-merge.ts +61 -34
  992. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +33 -35
  993. package/src/resources/extensions/gsd/parallel-orchestrator.ts +13 -3
  994. package/src/resources/extensions/gsd/planning-path-scope.ts +35 -0
  995. package/src/resources/extensions/gsd/post-execution-checks.ts +4 -1
  996. package/src/resources/extensions/gsd/pr-evidence.ts +182 -0
  997. package/src/resources/extensions/gsd/pre-execution-checks.ts +27 -1
  998. package/src/resources/extensions/gsd/preferences-types.ts +1 -1
  999. package/src/resources/extensions/gsd/process-task-path.ts +81 -0
  1000. package/src/resources/extensions/gsd/prompt-loader.ts +36 -7
  1001. package/src/resources/extensions/gsd/prompts/complete-milestone.md +41 -35
  1002. package/src/resources/extensions/gsd/prompts/complete-slice.md +25 -34
  1003. package/src/resources/extensions/gsd/prompts/discuss-headless.md +70 -98
  1004. package/src/resources/extensions/gsd/prompts/discuss.md +101 -183
  1005. package/src/resources/extensions/gsd/prompts/execute-task.md +42 -67
  1006. package/src/resources/extensions/gsd/prompts/forensics.md +41 -84
  1007. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +29 -39
  1008. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +30 -65
  1009. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +25 -52
  1010. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +36 -36
  1011. package/src/resources/extensions/gsd/prompts/guided-research-project.md +20 -38
  1012. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +1 -1
  1013. package/src/resources/extensions/gsd/prompts/plan-milestone.md +47 -59
  1014. package/src/resources/extensions/gsd/prompts/plan-slice.md +25 -87
  1015. package/src/resources/extensions/gsd/prompts/queue.md +46 -53
  1016. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -5
  1017. package/src/resources/extensions/gsd/prompts/refine-slice.md +23 -23
  1018. package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  1019. package/src/resources/extensions/gsd/prompts/research-slice.md +23 -23
  1020. package/src/resources/extensions/gsd/prompts/rethink.md +10 -10
  1021. package/src/resources/extensions/gsd/prompts/system.md +65 -107
  1022. package/src/resources/extensions/gsd/prompts/triage-captures.md +15 -15
  1023. package/src/resources/extensions/gsd/prompts/validate-milestone.md +24 -24
  1024. package/src/resources/extensions/gsd/prompts/worktree-merge.md +35 -35
  1025. package/src/resources/extensions/gsd/quick.ts +37 -2
  1026. package/src/resources/extensions/gsd/recovery-classification.ts +122 -0
  1027. package/src/resources/extensions/gsd/safety/evidence-collector.ts +11 -2
  1028. package/src/resources/extensions/gsd/slice-cadence.ts +49 -2
  1029. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +23 -9
  1030. package/src/resources/extensions/gsd/state-reconciliation.ts +57 -0
  1031. package/src/resources/extensions/gsd/state.ts +6 -3
  1032. package/src/resources/extensions/gsd/tests/agent-end-retry.test.ts +59 -89
  1033. package/src/resources/extensions/gsd/tests/artifact-retry-cap.test.ts +47 -172
  1034. package/src/resources/extensions/gsd/tests/artifacts-table-preserved-on-cache-invalidate.test.ts +0 -35
  1035. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +7 -1
  1036. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +232 -9
  1037. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +1269 -242
  1038. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +80 -59
  1039. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +119 -2
  1040. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +3 -47
  1041. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +363 -18
  1042. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +175 -11
  1043. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +54 -76
  1044. package/src/resources/extensions/gsd/tests/auto-project-root-env.test.ts +67 -26
  1045. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +184 -2
  1046. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +32 -30
  1047. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +16 -1
  1048. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +32 -128
  1049. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +20 -54
  1050. package/src/resources/extensions/gsd/tests/auto-start-cold-db-bootstrap.test.ts +20 -30
  1051. package/src/resources/extensions/gsd/tests/auto-start-index-lock.test.ts +17 -29
  1052. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +160 -0
  1053. package/src/resources/extensions/gsd/tests/auto-start-time-persistence.test.ts +21 -39
  1054. package/src/resources/extensions/gsd/tests/auto-start-worktree-db-path.test.ts +15 -24
  1055. package/src/resources/extensions/gsd/tests/auto-thinking-restore.test.ts +44 -29
  1056. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +68 -0
  1057. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +39 -51
  1058. package/src/resources/extensions/gsd/tests/auto-wrapup-inflight-guard.test.ts +159 -213
  1059. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +15 -32
  1060. package/src/resources/extensions/gsd/tests/browser-teardown.test.ts +0 -41
  1061. package/src/resources/extensions/gsd/tests/clean-root-preflight.test.ts +97 -2
  1062. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +34 -27
  1063. package/src/resources/extensions/gsd/tests/cmux.test.ts +51 -53
  1064. package/src/resources/extensions/gsd/tests/cold-resume-db-reopen.test.ts +39 -61
  1065. package/src/resources/extensions/gsd/tests/commands-config.test.ts +26 -19
  1066. package/src/resources/extensions/gsd/tests/commands-eval-review.test.ts +2 -2
  1067. package/src/resources/extensions/gsd/tests/commands-extract-learnings.test.ts +9 -0
  1068. package/src/resources/extensions/gsd/tests/commands-ship-eval-warn.test.ts +3 -2
  1069. package/src/resources/extensions/gsd/tests/compaction-snapshot.test.ts +14 -1
  1070. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +31 -0
  1071. package/src/resources/extensions/gsd/tests/complete-milestone-prompt-rendering.test.ts +47 -0
  1072. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +159 -5
  1073. package/src/resources/extensions/gsd/tests/complete-slice-composer.test.ts +3 -2
  1074. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +29 -33
  1075. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +45 -108
  1076. package/src/resources/extensions/gsd/tests/component-loader.test.ts +2 -9
  1077. package/src/resources/extensions/gsd/tests/context-budget.test.ts +10 -1
  1078. package/src/resources/extensions/gsd/tests/context-store.test.ts +7 -1
  1079. package/src/resources/extensions/gsd/tests/crash-handler-secondary.test.ts +90 -31
  1080. package/src/resources/extensions/gsd/tests/crash-recovery-via-db.test.ts +22 -0
  1081. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +190 -11
  1082. package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +139 -0
  1083. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +50 -0
  1084. package/src/resources/extensions/gsd/tests/cwd-fallback-hardening.test.ts +138 -0
  1085. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +4 -68
  1086. package/src/resources/extensions/gsd/tests/db-adapter.test.ts +82 -0
  1087. package/src/resources/extensions/gsd/tests/db-base-schema.test.ts +62 -0
  1088. package/src/resources/extensions/gsd/tests/db-connection-cache.test.ts +60 -0
  1089. package/src/resources/extensions/gsd/tests/db-coordination-schema.test.ts +39 -0
  1090. package/src/resources/extensions/gsd/tests/db-decision-requirement-rows.test.ts +135 -0
  1091. package/src/resources/extensions/gsd/tests/db-gate-rows.test.ts +53 -0
  1092. package/src/resources/extensions/gsd/tests/db-lightweight-query-rows.test.ts +45 -0
  1093. package/src/resources/extensions/gsd/tests/db-memory-fts-schema.test.ts +86 -0
  1094. package/src/resources/extensions/gsd/tests/db-migration-backup.test.ts +105 -0
  1095. package/src/resources/extensions/gsd/tests/db-migration-steps.integration.test.ts +428 -0
  1096. package/src/resources/extensions/gsd/tests/db-migration-steps.test.ts +159 -0
  1097. package/src/resources/extensions/gsd/tests/db-milestone-artifact-rows.test.ts +53 -0
  1098. package/src/resources/extensions/gsd/tests/db-open-state.test.ts +56 -0
  1099. package/src/resources/extensions/gsd/tests/db-provider.test.ts +105 -0
  1100. package/src/resources/extensions/gsd/tests/db-runtime-kv-schema.test.ts +37 -0
  1101. package/src/resources/extensions/gsd/tests/db-schema-metadata.test.ts +115 -0
  1102. package/src/resources/extensions/gsd/tests/db-task-slice-rows.test.ts +128 -0
  1103. package/src/resources/extensions/gsd/tests/db-transaction.test.ts +110 -0
  1104. package/src/resources/extensions/gsd/tests/db-verification-evidence-schema.test.ts +76 -0
  1105. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +24 -11
  1106. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +14 -65
  1107. package/src/resources/extensions/gsd/tests/detection.test.ts +140 -0
  1108. package/src/resources/extensions/gsd/tests/discuss-headless-rendering.test.ts +37 -0
  1109. package/src/resources/extensions/gsd/tests/discuss-tool-scoping.test.ts +44 -37
  1110. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +100 -38
  1111. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +25 -15
  1112. package/src/resources/extensions/gsd/tests/dispatch-rule-coverage.test.ts +313 -0
  1113. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +35 -17
  1114. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +16 -21
  1115. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +15 -82
  1116. package/src/resources/extensions/gsd/tests/exec-history.test.ts +15 -0
  1117. package/src/resources/extensions/gsd/tests/exec-sandbox.test.ts +65 -0
  1118. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +62 -0
  1119. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +219 -0
  1120. package/src/resources/extensions/gsd/tests/finalize-survivor-branch.test.ts +151 -0
  1121. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-basic.md +52 -0
  1122. package/src/resources/extensions/gsd/tests/fixtures/pr-body/commands-ship-empty-optionals.md +42 -0
  1123. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +55 -0
  1124. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +60 -0
  1125. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -20
  1126. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +36 -0
  1127. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +18 -26
  1128. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +10 -0
  1129. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +44 -0
  1130. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +43 -0
  1131. package/src/resources/extensions/gsd/tests/guided-discuss-project-prompt-rendering.test.ts +41 -0
  1132. package/src/resources/extensions/gsd/tests/guided-discuss-requirements-prompt-rendering.test.ts +45 -0
  1133. package/src/resources/extensions/gsd/tests/has-pending-deep-stage.test.ts +33 -1
  1134. package/src/resources/extensions/gsd/tests/header-renderer.test.ts +40 -0
  1135. package/src/resources/extensions/gsd/tests/headless-milestone-parity.test.ts +10 -0
  1136. package/src/resources/extensions/gsd/tests/health-widget.test.ts +14 -4
  1137. package/src/resources/extensions/gsd/tests/init-skip-git.test.ts +9 -12
  1138. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +77 -0
  1139. package/src/resources/extensions/gsd/tests/integration/commands-eval-review.integration.test.ts +4 -2
  1140. package/src/resources/extensions/gsd/tests/integration/git-locale.test.ts +31 -20
  1141. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +92 -0
  1142. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +0 -47
  1143. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +116 -24
  1144. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +5 -3
  1145. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +60 -202
  1146. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +13 -56
  1147. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +248 -11
  1148. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +32 -0
  1149. package/src/resources/extensions/gsd/tests/knowledge.test.ts +47 -0
  1150. package/src/resources/extensions/gsd/tests/lazy-pi-tui-import.test.ts +44 -6
  1151. package/src/resources/extensions/gsd/tests/legacy-component-format-telemetry.test.ts +62 -0
  1152. package/src/resources/extensions/gsd/tests/legacy-telemetry.test.ts +144 -0
  1153. package/src/resources/extensions/gsd/tests/memory-decay-factor.test.ts +90 -0
  1154. package/src/resources/extensions/gsd/tests/memory-pressure-stuck-state.test.ts +53 -43
  1155. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +77 -12
  1156. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +48 -0
  1157. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +127 -0
  1158. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +267 -0
  1159. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +88 -98
  1160. package/src/resources/extensions/gsd/tests/model-router.test.ts +33 -12
  1161. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +70 -278
  1162. package/src/resources/extensions/gsd/tests/native-git-bridge-exec-fallback.test.ts +34 -2
  1163. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +37 -30
  1164. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +32 -28
  1165. package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +78 -41
  1166. package/src/resources/extensions/gsd/tests/notification-store.test.ts +8 -0
  1167. package/src/resources/extensions/gsd/tests/notification-widget.test.ts +40 -1
  1168. package/src/resources/extensions/gsd/tests/notifications-handler.test.ts +44 -0
  1169. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +12 -182
  1170. package/src/resources/extensions/gsd/tests/orphan-merge-bootstrap.test.ts +144 -0
  1171. package/src/resources/extensions/gsd/tests/orphan-stash-audit.test.ts +201 -0
  1172. package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +38 -6
  1173. package/src/resources/extensions/gsd/tests/parallel-orchestrator-fast-forward.test.ts +113 -0
  1174. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +24 -37
  1175. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +9 -24
  1176. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +95 -75
  1177. package/src/resources/extensions/gsd/tests/plan-milestone-rendering.test.ts +45 -0
  1178. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +65 -16
  1179. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +50 -0
  1180. package/src/resources/extensions/gsd/tests/plan-task.test.ts +21 -0
  1181. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +2 -2
  1182. package/src/resources/extensions/gsd/tests/post-unit-state-rebuild.test.ts +36 -22
  1183. package/src/resources/extensions/gsd/tests/pr-evidence-equivalence.test.ts +102 -0
  1184. package/src/resources/extensions/gsd/tests/pr-evidence-hardening.test.ts +165 -0
  1185. package/src/resources/extensions/gsd/tests/pr-evidence.test.ts +79 -0
  1186. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +36 -30
  1187. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +45 -5
  1188. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +74 -4
  1189. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +20 -22
  1190. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +130 -32
  1191. package/src/resources/extensions/gsd/tests/process-task-path.test.ts +51 -0
  1192. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +18 -36
  1193. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +35 -73
  1194. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +76 -138
  1195. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +24 -1
  1196. package/src/resources/extensions/gsd/tests/prompt-duplication-cuts.test.ts +230 -0
  1197. package/src/resources/extensions/gsd/tests/prompt-path-audit.test.ts +40 -0
  1198. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +70 -91
  1199. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +59 -161
  1200. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +33 -29
  1201. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +22 -196
  1202. package/src/resources/extensions/gsd/tests/queue-prompt-rendering.test.ts +37 -0
  1203. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +23 -93
  1204. package/src/resources/extensions/gsd/tests/quick-external-gsd.test.ts +40 -0
  1205. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +50 -79
  1206. package/src/resources/extensions/gsd/tests/reassess-default-optin.test.ts +27 -13
  1207. package/src/resources/extensions/gsd/tests/remote-questions.test.ts +151 -251
  1208. package/src/resources/extensions/gsd/tests/resource-loader-import-path.test.ts +41 -29
  1209. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +58 -69
  1210. package/src/resources/extensions/gsd/tests/resume-dispatch-worktree.test.ts +36 -164
  1211. package/src/resources/extensions/gsd/tests/right-sized-workflow-prompts.test.ts +192 -0
  1212. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +57 -41
  1213. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +91 -0
  1214. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +29 -0
  1215. package/src/resources/extensions/gsd/tests/schema-v27-v28-sequence.test.ts +156 -0
  1216. package/src/resources/extensions/gsd/tests/select-resumable-milestone.test.ts +96 -0
  1217. package/src/resources/extensions/gsd/tests/session-model-override.test.ts +14 -9
  1218. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +77 -0
  1219. package/src/resources/extensions/gsd/tests/session-switch-abort-misclassification.test.ts +222 -0
  1220. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +44 -42
  1221. package/src/resources/extensions/gsd/tests/signal-handlers.test.ts +27 -0
  1222. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +56 -24
  1223. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +51 -11
  1224. package/src/resources/extensions/gsd/tests/slice-cadence.test.ts +23 -0
  1225. package/src/resources/extensions/gsd/tests/slice-context-injection.test.ts +66 -50
  1226. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +68 -107
  1227. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +115 -42
  1228. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +21 -59
  1229. package/src/resources/extensions/gsd/tests/smart-entry-draft.test.ts +25 -116
  1230. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +21 -57
  1231. package/src/resources/extensions/gsd/tests/stale-dirlistcache-4648.test.ts +29 -76
  1232. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +33 -24
  1233. package/src/resources/extensions/gsd/tests/stale-slice-rows.test.ts +39 -30
  1234. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +49 -1
  1235. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +101 -2
  1236. package/src/resources/extensions/gsd/tests/state-corruption-2945.test.ts +65 -56
  1237. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +35 -40
  1238. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +48 -46
  1239. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +14 -102
  1240. package/src/resources/extensions/gsd/tests/subagent-model-dispatch.test.ts +78 -232
  1241. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +32 -35
  1242. package/src/resources/extensions/gsd/tests/system-context-memory.test.ts +112 -0
  1243. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +7 -9
  1244. package/src/resources/extensions/gsd/tests/token-profile.test.ts +84 -309
  1245. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +295 -0
  1246. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +32 -9
  1247. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +134 -341
  1248. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +330 -0
  1249. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +66 -0
  1250. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +140 -8
  1251. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +8 -25
  1252. package/src/resources/extensions/gsd/tests/unit-dispatches.test.ts +80 -1
  1253. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +37 -0
  1254. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -99
  1255. package/src/resources/extensions/gsd/tests/uok-kernel-path.test.ts +12 -0
  1256. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +43 -36
  1257. package/src/resources/extensions/gsd/tests/verification-retry-policy.test.ts +83 -0
  1258. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -444
  1259. package/src/resources/extensions/gsd/tests/workflow-custom-engine-dispatch-outcome.test.ts +55 -0
  1260. package/src/resources/extensions/gsd/tests/workflow-custom-engine-iteration.test.ts +93 -0
  1261. package/src/resources/extensions/gsd/tests/workflow-custom-engine-reconcile-outcome.test.ts +108 -0
  1262. package/src/resources/extensions/gsd/tests/workflow-custom-engine-reconcile.test.ts +146 -0
  1263. package/src/resources/extensions/gsd/tests/workflow-custom-engine-retry.test.ts +136 -0
  1264. package/src/resources/extensions/gsd/tests/workflow-custom-engine-verify-outcome.test.ts +95 -0
  1265. package/src/resources/extensions/gsd/tests/workflow-dispatch-claim.test.ts +300 -0
  1266. package/src/resources/extensions/gsd/tests/workflow-dispatch-ledger.test.ts +82 -0
  1267. package/src/resources/extensions/gsd/tests/workflow-iteration-completion.test.ts +44 -0
  1268. package/src/resources/extensions/gsd/tests/workflow-journal-reporter.test.ts +49 -0
  1269. package/src/resources/extensions/gsd/tests/workflow-kernel.test.ts +607 -0
  1270. package/src/resources/extensions/gsd/tests/workflow-logger-wiring.test.ts +44 -189
  1271. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +20 -4
  1272. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +8 -57
  1273. package/src/resources/extensions/gsd/tests/workflow-memory-pressure.test.ts +71 -0
  1274. package/src/resources/extensions/gsd/tests/workflow-phase-reporter.test.ts +40 -0
  1275. package/src/resources/extensions/gsd/tests/workflow-protocol-excerpt.test.ts +99 -0
  1276. package/src/resources/extensions/gsd/tests/workflow-session-lock.test.ts +135 -0
  1277. package/src/resources/extensions/gsd/tests/workflow-sidecar-iteration.test.ts +110 -0
  1278. package/src/resources/extensions/gsd/tests/workflow-sidecar-queue.test.ts +116 -0
  1279. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +21 -0
  1280. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +35 -0
  1281. package/src/resources/extensions/gsd/tests/workflow-turn-reporter.test.ts +87 -0
  1282. package/src/resources/extensions/gsd/tests/workflow-unit-dispatch.test.ts +160 -0
  1283. package/src/resources/extensions/gsd/tests/workflow-worker-heartbeat.test.ts +154 -0
  1284. package/src/resources/extensions/gsd/tests/working-output-messages.test.ts +93 -0
  1285. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +21 -44
  1286. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +27 -26
  1287. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +38 -6
  1288. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +197 -78
  1289. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +888 -0
  1290. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -18
  1291. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +7 -0
  1292. package/src/resources/extensions/gsd/tests/worktree-nested-git-safety.test.ts +9 -2
  1293. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +22 -19
  1294. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +66 -0
  1295. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +327 -0
  1296. package/src/resources/extensions/gsd/tests/worktree-state-projection.test.ts +120 -0
  1297. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +17 -33
  1298. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +59 -2
  1299. package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +179 -0
  1300. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +18 -0
  1301. package/src/resources/extensions/gsd/tests/write-gate.test.ts +40 -1
  1302. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -13
  1303. package/src/resources/extensions/gsd/tool-contract.ts +82 -0
  1304. package/src/resources/extensions/gsd/tools/complete-milestone.ts +29 -24
  1305. package/src/resources/extensions/gsd/tools/complete-task.ts +5 -2
  1306. package/src/resources/extensions/gsd/tools/context-mode-tool-result.ts +25 -0
  1307. package/src/resources/extensions/gsd/tools/exec-search-tool.ts +7 -7
  1308. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -23
  1309. package/src/resources/extensions/gsd/tools/memory-tools.ts +1 -0
  1310. package/src/resources/extensions/gsd/tools/plan-slice.ts +13 -0
  1311. package/src/resources/extensions/gsd/tools/plan-task.ts +10 -0
  1312. package/src/resources/extensions/gsd/tools/resume-tool.ts +7 -7
  1313. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +7 -2
  1314. package/src/resources/extensions/gsd/tui/render-kit.ts +109 -0
  1315. package/src/resources/extensions/gsd/unit-context-composer.ts +19 -4
  1316. package/src/resources/extensions/gsd/unit-runtime.ts +25 -0
  1317. package/src/resources/extensions/gsd/uok/kernel.ts +10 -3
  1318. package/src/resources/extensions/gsd/uok/plan-v2.ts +5 -1
  1319. package/src/resources/extensions/gsd/watch/header-renderer.ts +121 -79
  1320. package/src/resources/extensions/gsd/watch/splash-palette.ts +11 -0
  1321. package/src/resources/extensions/gsd/workflow-logger.ts +13 -13
  1322. package/src/resources/extensions/gsd/workflow-manifest.ts +6 -15
  1323. package/src/resources/extensions/gsd/workflow-mcp.ts +2 -2
  1324. package/src/resources/extensions/gsd/workflow-projections.ts +5 -1
  1325. package/src/resources/extensions/gsd/workflow-protocol.ts +160 -0
  1326. package/src/resources/extensions/gsd/workflow-templates.ts +11 -0
  1327. package/src/resources/extensions/gsd/working-output-messages.ts +120 -0
  1328. package/src/resources/extensions/gsd/worktree-lifecycle.ts +1882 -0
  1329. package/src/resources/extensions/gsd/worktree-manager.ts +15 -4
  1330. package/src/resources/extensions/gsd/worktree-safety.ts +282 -0
  1331. package/src/resources/extensions/gsd/worktree-state-projection.ts +404 -0
  1332. package/src/resources/extensions/gsd/worktree-telemetry.ts +7 -2
  1333. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +86 -40
  1334. package/src/resources/skills/web-quality-audit/scripts/analyze.sh +0 -0
  1335. package/dist/resources/extensions/gsd/worktree-resolver.js +0 -733
  1336. package/dist/web/standalone/.next/server/chunks/6336.js +0 -1
  1337. package/dist/web/standalone/.next/static/chunks/8336.6f6f30e410419aff.js +0 -10
  1338. package/dist/web/standalone/.next/static/chunks/app/page-ff639266d978f2a0.js +0 -1
  1339. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  1340. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  1341. package/src/resources/extensions/gsd/tests/sync-layer-scope.test.ts +0 -434
  1342. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +0 -1247
  1343. package/src/resources/extensions/gsd/worktree-resolver.ts +0 -909
  1344. /package/dist/web/standalone/.next/static/{V-3Ehy4B24f9FCGiLPWIM → F5x9E6H9k_52fjqyql93y}/_buildManifest.js +0 -0
  1345. /package/dist/web/standalone/.next/static/{V-3Ehy4B24f9FCGiLPWIM → F5x9E6H9k_52fjqyql93y}/_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)
@@ -21,6 +23,7 @@
21
23
  // excluded from this invariant.
22
24
 
23
25
  import { createRequire } from "node:module";
26
+ import { createHash } from "node:crypto";
24
27
  import { existsSync, copyFileSync, mkdirSync, realpathSync } from "node:fs";
25
28
  import { dirname } from "node:path";
26
29
  import type { Decision, Requirement, GateRow, GateId, GateScope, GateStatus, GateVerdict } from "./types.js";
@@ -28,315 +31,85 @@ import { GSDError, GSD_STALE_STATE } from "./errors.js";
28
31
  import type { GsdWorkspace, MilestoneScope } from "./workspace.js";
29
32
  import { getGateIdsForTurn, type OwnerTurn } from "./gate-registry.js";
30
33
  import { logError, logWarning } from "./workflow-logger.js";
34
+ import { createDbAdapter, type DbAdapter } from "./db-adapter.js";
35
+ import { createBaseSchemaObjects } from "./db-base-schema.js";
36
+ import { createCoordinationTablesV24 } from "./db-coordination-schema.js";
37
+ import { createDbConnectionCache, type DbConnectionCacheEntry } from "./db-connection-cache.js";
38
+ import {
39
+ emptyTaskStatusCounts,
40
+ rowToActiveTaskSummary,
41
+ rowToIdStatusSummary,
42
+ rowToTaskStatusCounts,
43
+ rowsToStringColumn,
44
+ type ActiveTaskSummary,
45
+ type IdStatusSummary,
46
+ type TaskStatusCounts,
47
+ } from "./db-lightweight-query-rows.js";
48
+ import {
49
+ rowToActiveDecision,
50
+ rowToActiveRequirement,
51
+ rowToDecision,
52
+ rowToRequirement,
53
+ rowsToRequirementCounts,
54
+ } from "./db-decision-requirement-rows.js";
55
+ import { rowToGate } from "./db-gate-rows.js";
56
+ import { rowToArtifact, rowToMilestone, type ArtifactRow, type MilestoneRow } from "./db-milestone-artifact-rows.js";
57
+ import { backupDatabaseBeforeMigration } from "./db-migration-backup.js";
58
+ import {
59
+ applyMigrationV2Artifacts,
60
+ applyMigrationV3Memories,
61
+ applyMigrationV4DecisionMadeBy,
62
+ applyMigrationV5HierarchyTables,
63
+ applyMigrationV6SliceSummaries,
64
+ applyMigrationV7Dependencies,
65
+ applyMigrationV8PlanningFields,
66
+ applyMigrationV9Ordering,
67
+ applyMigrationV10ReplanTrigger,
68
+ applyMigrationV11TaskPlanning,
69
+ applyMigrationV12QualityGates,
70
+ applyMigrationV13HotPathIndexes,
71
+ applyMigrationV14SliceDependencies,
72
+ applyMigrationV15AuditTables,
73
+ applyMigrationV16EscalationSource,
74
+ applyMigrationV17TaskEscalation,
75
+ applyMigrationV18MemorySources,
76
+ applyMigrationV19MemoryFts,
77
+ applyMigrationV20MemoryRelations,
78
+ applyMigrationV21StructuredMemories,
79
+ applyMigrationV22QualityGateRepair,
80
+ applyMigrationV23MilestoneQueue,
81
+ applyMigrationV26MilestoneCommitAttributions,
82
+ applyMigrationV27ArtifactHash,
83
+ applyMigrationV28MemoryLastHitAt,
84
+ } from "./db-migration-steps.js";
85
+ import { isMemoriesFtsAvailableSchema, tryCreateMemoriesFtsSchema } from "./db-memory-fts-schema.js";
86
+ import { createDbOpenState, type DbOpenPhase } from "./db-open-state.js";
87
+ import { createRuntimeKvTableV25 } from "./db-runtime-kv-schema.js";
88
+ import { ensureColumn, getCurrentSchemaVersion, recordSchemaVersion } from "./db-schema-metadata.js";
89
+ import { rowToSlice, rowToTask, type SliceRow, type TaskRow } from "./db-task-slice-rows.js";
90
+ import { createDbTransactionRunner } from "./db-transaction.js";
91
+ import { ensureVerificationEvidenceDedupIndex } from "./db-verification-evidence-schema.js";
92
+ import { createSqliteProviderLoader, suppressSqliteWarning, type DbProviderName, type SqliteFallbackOpen } from "./db-provider.js";
31
93
  // Type-only import to avoid a circular runtime dep. The runtime side of
32
94
  // workflow-manifest.ts depends on this file, but the StateManifest type is
33
95
  // pure structure with no runtime coupling.
34
96
  import type { StateManifest } from "./workflow-manifest.js";
35
97
 
36
98
  const _require = createRequire(import.meta.url);
37
- const BETTER_SQLITE3_PACKAGE = ["better", "sqlite3"].join("-");
38
-
39
- interface DbStatement {
40
- run(...params: unknown[]): unknown;
41
- get(...params: unknown[]): Record<string, unknown> | undefined;
42
- all(...params: unknown[]): Record<string, unknown>[];
43
- }
44
-
45
- interface DbAdapter {
46
- exec(sql: string): void;
47
- prepare(sql: string): DbStatement;
48
- close(): void;
49
- }
50
-
51
- type ProviderName = "node:sqlite" | "better-sqlite3";
52
-
53
- let providerName: ProviderName | null = null;
54
- let providerModule: unknown = null;
55
- let loadAttempted = false;
56
-
57
- function suppressSqliteWarning(): void {
58
- const origEmit = process.emit;
59
- // Override via loose cast: Node's overloaded emit signature is not directly assignable.
60
- (process as any).emit = function (event: string, ...args: unknown[]): boolean {
61
- if (
62
- event === "warning" &&
63
- args[0] &&
64
- typeof args[0] === "object" &&
65
- "name" in args[0] &&
66
- (args[0] as { name: string }).name === "ExperimentalWarning" &&
67
- "message" in args[0] &&
68
- typeof (args[0] as { message: string }).message === "string" &&
69
- (args[0] as { message: string }).message.includes("SQLite")
70
- ) {
71
- return false;
72
- }
73
- return origEmit.apply(process, [event, ...args] as Parameters<typeof process.emit>) as unknown as boolean;
74
- };
75
- }
76
-
77
- function loadProvider(): void {
78
- if (loadAttempted) return;
79
- loadAttempted = true;
80
-
81
- try {
82
- suppressSqliteWarning();
83
- const mod = _require("node:sqlite");
84
- if (mod.DatabaseSync) {
85
- providerModule = mod;
86
- providerName = "node:sqlite";
87
- return;
88
- }
89
- } catch {
90
- // unavailable
91
- }
92
-
93
- try {
94
- const mod = _require(BETTER_SQLITE3_PACKAGE);
95
- if (typeof mod === "function" || (mod && mod.default)) {
96
- providerModule = mod.default || mod;
97
- providerName = "better-sqlite3";
98
- return;
99
- }
100
- } catch {
101
- // unavailable
102
- }
103
-
104
- const nodeMajor = parseInt(process.versions.node.split(".")[0], 10);
105
- const versionHint = nodeMajor < 22
106
- ? ` GSD requires Node >= 22.0.0 (current: v${process.versions.node}). Upgrade Node to fix this.`
107
- : "";
108
- process.stderr.write(
109
- `gsd-db: No SQLite provider available (tried node:sqlite, better-sqlite3).${versionHint}\n`,
110
- );
111
- }
99
+ type ProviderName = DbProviderName;
112
100
 
113
- function normalizeRow(row: unknown): Record<string, unknown> | undefined {
114
- if (row == null) return undefined;
115
- if (Object.getPrototypeOf(row) === null) {
116
- return { ...(row as Record<string, unknown>) };
117
- }
118
- return row as Record<string, unknown>;
119
- }
101
+ export type { ArtifactRow, MilestoneRow } from "./db-milestone-artifact-rows.js";
102
+ export type { ActiveTaskSummary, IdStatusSummary, TaskStatusCounts } from "./db-lightweight-query-rows.js";
103
+ export type { SliceRow, TaskRow } from "./db-task-slice-rows.js";
120
104
 
121
- function normalizeRows(rows: unknown[]): Record<string, unknown>[] {
122
- return rows.map((r) => normalizeRow(r)!);
123
- }
105
+ const providerLoader = createSqliteProviderLoader({
106
+ requireModule: (id: string) => _require(id),
107
+ suppressSqliteWarning,
108
+ nodeVersion: process.versions.node,
109
+ writeStderr: (message: string) => process.stderr.write(message),
110
+ });
124
111
 
125
- function createAdapter(rawDb: unknown): DbAdapter {
126
- const db = rawDb as {
127
- exec(sql: string): void;
128
- prepare(sql: string): {
129
- run(...args: unknown[]): unknown;
130
- get(...args: unknown[]): unknown;
131
- all(...args: unknown[]): unknown[];
132
- };
133
- close(): void;
134
- };
135
-
136
- const stmtCache = new Map<string, DbStatement>();
137
-
138
- function wrapStmt(raw: { run(...a: unknown[]): unknown; get(...a: unknown[]): unknown; all(...a: unknown[]): unknown[] }): DbStatement {
139
- return {
140
- run(...params: unknown[]): unknown {
141
- return raw.run(...params);
142
- },
143
- get(...params: unknown[]): Record<string, unknown> | undefined {
144
- return normalizeRow(raw.get(...params));
145
- },
146
- all(...params: unknown[]): Record<string, unknown>[] {
147
- return normalizeRows(raw.all(...params));
148
- },
149
- };
150
- }
151
-
152
- return {
153
- exec(sql: string): void {
154
- db.exec(sql);
155
- },
156
- prepare(sql: string): DbStatement {
157
- let cached = stmtCache.get(sql);
158
- if (cached) return cached;
159
- cached = wrapStmt(db.prepare(sql));
160
- stmtCache.set(sql, cached);
161
- return cached;
162
- },
163
- close(): void {
164
- stmtCache.clear();
165
- db.close();
166
- },
167
- };
168
- }
169
-
170
- function openRawDb(path: string): unknown {
171
- loadProvider();
172
- if (!providerModule || !providerName) return null;
173
-
174
- if (providerName === "node:sqlite") {
175
- const { DatabaseSync } = providerModule as {
176
- DatabaseSync: new (path: string) => unknown;
177
- };
178
- return new DatabaseSync(path);
179
- }
180
-
181
- const Database = providerModule as new (path: string) => unknown;
182
- return new Database(path);
183
- }
184
-
185
- export const SCHEMA_VERSION = 25;
186
-
187
- function indexExists(db: DbAdapter, name: string): boolean {
188
- return !!db.prepare(
189
- "SELECT 1 as present FROM sqlite_master WHERE type = 'index' AND name = ?",
190
- ).get(name);
191
- }
192
-
193
- /**
194
- * Create the v24 coordination tables (workers, milestone_leases,
195
- * unit_dispatches, cancellation_requests, command_queue) and their indexes.
196
- *
197
- * Idempotent — uses IF NOT EXISTS throughout. Called from both the
198
- * fresh-install path and the v24 migration block in migrateSchema().
199
- *
200
- * Single-host invariant: these tables coordinate concurrent auto-mode
201
- * workers via shared SQLite WAL on local disk only. NFS / network
202
- * filesystems break the coordination semantics — multi-host execution
203
- * needs a real coordinator (etcd, Postgres) and is out of scope.
204
- */
205
- function createCoordinationTablesV24(db: DbAdapter): void {
206
- const ddl = [
207
- `CREATE TABLE IF NOT EXISTS workers (
208
- worker_id TEXT PRIMARY KEY,
209
- host TEXT NOT NULL,
210
- pid INTEGER NOT NULL,
211
- started_at TEXT NOT NULL,
212
- version TEXT NOT NULL,
213
- last_heartbeat_at TEXT NOT NULL,
214
- status TEXT NOT NULL,
215
- project_root_realpath TEXT NOT NULL
216
- )`,
217
- `CREATE TABLE IF NOT EXISTS milestone_leases (
218
- milestone_id TEXT PRIMARY KEY,
219
- worker_id TEXT NOT NULL,
220
- fencing_token INTEGER NOT NULL,
221
- acquired_at TEXT NOT NULL,
222
- expires_at TEXT NOT NULL,
223
- status TEXT NOT NULL,
224
- FOREIGN KEY (worker_id) REFERENCES workers(worker_id),
225
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
226
- )`,
227
- `CREATE TABLE IF NOT EXISTS unit_dispatches (
228
- id INTEGER PRIMARY KEY AUTOINCREMENT,
229
- trace_id TEXT NOT NULL,
230
- turn_id TEXT,
231
- worker_id TEXT NOT NULL,
232
- milestone_lease_token INTEGER NOT NULL,
233
- milestone_id TEXT NOT NULL,
234
- slice_id TEXT,
235
- task_id TEXT,
236
- unit_type TEXT NOT NULL,
237
- unit_id TEXT NOT NULL,
238
- status TEXT NOT NULL,
239
- attempt_n INTEGER NOT NULL DEFAULT 1,
240
- started_at TEXT NOT NULL,
241
- ended_at TEXT,
242
- exit_reason TEXT,
243
- error_summary TEXT,
244
- verification_evidence_id INTEGER,
245
- next_run_at TEXT,
246
- retry_after_ms INTEGER,
247
- max_attempts INTEGER NOT NULL DEFAULT 3,
248
- last_error_code TEXT,
249
- last_error_at TEXT,
250
- FOREIGN KEY (worker_id) REFERENCES workers(worker_id),
251
- FOREIGN KEY (verification_evidence_id) REFERENCES verification_evidence(id)
252
- )`,
253
- `CREATE TABLE IF NOT EXISTS cancellation_requests (
254
- id INTEGER PRIMARY KEY AUTOINCREMENT,
255
- requested_at TEXT NOT NULL,
256
- requested_by TEXT NOT NULL,
257
- scope TEXT NOT NULL,
258
- scope_id TEXT NOT NULL,
259
- dispatch_id INTEGER,
260
- reason TEXT NOT NULL,
261
- status TEXT NOT NULL,
262
- acked_at TEXT,
263
- acked_worker_id TEXT,
264
- FOREIGN KEY (dispatch_id) REFERENCES unit_dispatches(id),
265
- FOREIGN KEY (acked_worker_id) REFERENCES workers(worker_id)
266
- )`,
267
- `CREATE TABLE IF NOT EXISTS command_queue (
268
- id INTEGER PRIMARY KEY AUTOINCREMENT,
269
- target_worker TEXT,
270
- command TEXT NOT NULL,
271
- args_json TEXT NOT NULL DEFAULT '{}',
272
- enqueued_at TEXT NOT NULL,
273
- claimed_at TEXT,
274
- claimed_by TEXT,
275
- completed_at TEXT,
276
- result_json TEXT
277
- )`,
278
- ];
279
- for (const stmt of ddl) db.exec(stmt);
280
-
281
- // Indexes — created here so both fresh-install and v24-migration paths
282
- // produce identical structure.
283
- db.exec("CREATE INDEX IF NOT EXISTS idx_unit_dispatches_active ON unit_dispatches(milestone_id, status)");
284
- db.exec("CREATE INDEX IF NOT EXISTS idx_unit_dispatches_trace ON unit_dispatches(trace_id, turn_id)");
285
- // Partial unique index — prevents two workers from claiming the same
286
- // unit concurrently. Codex review MEDIUM B2: enforces double-claim guard
287
- // at the DB level.
288
- db.exec(
289
- "CREATE UNIQUE INDEX IF NOT EXISTS idx_unit_dispatches_active_per_unit "
290
- + "ON unit_dispatches(unit_id) WHERE status IN ('claimed','running')",
291
- );
292
- // command_queue index — SQLite indexes NULLs in B-trees, so this single
293
- // index serves both targeted (target_worker = ?) and broadcast
294
- // (target_worker IS NULL) queries. Codex review LOW B4 documented.
295
- db.exec("CREATE INDEX IF NOT EXISTS idx_command_queue_pending ON command_queue(target_worker, claimed_at)");
296
- }
297
-
298
- /**
299
- * Create the v25 runtime_kv table. Idempotent — uses IF NOT EXISTS.
300
- *
301
- * STRICT INVARIANT: runtime_kv is NON-CORRECTNESS-CRITICAL. UI cursors,
302
- * dashboard caches, last-seen-version markers, resume cursors, and other
303
- * "soft" state are OK. Anything that drives auto-mode control flow gets
304
- * typed columns in unit_dispatches / workers / milestone_leases — never
305
- * a bag of JSON in runtime_kv.
306
- *
307
- * Scope partitioning: ('global', '', key) for project-wide values;
308
- * ('worker', worker_id, key) for per-worker state (resume cursors);
309
- * ('milestone', milestone_id, key) for per-milestone soft state.
310
- */
311
- function createRuntimeKvTableV25(db: DbAdapter): void {
312
- db.exec(`
313
- CREATE TABLE IF NOT EXISTS runtime_kv (
314
- scope TEXT NOT NULL,
315
- scope_id TEXT NOT NULL DEFAULT '',
316
- key TEXT NOT NULL,
317
- value_json TEXT NOT NULL,
318
- updated_at TEXT NOT NULL,
319
- PRIMARY KEY (scope, scope_id, key)
320
- )
321
- `);
322
- }
323
-
324
- function dedupeVerificationEvidenceRows(db: DbAdapter): void {
325
- db.exec(`
326
- DELETE FROM verification_evidence
327
- WHERE rowid NOT IN (
328
- SELECT MIN(rowid)
329
- FROM verification_evidence
330
- GROUP BY task_id, slice_id, milestone_id, command, verdict
331
- )
332
- `);
333
- }
334
-
335
- function ensureVerificationEvidenceDedupIndex(db: DbAdapter): void {
336
- if (indexExists(db, "idx_verification_evidence_dedup")) return;
337
- dedupeVerificationEvidenceRows(db);
338
- db.exec("CREATE UNIQUE INDEX IF NOT EXISTS idx_verification_evidence_dedup ON verification_evidence(task_id, slice_id, milestone_id, command, verdict)");
339
- }
112
+ export const SCHEMA_VERSION = 28;
340
113
 
341
114
  function initSchema(db: DbAdapter, fileBacked: boolean): void {
342
115
  if (fileBacked) db.exec("PRAGMA journal_mode=WAL");
@@ -350,370 +123,10 @@ function initSchema(db: DbAdapter, fileBacked: boolean): void {
350
123
 
351
124
  db.exec("BEGIN");
352
125
  try {
353
- db.exec(`
354
- CREATE TABLE IF NOT EXISTS schema_version (
355
- version INTEGER NOT NULL,
356
- applied_at TEXT NOT NULL
357
- )
358
- `);
359
-
360
- db.exec(`
361
- CREATE TABLE IF NOT EXISTS decisions (
362
- seq INTEGER PRIMARY KEY AUTOINCREMENT,
363
- id TEXT NOT NULL UNIQUE,
364
- when_context TEXT NOT NULL DEFAULT '',
365
- scope TEXT NOT NULL DEFAULT '',
366
- decision TEXT NOT NULL DEFAULT '',
367
- choice TEXT NOT NULL DEFAULT '',
368
- rationale TEXT NOT NULL DEFAULT '',
369
- revisable TEXT NOT NULL DEFAULT '',
370
- made_by TEXT NOT NULL DEFAULT 'agent',
371
- source TEXT NOT NULL DEFAULT 'discussion', -- ADR-011 P2: 'discussion' | 'planning' | 'escalation'
372
- superseded_by TEXT DEFAULT NULL
373
- )
374
- `);
375
-
376
- db.exec(`
377
- CREATE TABLE IF NOT EXISTS requirements (
378
- id TEXT PRIMARY KEY,
379
- class TEXT NOT NULL DEFAULT '',
380
- status TEXT NOT NULL DEFAULT '',
381
- description TEXT NOT NULL DEFAULT '',
382
- why TEXT NOT NULL DEFAULT '',
383
- source TEXT NOT NULL DEFAULT '',
384
- primary_owner TEXT NOT NULL DEFAULT '',
385
- supporting_slices TEXT NOT NULL DEFAULT '',
386
- validation TEXT NOT NULL DEFAULT '',
387
- notes TEXT NOT NULL DEFAULT '',
388
- full_content TEXT NOT NULL DEFAULT '',
389
- superseded_by TEXT DEFAULT NULL
390
- )
391
- `);
392
-
393
- db.exec(`
394
- CREATE TABLE IF NOT EXISTS artifacts (
395
- path TEXT PRIMARY KEY,
396
- artifact_type TEXT NOT NULL DEFAULT '',
397
- milestone_id TEXT DEFAULT NULL,
398
- slice_id TEXT DEFAULT NULL,
399
- task_id TEXT DEFAULT NULL,
400
- full_content TEXT NOT NULL DEFAULT '',
401
- imported_at TEXT NOT NULL DEFAULT ''
402
- )
403
- `);
404
-
405
- db.exec(`
406
- CREATE TABLE IF NOT EXISTS memories (
407
- seq INTEGER PRIMARY KEY AUTOINCREMENT,
408
- id TEXT NOT NULL UNIQUE,
409
- category TEXT NOT NULL,
410
- content TEXT NOT NULL,
411
- confidence REAL NOT NULL DEFAULT 0.8,
412
- source_unit_type TEXT,
413
- source_unit_id TEXT,
414
- created_at TEXT NOT NULL,
415
- updated_at TEXT NOT NULL,
416
- superseded_by TEXT DEFAULT NULL,
417
- hit_count INTEGER NOT NULL DEFAULT 0,
418
- scope TEXT NOT NULL DEFAULT 'project',
419
- tags TEXT NOT NULL DEFAULT '[]',
420
- structured_fields TEXT DEFAULT NULL
421
- )
422
- `);
423
-
424
- db.exec(`
425
- CREATE TABLE IF NOT EXISTS memory_processed_units (
426
- unit_key TEXT PRIMARY KEY,
427
- activity_file TEXT,
428
- processed_at TEXT NOT NULL
429
- )
430
- `);
431
-
432
- db.exec(`
433
- CREATE TABLE IF NOT EXISTS memory_sources (
434
- id TEXT PRIMARY KEY,
435
- kind TEXT NOT NULL,
436
- uri TEXT,
437
- title TEXT,
438
- content TEXT NOT NULL,
439
- content_hash TEXT NOT NULL UNIQUE,
440
- imported_at TEXT NOT NULL,
441
- scope TEXT NOT NULL DEFAULT 'project',
442
- tags TEXT NOT NULL DEFAULT '[]'
443
- )
444
- `);
445
-
446
- db.exec(`
447
- CREATE TABLE IF NOT EXISTS memory_embeddings (
448
- memory_id TEXT PRIMARY KEY,
449
- model TEXT NOT NULL,
450
- dim INTEGER NOT NULL,
451
- vector BLOB NOT NULL,
452
- updated_at TEXT NOT NULL
453
- )
454
- `);
455
-
456
- db.exec(`
457
- CREATE TABLE IF NOT EXISTS memory_relations (
458
- from_id TEXT NOT NULL,
459
- to_id TEXT NOT NULL,
460
- rel TEXT NOT NULL,
461
- confidence REAL NOT NULL DEFAULT 0.8,
462
- created_at TEXT NOT NULL,
463
- PRIMARY KEY (from_id, to_id, rel)
464
- )
465
- `);
466
-
467
- // FTS5 virtual table mirroring memories.content for fast keyword search.
468
- // Optional — if the SQLite build lacks FTS5, we fall back to LIKE scans.
469
- tryCreateMemoriesFts(db);
470
-
471
- db.exec(`
472
- CREATE TABLE IF NOT EXISTS milestones (
473
- id TEXT PRIMARY KEY,
474
- title TEXT NOT NULL DEFAULT '',
475
- status TEXT NOT NULL DEFAULT 'active',
476
- depends_on TEXT NOT NULL DEFAULT '[]',
477
- created_at TEXT NOT NULL DEFAULT '',
478
- completed_at TEXT DEFAULT NULL,
479
- vision TEXT NOT NULL DEFAULT '',
480
- success_criteria TEXT NOT NULL DEFAULT '[]',
481
- key_risks TEXT NOT NULL DEFAULT '[]',
482
- proof_strategy TEXT NOT NULL DEFAULT '[]',
483
- verification_contract TEXT NOT NULL DEFAULT '',
484
- verification_integration TEXT NOT NULL DEFAULT '',
485
- verification_operational TEXT NOT NULL DEFAULT '',
486
- verification_uat TEXT NOT NULL DEFAULT '',
487
- definition_of_done TEXT NOT NULL DEFAULT '[]',
488
- requirement_coverage TEXT NOT NULL DEFAULT '',
489
- boundary_map_markdown TEXT NOT NULL DEFAULT '',
490
- sequence INTEGER DEFAULT 0
491
- )
492
- `);
493
-
494
- db.exec(`
495
- CREATE TABLE IF NOT EXISTS slices (
496
- milestone_id TEXT NOT NULL,
497
- id TEXT NOT NULL,
498
- title TEXT NOT NULL DEFAULT '',
499
- status TEXT NOT NULL DEFAULT 'pending',
500
- risk TEXT NOT NULL DEFAULT 'medium',
501
- depends TEXT NOT NULL DEFAULT '[]',
502
- demo TEXT NOT NULL DEFAULT '',
503
- created_at TEXT NOT NULL DEFAULT '',
504
- completed_at TEXT DEFAULT NULL,
505
- full_summary_md TEXT NOT NULL DEFAULT '',
506
- full_uat_md TEXT NOT NULL DEFAULT '',
507
- goal TEXT NOT NULL DEFAULT '',
508
- success_criteria TEXT NOT NULL DEFAULT '',
509
- proof_level TEXT NOT NULL DEFAULT '',
510
- integration_closure TEXT NOT NULL DEFAULT '',
511
- observability_impact TEXT NOT NULL DEFAULT '',
512
- sequence INTEGER DEFAULT 0, -- Ordering hint: tools may set this to control execution order
513
- replan_triggered_at TEXT DEFAULT NULL,
514
- is_sketch INTEGER NOT NULL DEFAULT 0, -- ADR-011: 1 = slice is a sketch awaiting refinement
515
- sketch_scope TEXT NOT NULL DEFAULT '', -- ADR-011: 2-3 sentence rough scope from plan-milestone
516
- PRIMARY KEY (milestone_id, id),
517
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
518
- )
519
- `);
520
-
521
- db.exec(`
522
- CREATE TABLE IF NOT EXISTS tasks (
523
- milestone_id TEXT NOT NULL,
524
- slice_id TEXT NOT NULL,
525
- id TEXT NOT NULL,
526
- title TEXT NOT NULL DEFAULT '',
527
- status TEXT NOT NULL DEFAULT 'pending',
528
- one_liner TEXT NOT NULL DEFAULT '',
529
- narrative TEXT NOT NULL DEFAULT '',
530
- verification_result TEXT NOT NULL DEFAULT '',
531
- duration TEXT NOT NULL DEFAULT '',
532
- completed_at TEXT DEFAULT NULL,
533
- blocker_discovered INTEGER DEFAULT 0,
534
- blocker_source TEXT NOT NULL DEFAULT '', -- ADR-011 P2: provenance for blocker_discovered (e.g. 'reject-escalation')
535
- escalation_pending INTEGER NOT NULL DEFAULT 0, -- ADR-011 P2: pause-on-escalation flag
536
- escalation_awaiting_review INTEGER NOT NULL DEFAULT 0, -- ADR-011 P2: artifact exists but continueWithDefault=true (no pause)
537
- escalation_artifact_path TEXT DEFAULT NULL, -- ADR-011 P2: path to T##-ESCALATION.json
538
- escalation_override_applied_at TEXT DEFAULT NULL, -- ADR-011 P2: DB claim lock for idempotent override injection
539
- deviations TEXT NOT NULL DEFAULT '',
540
- known_issues TEXT NOT NULL DEFAULT '',
541
- key_files TEXT NOT NULL DEFAULT '[]',
542
- key_decisions TEXT NOT NULL DEFAULT '[]',
543
- full_summary_md TEXT NOT NULL DEFAULT '',
544
- description TEXT NOT NULL DEFAULT '',
545
- estimate TEXT NOT NULL DEFAULT '',
546
- files TEXT NOT NULL DEFAULT '[]',
547
- verify TEXT NOT NULL DEFAULT '',
548
- inputs TEXT NOT NULL DEFAULT '[]',
549
- expected_output TEXT NOT NULL DEFAULT '[]',
550
- observability_impact TEXT NOT NULL DEFAULT '',
551
- full_plan_md TEXT NOT NULL DEFAULT '',
552
- sequence INTEGER DEFAULT 0, -- Ordering hint: tools may set this to control execution order
553
- PRIMARY KEY (milestone_id, slice_id, id),
554
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
555
- )
556
- `);
557
-
558
- db.exec(`
559
- CREATE TABLE IF NOT EXISTS verification_evidence (
560
- id INTEGER PRIMARY KEY AUTOINCREMENT,
561
- task_id TEXT NOT NULL DEFAULT '',
562
- slice_id TEXT NOT NULL DEFAULT '',
563
- milestone_id TEXT NOT NULL DEFAULT '',
564
- command TEXT NOT NULL DEFAULT '',
565
- exit_code INTEGER DEFAULT 0,
566
- verdict TEXT NOT NULL DEFAULT '',
567
- duration_ms INTEGER DEFAULT 0,
568
- created_at TEXT NOT NULL DEFAULT '',
569
- FOREIGN KEY (milestone_id, slice_id, task_id) REFERENCES tasks(milestone_id, slice_id, id)
570
- )
571
- `);
572
-
573
- db.exec(`
574
- CREATE TABLE IF NOT EXISTS replan_history (
575
- id INTEGER PRIMARY KEY AUTOINCREMENT,
576
- milestone_id TEXT NOT NULL DEFAULT '',
577
- slice_id TEXT DEFAULT NULL,
578
- task_id TEXT DEFAULT NULL,
579
- summary TEXT NOT NULL DEFAULT '',
580
- previous_artifact_path TEXT DEFAULT NULL,
581
- replacement_artifact_path TEXT DEFAULT NULL,
582
- created_at TEXT NOT NULL DEFAULT '',
583
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
584
- )
585
- `);
586
-
587
- db.exec(`
588
- CREATE TABLE IF NOT EXISTS assessments (
589
- path TEXT PRIMARY KEY,
590
- milestone_id TEXT NOT NULL DEFAULT '',
591
- slice_id TEXT DEFAULT NULL,
592
- task_id TEXT DEFAULT NULL,
593
- status TEXT NOT NULL DEFAULT '',
594
- scope TEXT NOT NULL DEFAULT '',
595
- full_content TEXT NOT NULL DEFAULT '',
596
- created_at TEXT NOT NULL DEFAULT '',
597
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
598
- )
599
- `);
600
-
601
- db.exec(`
602
- CREATE TABLE IF NOT EXISTS quality_gates (
603
- milestone_id TEXT NOT NULL,
604
- slice_id TEXT NOT NULL,
605
- gate_id TEXT NOT NULL,
606
- scope TEXT NOT NULL DEFAULT 'slice',
607
- task_id TEXT NOT NULL DEFAULT '',
608
- status TEXT NOT NULL DEFAULT 'pending',
609
- verdict TEXT NOT NULL DEFAULT '',
610
- rationale TEXT NOT NULL DEFAULT '',
611
- findings TEXT NOT NULL DEFAULT '',
612
- evaluated_at TEXT DEFAULT NULL,
613
- PRIMARY KEY (milestone_id, slice_id, gate_id, task_id),
614
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
615
- )
616
- `);
617
-
618
- // Slice dependency junction table (v14)
619
- db.exec(`
620
- CREATE TABLE IF NOT EXISTS slice_dependencies (
621
- milestone_id TEXT NOT NULL,
622
- slice_id TEXT NOT NULL,
623
- depends_on_slice_id TEXT NOT NULL,
624
- PRIMARY KEY (milestone_id, slice_id, depends_on_slice_id),
625
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id),
626
- FOREIGN KEY (milestone_id, depends_on_slice_id) REFERENCES slices(milestone_id, id)
627
- )
628
- `);
629
-
630
- db.exec(`
631
- CREATE TABLE IF NOT EXISTS gate_runs (
632
- id INTEGER PRIMARY KEY AUTOINCREMENT,
633
- trace_id TEXT NOT NULL,
634
- turn_id TEXT NOT NULL,
635
- gate_id TEXT NOT NULL,
636
- gate_type TEXT NOT NULL DEFAULT '',
637
- unit_type TEXT DEFAULT NULL,
638
- unit_id TEXT DEFAULT NULL,
639
- milestone_id TEXT DEFAULT NULL,
640
- slice_id TEXT DEFAULT NULL,
641
- task_id TEXT DEFAULT NULL,
642
- outcome TEXT NOT NULL DEFAULT 'pass',
643
- failure_class TEXT NOT NULL DEFAULT 'none',
644
- rationale TEXT NOT NULL DEFAULT '',
645
- findings TEXT NOT NULL DEFAULT '',
646
- attempt INTEGER NOT NULL DEFAULT 1,
647
- max_attempts INTEGER NOT NULL DEFAULT 1,
648
- retryable INTEGER NOT NULL DEFAULT 0,
649
- evaluated_at TEXT NOT NULL DEFAULT ''
650
- )
651
- `);
652
-
653
- db.exec(`
654
- CREATE TABLE IF NOT EXISTS turn_git_transactions (
655
- trace_id TEXT NOT NULL,
656
- turn_id TEXT NOT NULL,
657
- unit_type TEXT DEFAULT NULL,
658
- unit_id TEXT DEFAULT NULL,
659
- stage TEXT NOT NULL DEFAULT 'turn-start',
660
- action TEXT NOT NULL DEFAULT 'status-only',
661
- push INTEGER NOT NULL DEFAULT 0,
662
- status TEXT NOT NULL DEFAULT 'ok',
663
- error TEXT DEFAULT NULL,
664
- metadata_json TEXT NOT NULL DEFAULT '{}',
665
- updated_at TEXT NOT NULL DEFAULT '',
666
- PRIMARY KEY (trace_id, turn_id, stage)
667
- )
668
- `);
669
-
670
- db.exec(`
671
- CREATE TABLE IF NOT EXISTS audit_events (
672
- event_id TEXT PRIMARY KEY,
673
- trace_id TEXT NOT NULL,
674
- turn_id TEXT DEFAULT NULL,
675
- caused_by TEXT DEFAULT NULL,
676
- category TEXT NOT NULL,
677
- type TEXT NOT NULL,
678
- ts TEXT NOT NULL,
679
- payload_json TEXT NOT NULL DEFAULT '{}'
680
- )
681
- `);
682
-
683
- db.exec(`
684
- CREATE TABLE IF NOT EXISTS audit_turn_index (
685
- trace_id TEXT NOT NULL,
686
- turn_id TEXT NOT NULL,
687
- first_ts TEXT NOT NULL,
688
- last_ts TEXT NOT NULL,
689
- event_count INTEGER NOT NULL DEFAULT 0,
690
- PRIMARY KEY (trace_id, turn_id)
691
- )
692
- `);
693
-
694
- db.exec("CREATE INDEX IF NOT EXISTS idx_memories_active ON memories(superseded_by)");
695
-
696
- db.exec("CREATE INDEX IF NOT EXISTS idx_replan_history_milestone ON replan_history(milestone_id, created_at)");
697
-
698
- // v13 indexes — hot-path dispatch queries
699
- db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_active ON tasks(milestone_id, slice_id, status)");
700
- db.exec("CREATE INDEX IF NOT EXISTS idx_slices_active ON slices(milestone_id, status)");
701
- db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
702
- db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
703
- db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
704
- ensureVerificationEvidenceDedupIndex(db);
705
-
706
- // v14 index — slice dependency lookups
707
- db.exec("CREATE INDEX IF NOT EXISTS idx_slice_deps_target ON slice_dependencies(milestone_id, depends_on_slice_id)");
708
- db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_turn ON gate_runs(trace_id, turn_id)");
709
- db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_lookup ON gate_runs(milestone_id, slice_id, task_id, gate_id)");
710
- db.exec("CREATE INDEX IF NOT EXISTS idx_turn_git_tx_turn ON turn_git_transactions(trace_id, turn_id)");
711
- db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_trace ON audit_events(trace_id, ts)");
712
- db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_turn ON audit_events(trace_id, turn_id, ts)");
713
-
714
- db.exec(`CREATE VIEW IF NOT EXISTS active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL`);
715
- db.exec(`CREATE VIEW IF NOT EXISTS active_requirements AS SELECT * FROM requirements WHERE superseded_by IS NULL`);
716
- db.exec(`CREATE VIEW IF NOT EXISTS active_memories AS SELECT * FROM memories WHERE superseded_by IS NULL`);
126
+ createBaseSchemaObjects(db, {
127
+ tryCreateMemoriesFts,
128
+ ensureVerificationEvidenceDedupIndex,
129
+ });
717
130
 
718
131
  const existing = db.prepare("SELECT count(*) as cnt FROM schema_version").get();
719
132
  if (existing && (existing["cnt"] as number) === 0) {
@@ -731,12 +144,7 @@ function initSchema(db: DbAdapter, fileBacked: boolean): void {
731
144
  db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_from ON memory_relations(from_id)");
732
145
  db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_to ON memory_relations(to_id)");
733
146
 
734
- db.prepare(
735
- "INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)",
736
- ).run({
737
- ":version": SCHEMA_VERSION,
738
- ":applied_at": new Date().toISOString(),
739
- });
147
+ recordSchemaVersion(db, SCHEMA_VERSION);
740
148
  }
741
149
 
742
150
  db.exec("COMMIT");
@@ -748,16 +156,6 @@ function initSchema(db: DbAdapter, fileBacked: boolean): void {
748
156
  migrateSchema(db);
749
157
  }
750
158
 
751
- function columnExists(db: DbAdapter, table: string, column: string): boolean {
752
- const rows = db.prepare(`PRAGMA table_info(${table})`).all();
753
- return rows.some((row) => row["name"] === column);
754
- }
755
-
756
- function formatFtsUnavailableError(err: unknown): string {
757
- const message = err instanceof Error ? err.message : String(err);
758
- return message.replace(/\bmoduel\s*:\s*/gi, "module: ");
759
- }
760
-
761
159
  /**
762
160
  * Create the FTS5 virtual table for memories plus the triggers that keep it
763
161
  * in sync with the base table. FTS5 may be unavailable on stripped-down
@@ -765,317 +163,88 @@ function formatFtsUnavailableError(err: unknown): string {
765
163
  * to LIKE-based scans in `memory-store.queryMemoriesRanked`.
766
164
  */
767
165
  export function tryCreateMemoriesFts(db: DbAdapter): boolean {
768
- try {
769
- db.exec(`
770
- CREATE VIRTUAL TABLE IF NOT EXISTS memories_fts
771
- USING fts5(content, content='memories', content_rowid='seq', tokenize='porter unicode61')
772
- `);
773
- // Triggers mirror inserts / updates / deletes on the base memories table.
774
- db.exec(`
775
- CREATE TRIGGER IF NOT EXISTS memories_ai
776
- AFTER INSERT ON memories BEGIN
777
- INSERT INTO memories_fts(rowid, content) VALUES (new.seq, new.content);
778
- END
779
- `);
780
- db.exec(`
781
- CREATE TRIGGER IF NOT EXISTS memories_ad
782
- AFTER DELETE ON memories BEGIN
783
- INSERT INTO memories_fts(memories_fts, rowid, content) VALUES ('delete', old.seq, old.content);
784
- END
785
- `);
786
- db.exec(`
787
- CREATE TRIGGER IF NOT EXISTS memories_au
788
- AFTER UPDATE OF content ON memories BEGIN
789
- INSERT INTO memories_fts(memories_fts, rowid, content) VALUES ('delete', old.seq, old.content);
790
- INSERT INTO memories_fts(rowid, content) VALUES (new.seq, new.content);
791
- END
792
- `);
793
- return true;
794
- } catch (err) {
795
- logWarning("db", `FTS5 unavailable — memory queries will use LIKE fallback: ${formatFtsUnavailableError(err)}`);
796
- return false;
797
- }
166
+ return tryCreateMemoriesFtsSchema(db, {
167
+ onUnavailable: (message) => logWarning("db", message),
168
+ });
798
169
  }
799
170
 
800
171
  export function isMemoriesFtsAvailable(db: DbAdapter): boolean {
801
- try {
802
- const row = db
803
- .prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='memories_fts'")
804
- .get();
805
- return !!row;
806
- } catch {
807
- return false;
808
- }
172
+ return isMemoriesFtsAvailableSchema(db);
809
173
  }
810
174
 
811
- function ensureColumn(db: DbAdapter, table: string, column: string, ddl: string): void {
812
- if (!columnExists(db, table, column)) db.exec(ddl);
175
+ function backfillMemoriesFts(db: DbAdapter): void {
176
+ db.exec(`INSERT INTO memories_fts(rowid, content) SELECT seq, content FROM memories`);
177
+ }
178
+
179
+ function copyQualityGateRowsToRepairedTable(db: DbAdapter): void {
180
+ db.exec(`
181
+ INSERT OR IGNORE INTO quality_gates_new
182
+ (milestone_id, slice_id, gate_id, scope, task_id, status, verdict, rationale, findings, evaluated_at)
183
+ SELECT milestone_id, slice_id, gate_id, scope, COALESCE(task_id, ''), status, verdict, rationale, findings, evaluated_at
184
+ FROM quality_gates
185
+ `);
813
186
  }
814
187
 
815
188
  function migrateSchema(db: DbAdapter): void {
816
- const row = db.prepare("SELECT MAX(version) as v FROM schema_version").get();
817
- const currentVersion = row ? (row["v"] as number) : 0;
189
+ const currentVersion = getCurrentSchemaVersion(db);
818
190
  if (currentVersion >= SCHEMA_VERSION) return;
819
191
 
820
- // Backup database before migration so a mid-migration crash doesn't
821
- // leave a partially-migrated DB with no recovery path.
822
- // WAL-safe: checkpoint first to flush WAL into the main DB file, then copy.
823
- if (currentPath && currentPath !== ":memory:" && existsSync(currentPath)) {
824
- try {
825
- const backupPath = `${currentPath}.backup-v${currentVersion}`;
826
- if (!existsSync(backupPath)) {
827
- // Flush WAL to main DB file before copying — without this, the backup
828
- // may be missing committed data that only exists in the -wal file.
829
- try { db.exec("PRAGMA wal_checkpoint(TRUNCATE)"); } catch { /* checkpoint is best-effort */ }
830
- copyFileSync(currentPath, backupPath);
831
- }
832
- } catch (backupErr) {
833
- // Log but proceed — blocking migration leaves the DB stuck at an old
834
- // schema version permanently on read-only or full filesystems.
835
- logWarning("db", `Pre-migration backup failed: ${backupErr instanceof Error ? backupErr.message : String(backupErr)}`);
836
- }
837
- }
192
+ backupDatabaseBeforeMigration(db, currentPath, currentVersion, {
193
+ existsSync,
194
+ copyFileSync,
195
+ logWarning,
196
+ });
838
197
 
839
198
  db.exec("BEGIN");
840
199
  try {
841
200
  if (currentVersion < 2) {
842
- db.exec(`
843
- CREATE TABLE IF NOT EXISTS artifacts (
844
- path TEXT PRIMARY KEY,
845
- artifact_type TEXT NOT NULL DEFAULT '',
846
- milestone_id TEXT DEFAULT NULL,
847
- slice_id TEXT DEFAULT NULL,
848
- task_id TEXT DEFAULT NULL,
849
- full_content TEXT NOT NULL DEFAULT '',
850
- imported_at TEXT NOT NULL DEFAULT ''
851
- )
852
- `);
853
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
854
- ":version": 2,
855
- ":applied_at": new Date().toISOString(),
856
- });
201
+ applyMigrationV2Artifacts(db);
202
+ recordSchemaVersion(db, 2);
857
203
  }
858
204
 
859
205
  if (currentVersion < 3) {
860
- db.exec(`
861
- CREATE TABLE IF NOT EXISTS memories (
862
- seq INTEGER PRIMARY KEY AUTOINCREMENT,
863
- id TEXT NOT NULL UNIQUE,
864
- category TEXT NOT NULL,
865
- content TEXT NOT NULL,
866
- confidence REAL NOT NULL DEFAULT 0.8,
867
- source_unit_type TEXT,
868
- source_unit_id TEXT,
869
- created_at TEXT NOT NULL,
870
- updated_at TEXT NOT NULL,
871
- superseded_by TEXT DEFAULT NULL,
872
- hit_count INTEGER NOT NULL DEFAULT 0
873
- )
874
- `);
875
- db.exec(`
876
- CREATE TABLE IF NOT EXISTS memory_processed_units (
877
- unit_key TEXT PRIMARY KEY,
878
- activity_file TEXT,
879
- processed_at TEXT NOT NULL
880
- )
881
- `);
882
- db.exec("CREATE INDEX IF NOT EXISTS idx_memories_active ON memories(superseded_by)");
883
- db.exec("DROP VIEW IF EXISTS active_memories");
884
- db.exec("CREATE VIEW active_memories AS SELECT * FROM memories WHERE superseded_by IS NULL");
885
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
886
- ":version": 3,
887
- ":applied_at": new Date().toISOString(),
888
- });
206
+ applyMigrationV3Memories(db);
207
+ recordSchemaVersion(db, 3);
889
208
  }
890
209
 
891
210
  if (currentVersion < 4) {
892
- ensureColumn(db, "decisions", "made_by", `ALTER TABLE decisions ADD COLUMN made_by TEXT NOT NULL DEFAULT 'agent'`);
893
- db.exec("DROP VIEW IF EXISTS active_decisions");
894
- db.exec("CREATE VIEW active_decisions AS SELECT * FROM decisions WHERE superseded_by IS NULL");
895
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
896
- ":version": 4,
897
- ":applied_at": new Date().toISOString(),
898
- });
211
+ applyMigrationV4DecisionMadeBy(db);
212
+ recordSchemaVersion(db, 4);
899
213
  }
900
214
 
901
215
  if (currentVersion < 5) {
902
- db.exec(`
903
- CREATE TABLE IF NOT EXISTS milestones (
904
- id TEXT PRIMARY KEY,
905
- title TEXT NOT NULL DEFAULT '',
906
- status TEXT NOT NULL DEFAULT 'active',
907
- created_at TEXT NOT NULL,
908
- completed_at TEXT DEFAULT NULL
909
- )
910
- `);
911
- db.exec(`
912
- CREATE TABLE IF NOT EXISTS slices (
913
- milestone_id TEXT NOT NULL,
914
- id TEXT NOT NULL,
915
- title TEXT NOT NULL DEFAULT '',
916
- status TEXT NOT NULL DEFAULT 'pending',
917
- risk TEXT NOT NULL DEFAULT 'medium',
918
- created_at TEXT NOT NULL DEFAULT '',
919
- completed_at TEXT DEFAULT NULL,
920
- PRIMARY KEY (milestone_id, id),
921
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
922
- )
923
- `);
924
- db.exec(`
925
- CREATE TABLE IF NOT EXISTS tasks (
926
- milestone_id TEXT NOT NULL,
927
- slice_id TEXT NOT NULL,
928
- id TEXT NOT NULL,
929
- title TEXT NOT NULL DEFAULT '',
930
- status TEXT NOT NULL DEFAULT 'pending',
931
- one_liner TEXT NOT NULL DEFAULT '',
932
- narrative TEXT NOT NULL DEFAULT '',
933
- verification_result TEXT NOT NULL DEFAULT '',
934
- duration TEXT NOT NULL DEFAULT '',
935
- completed_at TEXT DEFAULT NULL,
936
- blocker_discovered INTEGER DEFAULT 0,
937
- deviations TEXT NOT NULL DEFAULT '',
938
- known_issues TEXT NOT NULL DEFAULT '',
939
- key_files TEXT NOT NULL DEFAULT '[]',
940
- key_decisions TEXT NOT NULL DEFAULT '[]',
941
- full_summary_md TEXT NOT NULL DEFAULT '',
942
- PRIMARY KEY (milestone_id, slice_id, id),
943
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
944
- )
945
- `);
946
- db.exec(`
947
- CREATE TABLE IF NOT EXISTS verification_evidence (
948
- id INTEGER PRIMARY KEY AUTOINCREMENT,
949
- task_id TEXT NOT NULL DEFAULT '',
950
- slice_id TEXT NOT NULL DEFAULT '',
951
- milestone_id TEXT NOT NULL DEFAULT '',
952
- command TEXT NOT NULL DEFAULT '',
953
- exit_code INTEGER DEFAULT 0,
954
- verdict TEXT NOT NULL DEFAULT '',
955
- duration_ms INTEGER DEFAULT 0,
956
- created_at TEXT NOT NULL DEFAULT '',
957
- FOREIGN KEY (milestone_id, slice_id, task_id) REFERENCES tasks(milestone_id, slice_id, id)
958
- )
959
- `);
960
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
961
- ":version": 5,
962
- ":applied_at": new Date().toISOString(),
963
- });
216
+ applyMigrationV5HierarchyTables(db);
217
+ recordSchemaVersion(db, 5);
964
218
  }
965
219
 
966
220
  if (currentVersion < 6) {
967
- ensureColumn(db, "slices", "full_summary_md", `ALTER TABLE slices ADD COLUMN full_summary_md TEXT NOT NULL DEFAULT ''`);
968
- ensureColumn(db, "slices", "full_uat_md", `ALTER TABLE slices ADD COLUMN full_uat_md TEXT NOT NULL DEFAULT ''`);
969
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
970
- ":version": 6,
971
- ":applied_at": new Date().toISOString(),
972
- });
221
+ applyMigrationV6SliceSummaries(db);
222
+ recordSchemaVersion(db, 6);
973
223
  }
974
224
 
975
225
  if (currentVersion < 7) {
976
- ensureColumn(db, "slices", "depends", `ALTER TABLE slices ADD COLUMN depends TEXT NOT NULL DEFAULT '[]'`);
977
- ensureColumn(db, "slices", "demo", `ALTER TABLE slices ADD COLUMN demo TEXT NOT NULL DEFAULT ''`);
978
- ensureColumn(db, "milestones", "depends_on", `ALTER TABLE milestones ADD COLUMN depends_on TEXT NOT NULL DEFAULT '[]'`);
979
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
980
- ":version": 7,
981
- ":applied_at": new Date().toISOString(),
982
- });
226
+ applyMigrationV7Dependencies(db);
227
+ recordSchemaVersion(db, 7);
983
228
  }
984
229
 
985
230
  if (currentVersion < 8) {
986
- ensureColumn(db, "milestones", "vision", `ALTER TABLE milestones ADD COLUMN vision TEXT NOT NULL DEFAULT ''`);
987
- ensureColumn(db, "milestones", "success_criteria", `ALTER TABLE milestones ADD COLUMN success_criteria TEXT NOT NULL DEFAULT '[]'`);
988
- ensureColumn(db, "milestones", "key_risks", `ALTER TABLE milestones ADD COLUMN key_risks TEXT NOT NULL DEFAULT '[]'`);
989
- ensureColumn(db, "milestones", "proof_strategy", `ALTER TABLE milestones ADD COLUMN proof_strategy TEXT NOT NULL DEFAULT '[]'`);
990
- ensureColumn(db, "milestones", "verification_contract", `ALTER TABLE milestones ADD COLUMN verification_contract TEXT NOT NULL DEFAULT ''`);
991
- ensureColumn(db, "milestones", "verification_integration", `ALTER TABLE milestones ADD COLUMN verification_integration TEXT NOT NULL DEFAULT ''`);
992
- ensureColumn(db, "milestones", "verification_operational", `ALTER TABLE milestones ADD COLUMN verification_operational TEXT NOT NULL DEFAULT ''`);
993
- ensureColumn(db, "milestones", "verification_uat", `ALTER TABLE milestones ADD COLUMN verification_uat TEXT NOT NULL DEFAULT ''`);
994
- ensureColumn(db, "milestones", "definition_of_done", `ALTER TABLE milestones ADD COLUMN definition_of_done TEXT NOT NULL DEFAULT '[]'`);
995
- ensureColumn(db, "milestones", "requirement_coverage", `ALTER TABLE milestones ADD COLUMN requirement_coverage TEXT NOT NULL DEFAULT ''`);
996
- ensureColumn(db, "milestones", "boundary_map_markdown", `ALTER TABLE milestones ADD COLUMN boundary_map_markdown TEXT NOT NULL DEFAULT ''`);
997
-
998
- ensureColumn(db, "slices", "goal", `ALTER TABLE slices ADD COLUMN goal TEXT NOT NULL DEFAULT ''`);
999
- ensureColumn(db, "slices", "success_criteria", `ALTER TABLE slices ADD COLUMN success_criteria TEXT NOT NULL DEFAULT ''`);
1000
- ensureColumn(db, "slices", "proof_level", `ALTER TABLE slices ADD COLUMN proof_level TEXT NOT NULL DEFAULT ''`);
1001
- ensureColumn(db, "slices", "integration_closure", `ALTER TABLE slices ADD COLUMN integration_closure TEXT NOT NULL DEFAULT ''`);
1002
- ensureColumn(db, "slices", "observability_impact", `ALTER TABLE slices ADD COLUMN observability_impact TEXT NOT NULL DEFAULT ''`);
1003
-
1004
- ensureColumn(db, "tasks", "description", `ALTER TABLE tasks ADD COLUMN description TEXT NOT NULL DEFAULT ''`);
1005
- ensureColumn(db, "tasks", "estimate", `ALTER TABLE tasks ADD COLUMN estimate TEXT NOT NULL DEFAULT ''`);
1006
- ensureColumn(db, "tasks", "files", `ALTER TABLE tasks ADD COLUMN files TEXT NOT NULL DEFAULT '[]'`);
1007
- ensureColumn(db, "tasks", "verify", `ALTER TABLE tasks ADD COLUMN verify TEXT NOT NULL DEFAULT ''`);
1008
- ensureColumn(db, "tasks", "inputs", `ALTER TABLE tasks ADD COLUMN inputs TEXT NOT NULL DEFAULT '[]'`);
1009
- ensureColumn(db, "tasks", "expected_output", `ALTER TABLE tasks ADD COLUMN expected_output TEXT NOT NULL DEFAULT '[]'`);
1010
- ensureColumn(db, "tasks", "observability_impact", `ALTER TABLE tasks ADD COLUMN observability_impact TEXT NOT NULL DEFAULT ''`);
1011
-
1012
- db.exec(`
1013
- CREATE TABLE IF NOT EXISTS replan_history (
1014
- id INTEGER PRIMARY KEY AUTOINCREMENT,
1015
- milestone_id TEXT NOT NULL DEFAULT '',
1016
- slice_id TEXT DEFAULT NULL,
1017
- task_id TEXT DEFAULT NULL,
1018
- summary TEXT NOT NULL DEFAULT '',
1019
- previous_artifact_path TEXT DEFAULT NULL,
1020
- replacement_artifact_path TEXT DEFAULT NULL,
1021
- created_at TEXT NOT NULL DEFAULT '',
1022
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
1023
- )
1024
- `);
1025
- db.exec(`
1026
- CREATE TABLE IF NOT EXISTS assessments (
1027
- path TEXT PRIMARY KEY,
1028
- milestone_id TEXT NOT NULL DEFAULT '',
1029
- slice_id TEXT DEFAULT NULL,
1030
- task_id TEXT DEFAULT NULL,
1031
- status TEXT NOT NULL DEFAULT '',
1032
- scope TEXT NOT NULL DEFAULT '',
1033
- full_content TEXT NOT NULL DEFAULT '',
1034
- created_at TEXT NOT NULL DEFAULT '',
1035
- FOREIGN KEY (milestone_id) REFERENCES milestones(id)
1036
- )
1037
- `);
1038
- db.exec("CREATE INDEX IF NOT EXISTS idx_replan_history_milestone ON replan_history(milestone_id, created_at)");
1039
-
1040
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1041
- ":version": 8,
1042
- ":applied_at": new Date().toISOString(),
1043
- });
231
+ applyMigrationV8PlanningFields(db);
232
+ recordSchemaVersion(db, 8);
1044
233
  }
1045
234
 
1046
235
  if (currentVersion < 9) {
1047
- ensureColumn(db, "slices", "sequence", `ALTER TABLE slices ADD COLUMN sequence INTEGER DEFAULT 0`);
1048
- ensureColumn(db, "tasks", "sequence", `ALTER TABLE tasks ADD COLUMN sequence INTEGER DEFAULT 0`);
1049
-
1050
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1051
- ":version": 9,
1052
- ":applied_at": new Date().toISOString(),
1053
- });
236
+ applyMigrationV9Ordering(db);
237
+ recordSchemaVersion(db, 9);
1054
238
  }
1055
239
 
1056
240
  if (currentVersion < 10) {
1057
- ensureColumn(db, "slices", "replan_triggered_at", `ALTER TABLE slices ADD COLUMN replan_triggered_at TEXT DEFAULT NULL`);
1058
-
1059
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1060
- ":version": 10,
1061
- ":applied_at": new Date().toISOString(),
1062
- });
241
+ applyMigrationV10ReplanTrigger(db);
242
+ recordSchemaVersion(db, 10);
1063
243
  }
1064
244
 
1065
245
  if (currentVersion < 11) {
1066
- ensureColumn(db, "tasks", "full_plan_md", `ALTER TABLE tasks ADD COLUMN full_plan_md TEXT NOT NULL DEFAULT ''`);
1067
- // Add unique constraint to replan_history for idempotency:
1068
- // one replan record per blocker task per slice per milestone.
1069
- db.exec(`
1070
- CREATE UNIQUE INDEX IF NOT EXISTS idx_replan_history_unique
1071
- ON replan_history(milestone_id, slice_id, task_id)
1072
- WHERE slice_id IS NOT NULL AND task_id IS NOT NULL
1073
- `);
1074
-
1075
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1076
- ":version": 11,
1077
- ":applied_at": new Date().toISOString(),
1078
- });
246
+ applyMigrationV11TaskPlanning(db);
247
+ recordSchemaVersion(db, 11);
1079
248
  }
1080
249
 
1081
250
  if (currentVersion < 12) {
@@ -1084,305 +253,68 @@ function migrateSchema(db: DbAdapter): void {
1084
253
  // DBs that migrate through v12. The corrected DDL uses
1085
254
  // task_id TEXT NOT NULL DEFAULT '' with a plain column list PK. DBs that
1086
255
  // were created with the broken DDL are repaired by the v22 migration below.
1087
- db.exec(`
1088
- CREATE TABLE IF NOT EXISTS quality_gates (
1089
- milestone_id TEXT NOT NULL,
1090
- slice_id TEXT NOT NULL,
1091
- gate_id TEXT NOT NULL,
1092
- scope TEXT NOT NULL DEFAULT 'slice',
1093
- task_id TEXT NOT NULL DEFAULT '',
1094
- status TEXT NOT NULL DEFAULT 'pending',
1095
- verdict TEXT NOT NULL DEFAULT '',
1096
- rationale TEXT NOT NULL DEFAULT '',
1097
- findings TEXT NOT NULL DEFAULT '',
1098
- evaluated_at TEXT DEFAULT NULL,
1099
- PRIMARY KEY (milestone_id, slice_id, gate_id, task_id),
1100
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
1101
- )
1102
- `);
1103
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1104
- ":version": 12,
1105
- ":applied_at": new Date().toISOString(),
1106
- });
256
+ applyMigrationV12QualityGates(db);
257
+ recordSchemaVersion(db, 12);
1107
258
  }
1108
259
 
1109
260
  if (currentVersion < 13) {
1110
- // Hot-path indexes for auto-loop dispatch queries
1111
- db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_active ON tasks(milestone_id, slice_id, status)");
1112
- db.exec("CREATE INDEX IF NOT EXISTS idx_slices_active ON slices(milestone_id, status)");
1113
- db.exec("CREATE INDEX IF NOT EXISTS idx_milestones_status ON milestones(status)");
1114
- db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
1115
- db.exec("CREATE INDEX IF NOT EXISTS idx_verification_evidence_task ON verification_evidence(milestone_id, slice_id, task_id)");
1116
- ensureVerificationEvidenceDedupIndex(db);
1117
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1118
- ":version": 13,
1119
- ":applied_at": new Date().toISOString(),
1120
- });
261
+ applyMigrationV13HotPathIndexes(db, ensureVerificationEvidenceDedupIndex);
262
+ recordSchemaVersion(db, 13);
1121
263
  }
1122
264
 
1123
265
  if (currentVersion < 14) {
1124
- db.exec(`
1125
- CREATE TABLE IF NOT EXISTS slice_dependencies (
1126
- milestone_id TEXT NOT NULL,
1127
- slice_id TEXT NOT NULL,
1128
- depends_on_slice_id TEXT NOT NULL,
1129
- PRIMARY KEY (milestone_id, slice_id, depends_on_slice_id),
1130
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id),
1131
- FOREIGN KEY (milestone_id, depends_on_slice_id) REFERENCES slices(milestone_id, id)
1132
- )
1133
- `);
1134
- db.exec("CREATE INDEX IF NOT EXISTS idx_slice_deps_target ON slice_dependencies(milestone_id, depends_on_slice_id)");
1135
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1136
- ":version": 14,
1137
- ":applied_at": new Date().toISOString(),
1138
- });
266
+ applyMigrationV14SliceDependencies(db);
267
+ recordSchemaVersion(db, 14);
1139
268
  }
1140
269
 
1141
270
  if (currentVersion < 15) {
1142
- db.exec(`
1143
- CREATE TABLE IF NOT EXISTS gate_runs (
1144
- id INTEGER PRIMARY KEY AUTOINCREMENT,
1145
- trace_id TEXT NOT NULL,
1146
- turn_id TEXT NOT NULL,
1147
- gate_id TEXT NOT NULL,
1148
- gate_type TEXT NOT NULL DEFAULT '',
1149
- unit_type TEXT DEFAULT NULL,
1150
- unit_id TEXT DEFAULT NULL,
1151
- milestone_id TEXT DEFAULT NULL,
1152
- slice_id TEXT DEFAULT NULL,
1153
- task_id TEXT DEFAULT NULL,
1154
- outcome TEXT NOT NULL DEFAULT 'pass',
1155
- failure_class TEXT NOT NULL DEFAULT 'none',
1156
- rationale TEXT NOT NULL DEFAULT '',
1157
- findings TEXT NOT NULL DEFAULT '',
1158
- attempt INTEGER NOT NULL DEFAULT 1,
1159
- max_attempts INTEGER NOT NULL DEFAULT 1,
1160
- retryable INTEGER NOT NULL DEFAULT 0,
1161
- evaluated_at TEXT NOT NULL DEFAULT ''
1162
- )
1163
- `);
1164
- db.exec(`
1165
- CREATE TABLE IF NOT EXISTS turn_git_transactions (
1166
- trace_id TEXT NOT NULL,
1167
- turn_id TEXT NOT NULL,
1168
- unit_type TEXT DEFAULT NULL,
1169
- unit_id TEXT DEFAULT NULL,
1170
- stage TEXT NOT NULL DEFAULT 'turn-start',
1171
- action TEXT NOT NULL DEFAULT 'status-only',
1172
- push INTEGER NOT NULL DEFAULT 0,
1173
- status TEXT NOT NULL DEFAULT 'ok',
1174
- error TEXT DEFAULT NULL,
1175
- metadata_json TEXT NOT NULL DEFAULT '{}',
1176
- updated_at TEXT NOT NULL DEFAULT '',
1177
- PRIMARY KEY (trace_id, turn_id, stage)
1178
- )
1179
- `);
1180
- db.exec(`
1181
- CREATE TABLE IF NOT EXISTS audit_events (
1182
- event_id TEXT PRIMARY KEY,
1183
- trace_id TEXT NOT NULL,
1184
- turn_id TEXT DEFAULT NULL,
1185
- caused_by TEXT DEFAULT NULL,
1186
- category TEXT NOT NULL,
1187
- type TEXT NOT NULL,
1188
- ts TEXT NOT NULL,
1189
- payload_json TEXT NOT NULL DEFAULT '{}'
1190
- )
1191
- `);
1192
- db.exec(`
1193
- CREATE TABLE IF NOT EXISTS audit_turn_index (
1194
- trace_id TEXT NOT NULL,
1195
- turn_id TEXT NOT NULL,
1196
- first_ts TEXT NOT NULL,
1197
- last_ts TEXT NOT NULL,
1198
- event_count INTEGER NOT NULL DEFAULT 0,
1199
- PRIMARY KEY (trace_id, turn_id)
1200
- )
1201
- `);
1202
- db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_turn ON gate_runs(trace_id, turn_id)");
1203
- db.exec("CREATE INDEX IF NOT EXISTS idx_gate_runs_lookup ON gate_runs(milestone_id, slice_id, task_id, gate_id)");
1204
- db.exec("CREATE INDEX IF NOT EXISTS idx_turn_git_tx_turn ON turn_git_transactions(trace_id, turn_id)");
1205
- db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_trace ON audit_events(trace_id, ts)");
1206
- db.exec("CREATE INDEX IF NOT EXISTS idx_audit_events_turn ON audit_events(trace_id, turn_id, ts)");
1207
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1208
- ":version": 15,
1209
- ":applied_at": new Date().toISOString(),
1210
- });
271
+ applyMigrationV15AuditTables(db);
272
+ recordSchemaVersion(db, 15);
1211
273
  }
1212
274
 
1213
275
  if (currentVersion < 16) {
1214
- // ADR-011 Phase 1: sketch-then-refine progressive planning — sketch columns on slices.
1215
- ensureColumn(db, "slices", "is_sketch", `ALTER TABLE slices ADD COLUMN is_sketch INTEGER NOT NULL DEFAULT 0`);
1216
- ensureColumn(db, "slices", "sketch_scope", `ALTER TABLE slices ADD COLUMN sketch_scope TEXT NOT NULL DEFAULT ''`);
1217
- // ADR-011 Phase 2: decisions can now be sourced from escalation resolutions.
1218
- ensureColumn(db, "decisions", "source", `ALTER TABLE decisions ADD COLUMN source TEXT NOT NULL DEFAULT 'discussion'`);
1219
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1220
- ":version": 16,
1221
- ":applied_at": new Date().toISOString(),
1222
- });
276
+ applyMigrationV16EscalationSource(db);
277
+ recordSchemaVersion(db, 16);
1223
278
  }
1224
279
 
1225
280
  if (currentVersion < 17) {
1226
- // ADR-011 Phase 2: mid-execution escalation — columns on the tasks table.
1227
- ensureColumn(db, "tasks", "blocker_source", `ALTER TABLE tasks ADD COLUMN blocker_source TEXT NOT NULL DEFAULT ''`);
1228
- ensureColumn(db, "tasks", "escalation_pending", `ALTER TABLE tasks ADD COLUMN escalation_pending INTEGER NOT NULL DEFAULT 0`);
1229
- ensureColumn(db, "tasks", "escalation_awaiting_review", `ALTER TABLE tasks ADD COLUMN escalation_awaiting_review INTEGER NOT NULL DEFAULT 0`);
1230
- ensureColumn(db, "tasks", "escalation_artifact_path", `ALTER TABLE tasks ADD COLUMN escalation_artifact_path TEXT DEFAULT NULL`);
1231
- ensureColumn(db, "tasks", "escalation_override_applied_at", `ALTER TABLE tasks ADD COLUMN escalation_override_applied_at TEXT DEFAULT NULL`);
1232
- db.exec("CREATE INDEX IF NOT EXISTS idx_tasks_escalation_pending ON tasks(milestone_id, slice_id, escalation_pending)");
1233
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1234
- ":version": 17,
1235
- ":applied_at": new Date().toISOString(),
1236
- });
281
+ applyMigrationV17TaskEscalation(db);
282
+ recordSchemaVersion(db, 17);
1237
283
  }
1238
284
 
1239
285
  if (currentVersion < 18) {
1240
- // Memory system Phase 2: scope + tags on memories, plus memory_sources
1241
- // table for raw ingested content (notes, files, URLs, artifacts).
1242
- ensureColumn(db, "memories", "scope", `ALTER TABLE memories ADD COLUMN scope TEXT NOT NULL DEFAULT 'project'`);
1243
- ensureColumn(db, "memories", "tags", `ALTER TABLE memories ADD COLUMN tags TEXT NOT NULL DEFAULT '[]'`);
1244
- db.exec(`
1245
- CREATE TABLE IF NOT EXISTS memory_sources (
1246
- id TEXT PRIMARY KEY,
1247
- kind TEXT NOT NULL,
1248
- uri TEXT,
1249
- title TEXT,
1250
- content TEXT NOT NULL,
1251
- content_hash TEXT NOT NULL UNIQUE,
1252
- imported_at TEXT NOT NULL,
1253
- scope TEXT NOT NULL DEFAULT 'project',
1254
- tags TEXT NOT NULL DEFAULT '[]'
1255
- )
1256
- `);
1257
- // If memory_sources already existed before v18 (created by an earlier
1258
- // version of initSchema that lacked scope/tags), add the missing columns.
1259
- ensureColumn(db, "memory_sources", "scope", `ALTER TABLE memory_sources ADD COLUMN scope TEXT NOT NULL DEFAULT 'project'`);
1260
- ensureColumn(db, "memory_sources", "tags", `ALTER TABLE memory_sources ADD COLUMN tags TEXT NOT NULL DEFAULT '[]'`);
1261
- db.exec("CREATE INDEX IF NOT EXISTS idx_memories_scope ON memories(scope)");
1262
- db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_kind ON memory_sources(kind)");
1263
- db.exec("CREATE INDEX IF NOT EXISTS idx_memory_sources_scope ON memory_sources(scope)");
1264
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1265
- ":version": 18,
1266
- ":applied_at": new Date().toISOString(),
1267
- });
286
+ applyMigrationV18MemorySources(db);
287
+ recordSchemaVersion(db, 18);
1268
288
  }
1269
289
 
1270
290
  if (currentVersion < 19) {
1271
- // Memory system Phase 3: embeddings + FTS5 for hybrid retrieval.
1272
- db.exec(`
1273
- CREATE TABLE IF NOT EXISTS memory_embeddings (
1274
- memory_id TEXT PRIMARY KEY,
1275
- model TEXT NOT NULL,
1276
- dim INTEGER NOT NULL,
1277
- vector BLOB NOT NULL,
1278
- updated_at TEXT NOT NULL
1279
- )
1280
- `);
1281
- tryCreateMemoriesFts(db);
1282
- // Backfill FTS5 with any existing memories (triggers only cover future writes).
1283
- if (isMemoriesFtsAvailable(db)) {
1284
- try {
1285
- db.exec(`INSERT INTO memories_fts(rowid, content) SELECT seq, content FROM memories`);
1286
- } catch (err) {
1287
- logWarning("db", `FTS5 backfill failed: ${(err as Error).message}`);
1288
- }
1289
- }
1290
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1291
- ":version": 19,
1292
- ":applied_at": new Date().toISOString(),
291
+ applyMigrationV19MemoryFts(db, {
292
+ tryCreateMemoriesFts,
293
+ isMemoriesFtsAvailable,
294
+ backfillMemoriesFts,
295
+ logWarning,
1293
296
  });
297
+ recordSchemaVersion(db, 19);
1294
298
  }
1295
299
 
1296
300
  if (currentVersion < 20) {
1297
- // Memory system Phase 4: knowledge-graph relations between memories.
1298
- db.exec(`
1299
- CREATE TABLE IF NOT EXISTS memory_relations (
1300
- from_id TEXT NOT NULL,
1301
- to_id TEXT NOT NULL,
1302
- rel TEXT NOT NULL,
1303
- confidence REAL NOT NULL DEFAULT 0.8,
1304
- created_at TEXT NOT NULL,
1305
- PRIMARY KEY (from_id, to_id, rel)
1306
- )
1307
- `);
1308
- db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_from ON memory_relations(from_id)");
1309
- db.exec("CREATE INDEX IF NOT EXISTS idx_memory_relations_to ON memory_relations(to_id)");
1310
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1311
- ":version": 20,
1312
- ":applied_at": new Date().toISOString(),
1313
- });
301
+ applyMigrationV20MemoryRelations(db);
302
+ recordSchemaVersion(db, 20);
1314
303
  }
1315
304
 
1316
305
  if (currentVersion < 21) {
1317
- // ADR-013 Step 2: preserve structured fields (gsd_save_decision's
1318
- // scope/decision/choice/rationale/made_by/revisable) on memories rows so
1319
- // the eventual decisions->memories cutover does not lose schema fidelity.
1320
- // Nullable JSON column — existing rows stay NULL until backfilled in Step 5.
1321
- // Use ensureColumn for race-safety (matches v15-v18 pattern; bare ALTER
1322
- // throws "duplicate column" on the loser of a concurrent open race even
1323
- // though the transaction wrapper protects the schema_version row).
1324
- ensureColumn(db, "memories", "structured_fields", "ALTER TABLE memories ADD COLUMN structured_fields TEXT DEFAULT NULL");
1325
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1326
- ":version": 21,
1327
- ":applied_at": new Date().toISOString(),
1328
- });
306
+ applyMigrationV21StructuredMemories(db);
307
+ recordSchemaVersion(db, 21);
1329
308
  }
1330
309
 
1331
310
  if (currentVersion < 22) {
1332
- // v22: Repair quality_gates tables that were created by the broken v12
1333
- // migration (which used COALESCE(task_id, '') as a PK expression — invalid
1334
- // SQLite DDL). Those DBs have task_id nullable (dflt_value NULL, notnull 0).
1335
- // Rebuild the table with the correct schema, migrating existing rows via
1336
- // COALESCE so no data is lost.
1337
- const qgInfo = db.prepare("PRAGMA table_info(quality_gates)").all() as Array<Record<string, unknown>>;
1338
- const taskIdCol = qgInfo.find((r) => r["name"] === "task_id");
1339
- const needsRepair = taskIdCol && (taskIdCol["notnull"] === 0 || taskIdCol["notnull"] === "0");
1340
- if (needsRepair) {
1341
- db.exec(`
1342
- CREATE TABLE quality_gates_new (
1343
- milestone_id TEXT NOT NULL,
1344
- slice_id TEXT NOT NULL,
1345
- gate_id TEXT NOT NULL,
1346
- scope TEXT NOT NULL DEFAULT 'slice',
1347
- task_id TEXT NOT NULL DEFAULT '',
1348
- status TEXT NOT NULL DEFAULT 'pending',
1349
- verdict TEXT NOT NULL DEFAULT '',
1350
- rationale TEXT NOT NULL DEFAULT '',
1351
- findings TEXT NOT NULL DEFAULT '',
1352
- evaluated_at TEXT DEFAULT NULL,
1353
- PRIMARY KEY (milestone_id, slice_id, gate_id, task_id),
1354
- FOREIGN KEY (milestone_id, slice_id) REFERENCES slices(milestone_id, id)
1355
- )
1356
- `);
1357
- db.exec(`
1358
- INSERT OR IGNORE INTO quality_gates_new
1359
- (milestone_id, slice_id, gate_id, scope, task_id, status, verdict, rationale, findings, evaluated_at)
1360
- SELECT milestone_id, slice_id, gate_id, scope, COALESCE(task_id, ''), status, verdict, rationale, findings, evaluated_at
1361
- FROM quality_gates
1362
- `);
1363
- db.exec("DROP TABLE quality_gates");
1364
- db.exec("ALTER TABLE quality_gates_new RENAME TO quality_gates");
1365
- db.exec("CREATE INDEX IF NOT EXISTS idx_quality_gates_pending ON quality_gates(milestone_id, slice_id, status)");
1366
- }
1367
- // Ensure scope column exists on quality_gates and assessments (guard
1368
- // against DBs that somehow lack it after a partial migration).
1369
- ensureColumn(db, "quality_gates", "scope", "ALTER TABLE quality_gates ADD COLUMN scope TEXT NOT NULL DEFAULT 'slice'");
1370
- ensureColumn(db, "assessments", "scope", "ALTER TABLE assessments ADD COLUMN scope TEXT NOT NULL DEFAULT ''");
1371
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1372
- ":version": 22,
1373
- ":applied_at": new Date().toISOString(),
1374
- });
311
+ applyMigrationV22QualityGateRepair(db, { copyQualityGateRowsToRepairedTable });
312
+ recordSchemaVersion(db, 22);
1375
313
  }
1376
314
 
1377
315
  if (currentVersion < 23) {
1378
- // v23: milestone queue ordering moves into the canonical DB. The
1379
- // historical QUEUE-ORDER.json file remains a projection, but runtime
1380
- // derivation must not read it as authoritative state.
1381
- ensureColumn(db, "milestones", "sequence", "ALTER TABLE milestones ADD COLUMN sequence INTEGER DEFAULT 0");
1382
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1383
- ":version": 23,
1384
- ":applied_at": new Date().toISOString(),
1385
- });
316
+ applyMigrationV23MilestoneQueue(db);
317
+ recordSchemaVersion(db, 23);
1386
318
  }
1387
319
 
1388
320
  if (currentVersion < 24) {
@@ -1391,20 +323,29 @@ function migrateSchema(db: DbAdapter): void {
1391
323
  // helper runs in the fresh-install path); for upgraded DBs this is
1392
324
  // the only place these tables get created.
1393
325
  createCoordinationTablesV24(db);
1394
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1395
- ":version": 24,
1396
- ":applied_at": new Date().toISOString(),
1397
- });
326
+ recordSchemaVersion(db, 24);
1398
327
  }
1399
328
 
1400
329
  if (currentVersion < 25) {
1401
330
  // v25: runtime_kv non-correctness-critical key-value storage. See
1402
331
  // createRuntimeKvTableV25 for the full schema + invariants.
1403
332
  createRuntimeKvTableV25(db);
1404
- db.prepare("INSERT INTO schema_version (version, applied_at) VALUES (:version, :applied_at)").run({
1405
- ":version": 25,
1406
- ":applied_at": new Date().toISOString(),
1407
- });
333
+ recordSchemaVersion(db, 25);
334
+ }
335
+
336
+ if (currentVersion < 26) {
337
+ applyMigrationV26MilestoneCommitAttributions(db);
338
+ recordSchemaVersion(db, 26);
339
+ }
340
+
341
+ if (currentVersion < 27) {
342
+ applyMigrationV27ArtifactHash(db);
343
+ recordSchemaVersion(db, 27);
344
+ }
345
+
346
+ if (currentVersion < 28) {
347
+ applyMigrationV28MemoryLastHitAt(db);
348
+ recordSchemaVersion(db, 28);
1408
349
  }
1409
350
 
1410
351
  db.exec("COMMIT");
@@ -1418,9 +359,7 @@ let currentDb: DbAdapter | null = null;
1418
359
  let currentPath: string | null = null;
1419
360
  let currentPid: number = 0;
1420
361
  let _exitHandlerRegistered = false;
1421
- let _dbOpenAttempted = false;
1422
- let _lastDbError: Error | null = null;
1423
- let _lastDbPhase: "open" | "initSchema" | "vacuum-recovery" | null = null;
362
+ const _dbOpenState = createDbOpenState();
1424
363
  /**
1425
364
  * Identity key of the workspace whose connection is currently active
1426
365
  * (currentDb). Set by openDatabaseByWorkspace(); null when the active
@@ -1441,11 +380,29 @@ let _currentIdentityKey: string | null = null;
1441
380
  * The cache allows fast re-activation of a previously opened connection when
1442
381
  * callers switch between known workspaces via openDatabaseByWorkspace().
1443
382
  */
1444
- const _dbCache = new Map<string, { dbPath: string; db: DbAdapter }>();
383
+ const _dbCache = createDbConnectionCache();
1445
384
 
1446
385
  /** Test helper: expose the internal cache for inspection. Not for production use. */
1447
- export function _getDbCache(): ReadonlyMap<string, { dbPath: string; db: DbAdapter }> {
1448
- return _dbCache;
386
+ export function _getDbCache(): ReadonlyMap<string, DbConnectionCacheEntry> {
387
+ return _dbCache.asReadonlyMap();
388
+ }
389
+
390
+ function closeCachedConnection(entry: DbConnectionCacheEntry, source: "all" | "workspace"): void {
391
+ try {
392
+ entry.db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
393
+ } catch (e) {
394
+ if (source === "workspace") logWarning("db", `WAL checkpoint (byWorkspace) failed: ${(e as Error).message}`);
395
+ }
396
+ try {
397
+ entry.db.exec("PRAGMA incremental_vacuum(64)");
398
+ } catch (e) {
399
+ if (source === "workspace") logWarning("db", `incremental vacuum (byWorkspace) failed: ${(e as Error).message}`);
400
+ }
401
+ try {
402
+ entry.db.close();
403
+ } catch (e) {
404
+ if (source === "workspace") logWarning("db", `database close (byWorkspace) failed: ${(e as Error).message}`);
405
+ }
1449
406
  }
1450
407
 
1451
408
  /**
@@ -1458,13 +415,7 @@ export function _getDbCache(): ReadonlyMap<string, { dbPath: string; db: DbAdapt
1458
415
  */
1459
416
  export function closeAllDatabases(): void {
1460
417
  // Close all non-active cached connections first.
1461
- for (const [key, entry] of _dbCache) {
1462
- if (entry.db === currentDb) continue; // handled by closeDatabase() below
1463
- _dbCache.delete(key);
1464
- try { entry.db.exec("PRAGMA wal_checkpoint(TRUNCATE)"); } catch { /* best-effort */ }
1465
- try { entry.db.exec("PRAGMA incremental_vacuum(64)"); } catch { /* best-effort */ }
1466
- try { entry.db.close(); } catch { /* best-effort */ }
1467
- }
418
+ _dbCache.closeNonActive(currentDb, (entry) => closeCachedConnection(entry, "all"));
1468
419
  closeDatabase();
1469
420
  }
1470
421
 
@@ -1494,7 +445,7 @@ export function openDatabaseByWorkspace(workspace: GsdWorkspace): boolean {
1494
445
  currentDb = cached.db;
1495
446
  currentPath = cached.dbPath;
1496
447
  currentPid = process.pid;
1497
- _dbOpenAttempted = true;
448
+ _dbOpenState.markAttempted();
1498
449
  _currentIdentityKey = key;
1499
450
  return true;
1500
451
  }
@@ -1586,21 +537,13 @@ export function closeDatabaseByWorkspace(workspace: GsdWorkspace): void {
1586
537
  closeDatabase();
1587
538
  } else {
1588
539
  // Connection was displaced by a later open; close the adapter directly.
1589
- try {
1590
- cached.db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
1591
- } catch (e) { logWarning("db", `WAL checkpoint (byWorkspace) failed: ${(e as Error).message}`); }
1592
- try {
1593
- cached.db.exec("PRAGMA incremental_vacuum(64)");
1594
- } catch (e) { logWarning("db", `incremental vacuum (byWorkspace) failed: ${(e as Error).message}`); }
1595
- try {
1596
- cached.db.close();
1597
- } catch (e) { logWarning("db", `database close (byWorkspace) failed: ${(e as Error).message}`); }
540
+ closeCachedConnection(cached, "workspace");
1598
541
  }
1599
542
  }
1600
543
 
1601
544
  export function getDbProvider(): ProviderName | null {
1602
- loadProvider();
1603
- return providerName;
545
+ providerLoader.load();
546
+ return providerLoader.getProviderName();
1604
547
  }
1605
548
 
1606
549
  export function isDbAvailable(): boolean {
@@ -1614,7 +557,7 @@ export function isDbAvailable(): boolean {
1614
557
  * trigger a false degraded-mode warning.
1615
558
  */
1616
559
  export function wasDbOpenAttempted(): boolean {
1617
- return _dbOpenAttempted;
560
+ return _dbOpenState.snapshot().attempted;
1618
561
  }
1619
562
 
1620
563
  export function getDbStatus(): {
@@ -1622,56 +565,44 @@ export function getDbStatus(): {
1622
565
  provider: ProviderName | null;
1623
566
  attempted: boolean;
1624
567
  lastError: Error | null;
1625
- lastPhase: "open" | "initSchema" | "vacuum-recovery" | null;
568
+ lastPhase: DbOpenPhase | null;
1626
569
  } {
1627
- loadProvider();
570
+ providerLoader.load();
571
+ const openState = _dbOpenState.snapshot();
1628
572
  return {
1629
573
  available: currentDb !== null,
1630
- provider: providerName,
1631
- attempted: _dbOpenAttempted,
1632
- lastError: _lastDbError,
1633
- lastPhase: _lastDbPhase,
574
+ provider: providerLoader.getProviderName(),
575
+ attempted: openState.attempted,
576
+ lastError: openState.lastError,
577
+ lastPhase: openState.lastPhase,
1634
578
  };
1635
579
  }
1636
580
 
1637
581
  export function openDatabase(path: string): boolean {
1638
- _dbOpenAttempted = true;
582
+ _dbOpenState.markAttempted();
1639
583
  if (currentDb && currentPath !== path) closeDatabase();
1640
584
  if (currentDb && currentPath === path) return true;
1641
585
 
1642
586
  // Reset error state only when a new open attempt is actually going to run.
1643
- _lastDbError = null;
1644
- _lastDbPhase = null;
587
+ _dbOpenState.clearError();
1645
588
 
1646
589
  let rawDb: unknown;
1647
- let fallbackProvider: ProviderName | null = null;
1648
- let fallbackModule: unknown = null;
590
+ let fallbackOpen: SqliteFallbackOpen | null = null;
1649
591
  try {
1650
- rawDb = openRawDb(path);
592
+ rawDb = providerLoader.openRaw(path);
1651
593
  } catch (primaryErr) {
1652
- _lastDbPhase = "open";
1653
- _lastDbError = primaryErr instanceof Error ? primaryErr : new Error(String(primaryErr));
594
+ _dbOpenState.recordError("open", primaryErr);
1654
595
  // node:sqlite loaded but failed to open this file — try better-sqlite3 as fallback.
1655
- if (providerName === "node:sqlite") {
1656
- try {
1657
- const mod = _require(BETTER_SQLITE3_PACKAGE);
1658
- const Db = (mod && mod.default) ? mod.default : mod;
1659
- if (typeof Db === "function") {
1660
- rawDb = new Db(path);
1661
- fallbackProvider = "better-sqlite3";
1662
- fallbackModule = Db;
1663
- _lastDbError = null;
1664
- _lastDbPhase = null;
1665
- }
1666
- } catch {
1667
- // fallback unavailable; surface original error
1668
- }
596
+ fallbackOpen = providerLoader.tryOpenBetterSqliteFallback(path);
597
+ if (fallbackOpen) {
598
+ rawDb = fallbackOpen.rawDb;
599
+ _dbOpenState.clearError();
1669
600
  }
1670
601
  if (!rawDb) throw primaryErr;
1671
602
  }
1672
603
  if (!rawDb) return false;
1673
604
 
1674
- const adapter = createAdapter(rawDb);
605
+ const adapter = createDbAdapter(rawDb);
1675
606
  const fileBacked = path !== ":memory:";
1676
607
  try {
1677
608
  initSchema(adapter, fileBacked);
@@ -1684,24 +615,19 @@ export function openDatabase(path: string): boolean {
1684
615
  initSchema(adapter, fileBacked);
1685
616
  process.stderr.write("gsd-db: recovered corrupt database via VACUUM\n");
1686
617
  } catch (retryErr) {
1687
- _lastDbPhase = "vacuum-recovery";
1688
- _lastDbError = retryErr instanceof Error ? retryErr : new Error(String(retryErr));
618
+ _dbOpenState.recordError("vacuum-recovery", retryErr);
1689
619
  try { adapter.close(); } catch (e) { logWarning("db", `close after VACUUM failed: ${(e as Error).message}`); }
1690
620
  throw retryErr;
1691
621
  }
1692
622
  } else {
1693
- _lastDbPhase = "initSchema";
1694
- _lastDbError = err instanceof Error ? err : new Error(String(err));
623
+ _dbOpenState.recordError("initSchema", err);
1695
624
  try { adapter.close(); } catch (e) { logWarning("db", `close after initSchema failed: ${(e as Error).message}`); }
1696
625
  throw err;
1697
626
  }
1698
627
  }
1699
628
 
1700
629
  // Commit fallback provider switch only after open + schema both succeeded.
1701
- if (fallbackProvider) {
1702
- providerName = fallbackProvider;
1703
- providerModule = fallbackModule;
1704
- }
630
+ if (fallbackOpen) providerLoader.commitFallback(fallbackOpen);
1705
631
 
1706
632
  currentDb = adapter;
1707
633
  currentPath = path;
@@ -1740,9 +666,7 @@ export function closeDatabase(): void {
1740
666
  }
1741
667
  // Reset session-scoped state unconditionally so stale error info from a
1742
668
  // failed open doesn't persist into the next open attempt or status check.
1743
- _dbOpenAttempted = false;
1744
- _lastDbError = null;
1745
- _lastDbPhase = null;
669
+ _dbOpenState.reset();
1746
670
  }
1747
671
 
1748
672
  /**
@@ -1790,7 +714,16 @@ export function checkpointDatabase(): void {
1790
714
  } catch (e) { logWarning("db", `WAL checkpoint failed: ${(e as Error).message}`); }
1791
715
  }
1792
716
 
1793
- let _txDepth = 0;
717
+ const _transactionRunner = createDbTransactionRunner();
718
+
719
+ function createTransactionControls(db: DbAdapter) {
720
+ return {
721
+ begin: () => db.exec("BEGIN"),
722
+ beginRead: () => db.exec("BEGIN DEFERRED"),
723
+ commit: () => db.exec("COMMIT"),
724
+ rollback: () => db.exec("ROLLBACK"),
725
+ };
726
+ }
1794
727
 
1795
728
  /**
1796
729
  * Whether the current call is running inside an active SQLite transaction.
@@ -1799,35 +732,12 @@ let _txDepth = 0;
1799
732
  * and would mask the original error with a secondary "cannot VACUUM" throw.
1800
733
  */
1801
734
  export function isInTransaction(): boolean {
1802
- return _txDepth > 0;
735
+ return _transactionRunner.isInTransaction();
1803
736
  }
1804
737
 
1805
738
  export function transaction<T>(fn: () => T): T {
1806
739
  if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1807
-
1808
- // Re-entrant: if already inside a transaction, just run fn() without
1809
- // starting a new one. SQLite does not support nested BEGIN/COMMIT.
1810
- if (_txDepth > 0) {
1811
- _txDepth++;
1812
- try {
1813
- return fn();
1814
- } finally {
1815
- _txDepth--;
1816
- }
1817
- }
1818
-
1819
- currentDb.exec("BEGIN");
1820
- _txDepth++;
1821
- try {
1822
- const result = fn();
1823
- currentDb.exec("COMMIT");
1824
- return result;
1825
- } catch (err) {
1826
- currentDb.exec("ROLLBACK");
1827
- throw err;
1828
- } finally {
1829
- _txDepth--;
1830
- }
740
+ return _transactionRunner.transaction(createTransactionControls(currentDb), fn);
1831
741
  }
1832
742
 
1833
743
  /**
@@ -1840,36 +750,14 @@ export function transaction<T>(fn: () => T): T {
1840
750
  export function readTransaction<T>(fn: () => T): T {
1841
751
  if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
1842
752
 
1843
- if (_txDepth > 0) {
1844
- _txDepth++;
1845
- try {
1846
- return fn();
1847
- } finally {
1848
- _txDepth--;
1849
- }
1850
- }
1851
-
1852
- currentDb.exec("BEGIN DEFERRED");
1853
- _txDepth++;
1854
- try {
1855
- const result = fn();
1856
- currentDb.exec("COMMIT");
1857
- return result;
1858
- } catch (err) {
1859
- try {
1860
- currentDb.exec("ROLLBACK");
1861
- } catch (rollbackErr) {
1862
- // A failed ROLLBACK after a failed read is a split-brain signal —
1863
- // the transaction is in an indeterminate state. Surface it via the
1864
- // logger instead of swallowing it.
1865
- logError("db", "snapshotState ROLLBACK failed", {
1866
- error: (rollbackErr as Error).message,
1867
- });
1868
- }
1869
- throw err;
1870
- } finally {
1871
- _txDepth--;
1872
- }
753
+ return _transactionRunner.readTransaction(createTransactionControls(currentDb), fn, (rollbackErr) => {
754
+ // A failed ROLLBACK after a failed read is a split-brain signal —
755
+ // the transaction is in an indeterminate state. Surface it via the
756
+ // logger instead of swallowing it.
757
+ logError("db", "snapshotState ROLLBACK failed", {
758
+ error: rollbackErr.message,
759
+ });
760
+ });
1873
761
  }
1874
762
 
1875
763
  export function insertDecision(d: Omit<Decision, "seq">): void {
@@ -1895,37 +783,13 @@ export function getDecisionById(id: string): Decision | null {
1895
783
  if (!currentDb) return null;
1896
784
  const row = currentDb.prepare("SELECT * FROM decisions WHERE id = ?").get(id);
1897
785
  if (!row) return null;
1898
- return {
1899
- seq: row["seq"] as number,
1900
- id: row["id"] as string,
1901
- when_context: row["when_context"] as string,
1902
- scope: row["scope"] as string,
1903
- decision: row["decision"] as string,
1904
- choice: row["choice"] as string,
1905
- rationale: row["rationale"] as string,
1906
- revisable: row["revisable"] as string,
1907
- made_by: (row["made_by"] as string as import("./types.js").DecisionMadeBy) ?? "agent",
1908
- source: (row["source"] as string) ?? "discussion",
1909
- superseded_by: (row["superseded_by"] as string) ?? null,
1910
- };
786
+ return rowToDecision(row);
1911
787
  }
1912
788
 
1913
789
  export function getActiveDecisions(): Decision[] {
1914
790
  if (!currentDb) return [];
1915
791
  const rows = currentDb.prepare("SELECT * FROM active_decisions").all();
1916
- return rows.map((row) => ({
1917
- seq: row["seq"] as number,
1918
- id: row["id"] as string,
1919
- when_context: row["when_context"] as string,
1920
- scope: row["scope"] as string,
1921
- decision: row["decision"] as string,
1922
- choice: row["choice"] as string,
1923
- rationale: row["rationale"] as string,
1924
- revisable: row["revisable"] as string,
1925
- made_by: (row["made_by"] as string as import("./types.js").DecisionMadeBy) ?? "agent",
1926
- source: (row["source"] as string) ?? "discussion",
1927
- superseded_by: null,
1928
- }));
792
+ return rows.map(rowToActiveDecision);
1929
793
  }
1930
794
 
1931
795
  export function insertRequirement(r: Requirement): void {
@@ -1953,39 +817,13 @@ export function getRequirementById(id: string): Requirement | null {
1953
817
  if (!currentDb) return null;
1954
818
  const row = currentDb.prepare("SELECT * FROM requirements WHERE id = ?").get(id);
1955
819
  if (!row) return null;
1956
- return {
1957
- id: row["id"] as string,
1958
- class: row["class"] as string,
1959
- status: row["status"] as string,
1960
- description: row["description"] as string,
1961
- why: row["why"] as string,
1962
- source: row["source"] as string,
1963
- primary_owner: row["primary_owner"] as string,
1964
- supporting_slices: row["supporting_slices"] as string,
1965
- validation: row["validation"] as string,
1966
- notes: row["notes"] as string,
1967
- full_content: row["full_content"] as string,
1968
- superseded_by: (row["superseded_by"] as string) ?? null,
1969
- };
820
+ return rowToRequirement(row);
1970
821
  }
1971
822
 
1972
823
  export function getActiveRequirements(): Requirement[] {
1973
824
  if (!currentDb) return [];
1974
825
  const rows = currentDb.prepare("SELECT * FROM active_requirements").all();
1975
- return rows.map((row) => ({
1976
- id: row["id"] as string,
1977
- class: row["class"] as string,
1978
- status: row["status"] as string,
1979
- description: row["description"] as string,
1980
- why: row["why"] as string,
1981
- source: row["source"] as string,
1982
- primary_owner: row["primary_owner"] as string,
1983
- supporting_slices: row["supporting_slices"] as string,
1984
- validation: row["validation"] as string,
1985
- notes: row["notes"] as string,
1986
- full_content: row["full_content"] as string,
1987
- superseded_by: null,
1988
- }));
826
+ return rows.map(rowToActiveRequirement);
1989
827
  }
1990
828
 
1991
829
  export function getRequirementCounts(): {
@@ -2002,18 +840,7 @@ export function getRequirementCounts(): {
2002
840
  const rows = currentDb
2003
841
  .prepare("SELECT lower(status) as status, COUNT(*) as count FROM requirements GROUP BY lower(status)")
2004
842
  .all();
2005
- const counts = { active: 0, validated: 0, deferred: 0, outOfScope: 0, blocked: 0, total: 0 };
2006
- for (const row of rows) {
2007
- const status = String(row["status"] ?? "");
2008
- const count = Number(row["count"] ?? 0);
2009
- counts.total += count;
2010
- if (status === "active") counts.active += count;
2011
- else if (status === "validated") counts.validated += count;
2012
- else if (status === "deferred") counts.deferred += count;
2013
- else if (status === "out-of-scope" || status === "out_of_scope") counts.outOfScope += count;
2014
- else if (status === "blocked") counts.blocked += count;
2015
- }
2016
- return counts;
843
+ return rowsToRequirementCounts(rows);
2017
844
  }
2018
845
 
2019
846
  export function getDbOwnerPid(): number {
@@ -2029,9 +856,7 @@ export function _getAdapter(): DbAdapter | null {
2029
856
  }
2030
857
 
2031
858
  export function _resetProvider(): void {
2032
- loadAttempted = false;
2033
- providerModule = null;
2034
- providerName = null;
859
+ providerLoader.reset();
2035
860
  }
2036
861
 
2037
862
  export function upsertDecision(d: Omit<Decision, "seq">): void {
@@ -2101,9 +926,10 @@ export function insertArtifact(a: {
2101
926
  full_content: string;
2102
927
  }): void {
2103
928
  if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
929
+ const contentHash = createHash("sha256").update(a.full_content).digest("hex");
2104
930
  currentDb.prepare(
2105
- `INSERT OR REPLACE INTO artifacts (path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at)
2106
- VALUES (:path, :artifact_type, :milestone_id, :slice_id, :task_id, :full_content, :imported_at)`,
931
+ `INSERT OR REPLACE INTO artifacts (path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at, content_hash)
932
+ VALUES (:path, :artifact_type, :milestone_id, :slice_id, :task_id, :full_content, :imported_at, :content_hash)`,
2107
933
  ).run({
2108
934
  ":path": a.path,
2109
935
  ":artifact_type": a.artifact_type,
@@ -2112,6 +938,7 @@ export function insertArtifact(a: {
2112
938
  ":task_id": a.task_id,
2113
939
  ":full_content": a.full_content,
2114
940
  ":imported_at": new Date().toISOString(),
941
+ ":content_hash": contentHash,
2115
942
  });
2116
943
  }
2117
944
 
@@ -2492,54 +1319,6 @@ export function upsertTaskPlanning(milestoneId: string, sliceId: string, taskId:
2492
1319
  });
2493
1320
  }
2494
1321
 
2495
- export interface SliceRow {
2496
- milestone_id: string;
2497
- id: string;
2498
- title: string;
2499
- status: string;
2500
- risk: string;
2501
- depends: string[];
2502
- demo: string;
2503
- created_at: string;
2504
- completed_at: string | null;
2505
- full_summary_md: string;
2506
- full_uat_md: string;
2507
- goal: string;
2508
- success_criteria: string;
2509
- proof_level: string;
2510
- integration_closure: string;
2511
- observability_impact: string;
2512
- sequence: number;
2513
- replan_triggered_at: string | null;
2514
- is_sketch: number;
2515
- sketch_scope: string;
2516
- }
2517
-
2518
- function rowToSlice(row: Record<string, unknown>): SliceRow {
2519
- return {
2520
- milestone_id: row["milestone_id"] as string,
2521
- id: row["id"] as string,
2522
- title: row["title"] as string,
2523
- status: row["status"] as string,
2524
- risk: row["risk"] as string,
2525
- depends: JSON.parse((row["depends"] as string) || "[]"),
2526
- demo: (row["demo"] as string) ?? "",
2527
- created_at: row["created_at"] as string,
2528
- completed_at: (row["completed_at"] as string) ?? null,
2529
- full_summary_md: (row["full_summary_md"] as string) ?? "",
2530
- full_uat_md: (row["full_uat_md"] as string) ?? "",
2531
- goal: (row["goal"] as string) ?? "",
2532
- success_criteria: (row["success_criteria"] as string) ?? "",
2533
- proof_level: (row["proof_level"] as string) ?? "",
2534
- integration_closure: (row["integration_closure"] as string) ?? "",
2535
- observability_impact: (row["observability_impact"] as string) ?? "",
2536
- sequence: (row["sequence"] as number) ?? 0,
2537
- replan_triggered_at: (row["replan_triggered_at"] as string) ?? null,
2538
- is_sketch: (row["is_sketch"] as number) ?? 0,
2539
- sketch_scope: (row["sketch_scope"] as string) ?? "",
2540
- };
2541
- }
2542
-
2543
1322
  export function getSlice(milestoneId: string, sliceId: string): SliceRow | null {
2544
1323
  if (!currentDb) return null;
2545
1324
  const row = currentDb.prepare("SELECT * FROM slices WHERE milestone_id = :mid AND id = :sid").get({ ":mid": milestoneId, ":sid": sliceId });
@@ -2574,116 +1353,6 @@ export function setSliceSummaryMd(milestoneId: string, sliceId: string, summaryM
2574
1353
  ).run({ ":mid": milestoneId, ":sid": sliceId, ":summary_md": summaryMd, ":uat_md": uatMd });
2575
1354
  }
2576
1355
 
2577
- export interface TaskRow {
2578
- milestone_id: string;
2579
- slice_id: string;
2580
- id: string;
2581
- title: string;
2582
- status: string;
2583
- one_liner: string;
2584
- narrative: string;
2585
- verification_result: string;
2586
- duration: string;
2587
- completed_at: string | null;
2588
- blocker_discovered: boolean;
2589
- deviations: string;
2590
- known_issues: string;
2591
- key_files: string[];
2592
- key_decisions: string[];
2593
- full_summary_md: string;
2594
- description: string;
2595
- estimate: string;
2596
- files: string[];
2597
- verify: string;
2598
- inputs: string[];
2599
- expected_output: string[];
2600
- observability_impact: string;
2601
- full_plan_md: string;
2602
- sequence: number;
2603
- // ADR-011 Phase 2 escalation fields
2604
- blocker_source: string;
2605
- escalation_pending: number;
2606
- escalation_awaiting_review: number;
2607
- escalation_artifact_path: string | null;
2608
- escalation_override_applied_at: string | null;
2609
- }
2610
-
2611
- function parseTaskArrayColumn(raw: unknown): string[] {
2612
- if (typeof raw !== "string" || raw.trim() === "") return [];
2613
-
2614
- try {
2615
- const parsed = JSON.parse(raw);
2616
- if (Array.isArray(parsed)) return parsed.map((value) => String(value));
2617
- if (parsed === null || parsed === undefined || parsed === "") return [];
2618
- return [String(parsed)];
2619
- } catch {
2620
- // Older/corrupt rows may contain comma-separated strings instead of JSON.
2621
- return raw
2622
- .split(",")
2623
- .map((value) => value.trim())
2624
- .filter(Boolean);
2625
- }
2626
- }
2627
-
2628
- function rowToTask(row: Record<string, unknown>): TaskRow {
2629
- const parseTaskArray = (value: unknown): string[] => {
2630
- if (Array.isArray(value)) {
2631
- return value.filter((entry): entry is string => typeof entry === "string");
2632
- }
2633
- if (typeof value !== "string") return [];
2634
-
2635
- const trimmed = value.trim();
2636
- if (!trimmed) return [];
2637
-
2638
- try {
2639
- const parsed = JSON.parse(trimmed);
2640
- if (Array.isArray(parsed)) {
2641
- return parsed.filter((entry): entry is string => typeof entry === "string");
2642
- }
2643
- if (typeof parsed === "string" && parsed.trim()) {
2644
- return [parsed.trim()];
2645
- }
2646
- } catch {
2647
- // Older/corrupt DB rows may contain raw comma-separated paths instead of JSON arrays.
2648
- }
2649
-
2650
- return trimmed.split(",").map((entry) => entry.trim()).filter(Boolean);
2651
- };
2652
-
2653
- return {
2654
- milestone_id: row["milestone_id"] as string,
2655
- slice_id: row["slice_id"] as string,
2656
- id: row["id"] as string,
2657
- title: row["title"] as string,
2658
- status: row["status"] as string,
2659
- one_liner: row["one_liner"] as string,
2660
- narrative: row["narrative"] as string,
2661
- verification_result: row["verification_result"] as string,
2662
- duration: row["duration"] as string,
2663
- completed_at: (row["completed_at"] as string) ?? null,
2664
- blocker_discovered: (row["blocker_discovered"] as number) === 1,
2665
- deviations: row["deviations"] as string,
2666
- known_issues: row["known_issues"] as string,
2667
- key_files: parseTaskArrayColumn(row["key_files"]),
2668
- key_decisions: parseTaskArrayColumn(row["key_decisions"]),
2669
- full_summary_md: row["full_summary_md"] as string,
2670
- description: (row["description"] as string) ?? "",
2671
- estimate: (row["estimate"] as string) ?? "",
2672
- files: parseTaskArray(row["files"]),
2673
- verify: (row["verify"] as string) ?? "",
2674
- inputs: parseTaskArray(row["inputs"]),
2675
- expected_output: parseTaskArray(row["expected_output"]),
2676
- observability_impact: (row["observability_impact"] as string) ?? "",
2677
- full_plan_md: (row["full_plan_md"] as string) ?? "",
2678
- sequence: (row["sequence"] as number) ?? 0,
2679
- blocker_source: (row["blocker_source"] as string) ?? "",
2680
- escalation_pending: (row["escalation_pending"] as number) ?? 0,
2681
- escalation_awaiting_review: (row["escalation_awaiting_review"] as number) ?? 0,
2682
- escalation_artifact_path: (row["escalation_artifact_path"] as string) ?? null,
2683
- escalation_override_applied_at: (row["escalation_override_applied_at"] as string) ?? null,
2684
- };
2685
- }
2686
-
2687
1356
  export function getTask(milestoneId: string, sliceId: string, taskId: string): TaskRow | null {
2688
1357
  if (!currentDb) return null;
2689
1358
  const row = currentDb.prepare(
@@ -2701,6 +1370,45 @@ export function getSliceTasks(milestoneId: string, sliceId: string): TaskRow[] {
2701
1370
  return rows.map(rowToTask);
2702
1371
  }
2703
1372
 
1373
+ export function getCompletedMilestoneTaskFileHints(milestoneId: string): string[] {
1374
+ if (!currentDb) return [];
1375
+ const rows = currentDb.prepare(
1376
+ `SELECT files, key_files
1377
+ FROM tasks
1378
+ WHERE milestone_id = :mid AND status IN ('complete', 'done')`,
1379
+ ).all({ ":mid": milestoneId }) as Array<Record<string, unknown>>;
1380
+
1381
+ const hints = new Set<string>();
1382
+ for (const row of rows) {
1383
+ for (const raw of [row["files"], row["key_files"]]) {
1384
+ for (const file of parseStringArrayColumn(raw)) {
1385
+ const normalized = normalizeRepoPath(file);
1386
+ if (normalized) hints.add(normalized);
1387
+ }
1388
+ }
1389
+ }
1390
+ return [...hints];
1391
+ }
1392
+
1393
+ function parseStringArrayColumn(raw: unknown): string[] {
1394
+ if (Array.isArray(raw)) return raw.filter((entry): entry is string => typeof entry === "string");
1395
+ if (typeof raw !== "string") return [];
1396
+ const trimmed = raw.trim();
1397
+ if (!trimmed) return [];
1398
+ try {
1399
+ const parsed = JSON.parse(trimmed);
1400
+ if (Array.isArray(parsed)) return parsed.filter((entry): entry is string => typeof entry === "string");
1401
+ if (typeof parsed === "string") return [parsed];
1402
+ } catch {
1403
+ return trimmed.split(",");
1404
+ }
1405
+ return [];
1406
+ }
1407
+
1408
+ function normalizeRepoPath(file: string): string {
1409
+ return file.trim().replace(/\\/g, "/").replace(/^\.\/+/, "");
1410
+ }
1411
+
2704
1412
  // ─── ADR-011 Phase 2 escalation helpers ──────────────────────────────────
2705
1413
 
2706
1414
  /** Set pause-on-escalation state on a completed task. Mutually exclusive with awaiting_review. */
@@ -2865,72 +1573,6 @@ export function getVerificationEvidence(milestoneId: string, sliceId: string, ta
2865
1573
  return rows as unknown as VerificationEvidenceRow[];
2866
1574
  }
2867
1575
 
2868
- export interface MilestoneRow {
2869
- id: string;
2870
- title: string;
2871
- status: string;
2872
- depends_on: string[];
2873
- created_at: string;
2874
- completed_at: string | null;
2875
- vision: string;
2876
- success_criteria: string[];
2877
- key_risks: Array<{ risk: string; whyItMatters: string }>;
2878
- proof_strategy: Array<{ riskOrUnknown: string; retireIn: string; whatWillBeProven: string }>;
2879
- verification_contract: string;
2880
- verification_integration: string;
2881
- verification_operational: string;
2882
- verification_uat: string;
2883
- definition_of_done: string[];
2884
- requirement_coverage: string;
2885
- boundary_map_markdown: string;
2886
- sequence: number;
2887
- }
2888
-
2889
- function rowToMilestone(row: Record<string, unknown>): MilestoneRow {
2890
- return {
2891
- id: row["id"] as string,
2892
- title: row["title"] as string,
2893
- status: row["status"] as string,
2894
- depends_on: JSON.parse((row["depends_on"] as string) || "[]"),
2895
- created_at: row["created_at"] as string,
2896
- completed_at: (row["completed_at"] as string) ?? null,
2897
- vision: (row["vision"] as string) ?? "",
2898
- success_criteria: JSON.parse((row["success_criteria"] as string) || "[]"),
2899
- key_risks: JSON.parse((row["key_risks"] as string) || "[]"),
2900
- proof_strategy: JSON.parse((row["proof_strategy"] as string) || "[]"),
2901
- verification_contract: (row["verification_contract"] as string) ?? "",
2902
- verification_integration: (row["verification_integration"] as string) ?? "",
2903
- verification_operational: (row["verification_operational"] as string) ?? "",
2904
- verification_uat: (row["verification_uat"] as string) ?? "",
2905
- definition_of_done: JSON.parse((row["definition_of_done"] as string) || "[]"),
2906
- requirement_coverage: (row["requirement_coverage"] as string) ?? "",
2907
- boundary_map_markdown: (row["boundary_map_markdown"] as string) ?? "",
2908
- sequence: Number(row["sequence"] ?? 0),
2909
- };
2910
- }
2911
-
2912
- export interface ArtifactRow {
2913
- path: string;
2914
- artifact_type: string;
2915
- milestone_id: string | null;
2916
- slice_id: string | null;
2917
- task_id: string | null;
2918
- full_content: string;
2919
- imported_at: string;
2920
- }
2921
-
2922
- function rowToArtifact(row: Record<string, unknown>): ArtifactRow {
2923
- return {
2924
- path: row["path"] as string,
2925
- artifact_type: row["artifact_type"] as string,
2926
- milestone_id: (row["milestone_id"] as string) ?? null,
2927
- slice_id: (row["slice_id"] as string) ?? null,
2928
- task_id: (row["task_id"] as string) ?? null,
2929
- full_content: row["full_content"] as string,
2930
- imported_at: row["imported_at"] as string,
2931
- };
2932
- }
2933
-
2934
1576
  export function getAllMilestones(): MilestoneRow[] {
2935
1577
  if (!currentDb) return [];
2936
1578
  const rows = currentDb.prepare(
@@ -3030,36 +1672,36 @@ export function getArtifact(path: string): ArtifactRow | null {
3030
1672
  // ─── Lightweight Query Variants (hot-path optimized) ─────────────────────
3031
1673
 
3032
1674
  /** Fast milestone status check — avoids deserializing JSON planning fields. */
3033
- export function getActiveMilestoneIdFromDb(): { id: string; status: string } | null {
1675
+ export function getActiveMilestoneIdFromDb(): IdStatusSummary | null {
3034
1676
  if (!currentDb) return null;
3035
1677
  const row = currentDb.prepare(
3036
1678
  "SELECT id, status FROM milestones WHERE status NOT IN ('complete', 'parked') ORDER BY id LIMIT 1",
3037
1679
  ).get();
3038
1680
  if (!row) return null;
3039
- return { id: row["id"] as string, status: row["status"] as string };
1681
+ return rowToIdStatusSummary(row);
3040
1682
  }
3041
1683
 
3042
1684
  /** Fast slice status check — avoids deserializing JSON depends/planning fields. */
3043
- export function getSliceStatusSummary(milestoneId: string): Array<{ id: string; status: string }> {
1685
+ export function getSliceStatusSummary(milestoneId: string): IdStatusSummary[] {
3044
1686
  if (!currentDb) return [];
3045
1687
  return currentDb.prepare(
3046
1688
  "SELECT id, status FROM slices WHERE milestone_id = :mid ORDER BY sequence, id",
3047
- ).all({ ":mid": milestoneId }).map((r) => ({ id: r["id"] as string, status: r["status"] as string }));
1689
+ ).all({ ":mid": milestoneId }).map(rowToIdStatusSummary);
3048
1690
  }
3049
1691
 
3050
1692
  /** Fast task status check — avoids deserializing JSON arrays and large text fields. */
3051
- export function getActiveTaskIdFromDb(milestoneId: string, sliceId: string): { id: string; status: string; title: string } | null {
1693
+ export function getActiveTaskIdFromDb(milestoneId: string, sliceId: string): ActiveTaskSummary | null {
3052
1694
  if (!currentDb) return null;
3053
1695
  const row = currentDb.prepare(
3054
1696
  "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",
3055
1697
  ).get({ ":mid": milestoneId, ":sid": sliceId });
3056
1698
  if (!row) return null;
3057
- return { id: row["id"] as string, status: row["status"] as string, title: row["title"] as string };
1699
+ return rowToActiveTaskSummary(row);
3058
1700
  }
3059
1701
 
3060
1702
  /** Count tasks by status for a slice — useful for progress reporting without full row load. */
3061
- export function getSliceTaskCounts(milestoneId: string, sliceId: string): { total: number; done: number; pending: number } {
3062
- if (!currentDb) return { total: 0, done: 0, pending: 0 };
1703
+ export function getSliceTaskCounts(milestoneId: string, sliceId: string): TaskStatusCounts {
1704
+ if (!currentDb) return emptyTaskStatusCounts();
3063
1705
  const row = currentDb.prepare(
3064
1706
  `SELECT
3065
1707
  COUNT(*) as total,
@@ -3067,8 +1709,7 @@ export function getSliceTaskCounts(milestoneId: string, sliceId: string): { tota
3067
1709
  SUM(CASE WHEN status NOT IN ('complete', 'done') THEN 1 ELSE 0 END) as pending
3068
1710
  FROM tasks WHERE milestone_id = :mid AND slice_id = :sid`,
3069
1711
  ).get({ ":mid": milestoneId, ":sid": sliceId });
3070
- if (!row) return { total: 0, done: 0, pending: 0 };
3071
- return { total: (row["total"] as number) ?? 0, done: (row["done"] as number) ?? 0, pending: (row["pending"] as number) ?? 0 };
1712
+ return rowToTaskStatusCounts(row);
3072
1713
  }
3073
1714
 
3074
1715
  // ─── Slice Dependencies (junction table) ─────────────────────────────────
@@ -3089,9 +1730,10 @@ export function syncSliceDependencies(milestoneId: string, sliceId: string, depe
3089
1730
  /** Get all slices that depend on a given slice. */
3090
1731
  export function getDependentSlices(milestoneId: string, sliceId: string): string[] {
3091
1732
  if (!currentDb) return [];
3092
- return currentDb.prepare(
1733
+ const rows = currentDb.prepare(
3093
1734
  "SELECT slice_id FROM slice_dependencies WHERE milestone_id = :mid AND depends_on_slice_id = :sid",
3094
- ).all({ ":mid": milestoneId, ":sid": sliceId }).map((r) => r["slice_id"] as string);
1735
+ ).all({ ":mid": milestoneId, ":sid": sliceId });
1736
+ return rowsToStringColumn(rows, "slice_id");
3095
1737
  }
3096
1738
 
3097
1739
  // ─── Worktree DB Helpers ──────────────────────────────────────────────────
@@ -3168,6 +1810,13 @@ export function reconcileWorktreeDb(
3168
1810
  const hasEscalationAwaiting = wtTaskInfo.some((col) => col["name"] === "escalation_awaiting_review");
3169
1811
  const hasEscalationArtifact = wtTaskInfo.some((col) => col["name"] === "escalation_artifact_path");
3170
1812
  const hasEscalationOverride = wtTaskInfo.some((col) => col["name"] === "escalation_override_applied_at");
1813
+ const wtArtifactInfo = adapter.prepare("PRAGMA wt.table_info('artifacts')").all();
1814
+ const hasArtifactContentHash = wtArtifactInfo.some((col) => col["name"] === "content_hash");
1815
+ const wtMemoryInfo = adapter.prepare("PRAGMA wt.table_info('memories')").all();
1816
+ const hasMemoryScope = wtMemoryInfo.some((col) => col["name"] === "scope");
1817
+ const hasMemoryTags = wtMemoryInfo.some((col) => col["name"] === "tags");
1818
+ const hasMemoryStructuredFields = wtMemoryInfo.some((col) => col["name"] === "structured_fields");
1819
+ const hasMemoryLastHitAt = wtMemoryInfo.some((col) => col["name"] === "last_hit_at");
3171
1820
 
3172
1821
  const decConf = adapter.prepare(
3173
1822
  `SELECT m.id FROM decisions m INNER JOIN wt.decisions w ON m.id = w.id WHERE m.decision != w.decision OR m.choice != w.choice OR m.rationale != w.rationale OR ${
@@ -3215,12 +1864,17 @@ export function reconcileWorktreeDb(
3215
1864
  FROM wt.requirements
3216
1865
  `).run());
3217
1866
 
1867
+ // V27: preserve content_hash. If the worktree predates V27 (no column),
1868
+ // fall back to the main DB's existing hash so reconcile doesn't null
1869
+ // out integrity fingerprints on artifacts that were unchanged in wt.
3218
1870
  merged.artifacts = countChanges(adapter.prepare(`
3219
1871
  INSERT OR REPLACE INTO artifacts (
3220
- path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at
1872
+ path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at, content_hash
3221
1873
  )
3222
- SELECT path, artifact_type, milestone_id, slice_id, task_id, full_content, imported_at
3223
- FROM wt.artifacts
1874
+ SELECT w.path, w.artifact_type, w.milestone_id, w.slice_id, w.task_id, w.full_content, w.imported_at,
1875
+ ${hasArtifactContentHash ? "w.content_hash" : "m.content_hash"}
1876
+ FROM wt.artifacts w
1877
+ LEFT JOIN artifacts m ON m.path = w.path
3224
1878
  `).run());
3225
1879
 
3226
1880
  // Merge milestones — worktree may have updated status/planning fields.
@@ -3322,15 +1976,25 @@ export function reconcileWorktreeDb(
3322
1976
  LEFT JOIN tasks m ON m.milestone_id = w.milestone_id AND m.slice_id = w.slice_id AND m.id = w.id
3323
1977
  `).run());
3324
1978
 
3325
- // Merge memories — keep worktree-learned insights
1979
+ // Merge memories — keep worktree-learned insights.
1980
+ // V18 (scope, tags), V21 (structured_fields), V28 (last_hit_at): for each
1981
+ // column the wt may not yet have (older worktree DB), fall back to the
1982
+ // main DB's existing value via LEFT JOIN so reconcile never silently
1983
+ // resets these fields to defaults on rows that already had them.
3326
1984
  merged.memories = countChanges(adapter.prepare(`
3327
1985
  INSERT OR REPLACE INTO memories (
3328
1986
  seq, id, category, content, confidence, source_unit_type, source_unit_id,
3329
- created_at, updated_at, superseded_by, hit_count
1987
+ created_at, updated_at, superseded_by, hit_count,
1988
+ scope, tags, structured_fields, last_hit_at
3330
1989
  )
3331
- SELECT seq, id, category, content, confidence, source_unit_type, source_unit_id,
3332
- created_at, updated_at, superseded_by, hit_count
3333
- FROM wt.memories
1990
+ SELECT w.seq, w.id, w.category, w.content, w.confidence, w.source_unit_type, w.source_unit_id,
1991
+ w.created_at, w.updated_at, w.superseded_by, w.hit_count,
1992
+ ${hasMemoryScope ? "w.scope" : "COALESCE(m.scope, 'project')"},
1993
+ ${hasMemoryTags ? "w.tags" : "COALESCE(m.tags, '[]')"},
1994
+ ${hasMemoryStructuredFields ? "w.structured_fields" : "m.structured_fields"},
1995
+ ${hasMemoryLastHitAt ? "w.last_hit_at" : "m.last_hit_at"}
1996
+ FROM wt.memories w
1997
+ LEFT JOIN memories m ON m.id = w.id
3334
1998
  `).run());
3335
1999
 
3336
2000
  // Merge verification evidence — append-only, use INSERT OR IGNORE to avoid duplicates
@@ -3491,6 +2155,9 @@ export function deleteMilestone(milestoneId: string): void {
3491
2155
  currentDb!.prepare(
3492
2156
  `DELETE FROM artifacts WHERE milestone_id = :mid`,
3493
2157
  ).run({ ":mid": milestoneId });
2158
+ currentDb!.prepare(
2159
+ `DELETE FROM milestone_commit_attributions WHERE milestone_id = :mid`,
2160
+ ).run({ ":mid": milestoneId });
3494
2161
  currentDb!.prepare(
3495
2162
  `DELETE FROM milestone_leases WHERE milestone_id = :mid`,
3496
2163
  ).run({ ":mid": milestoneId });
@@ -3560,21 +2227,6 @@ export function getLatestAssessmentByScope(
3560
2227
 
3561
2228
  // ─── Quality Gates ───────────────────────────────────────────────────────
3562
2229
 
3563
- function rowToGate(row: Record<string, unknown>): GateRow {
3564
- return {
3565
- milestone_id: row["milestone_id"] as string,
3566
- slice_id: row["slice_id"] as string,
3567
- gate_id: row["gate_id"] as GateId,
3568
- scope: row["scope"] as GateScope,
3569
- task_id: (row["task_id"] as string) ?? "",
3570
- status: row["status"] as GateStatus,
3571
- verdict: row["status"] === "pending" ? null : (row["verdict"] as GateVerdict),
3572
- rationale: (row["rationale"] as string) || "",
3573
- findings: (row["findings"] as string) || "",
3574
- evaluated_at: (row["evaluated_at"] as string) ?? null,
3575
- };
3576
- }
3577
-
3578
2230
  export function insertGateRow(g: {
3579
2231
  milestoneId: string;
3580
2232
  sliceId: string;
@@ -3824,6 +2476,75 @@ export function upsertTurnGitTransaction(entry: {
3824
2476
  });
3825
2477
  }
3826
2478
 
2479
+ export function getMilestoneCommitAttributionShas(milestoneId: string): string[] {
2480
+ if (!currentDb) return [];
2481
+ const rows = currentDb.prepare(
2482
+ `SELECT commit_sha
2483
+ FROM milestone_commit_attributions
2484
+ WHERE milestone_id = :mid
2485
+ ORDER BY created_at, commit_sha`,
2486
+ ).all({ ":mid": milestoneId }) as Array<Record<string, unknown>>;
2487
+ return rows
2488
+ .map((row) => typeof row["commit_sha"] === "string" ? row["commit_sha"] : "")
2489
+ .filter(Boolean);
2490
+ }
2491
+
2492
+ export function recordMilestoneCommitAttribution(entry: {
2493
+ commitSha: string;
2494
+ milestoneId: string;
2495
+ sliceId?: string;
2496
+ taskId?: string;
2497
+ source: "recorded" | "backfill";
2498
+ confidence: number;
2499
+ files: string[];
2500
+ createdAt: string;
2501
+ }): void {
2502
+ if (!currentDb) return;
2503
+ transaction(() => {
2504
+ currentDb!.prepare(
2505
+ `INSERT OR REPLACE INTO milestone_commit_attributions (
2506
+ commit_sha, milestone_id, slice_id, task_id, source, confidence, files_json, created_at
2507
+ ) VALUES (
2508
+ :commit_sha, :milestone_id, :slice_id, :task_id, :source, :confidence, :files_json, :created_at
2509
+ )`,
2510
+ ).run({
2511
+ ":commit_sha": entry.commitSha,
2512
+ ":milestone_id": entry.milestoneId,
2513
+ ":slice_id": entry.sliceId ?? null,
2514
+ ":task_id": entry.taskId ?? null,
2515
+ ":source": entry.source,
2516
+ ":confidence": entry.confidence,
2517
+ ":files_json": JSON.stringify(entry.files),
2518
+ ":created_at": entry.createdAt,
2519
+ });
2520
+
2521
+ currentDb!.prepare(
2522
+ `INSERT OR IGNORE INTO audit_events (
2523
+ event_id, trace_id, turn_id, caused_by, category, type, ts, payload_json
2524
+ ) VALUES (
2525
+ :event_id, :trace_id, :turn_id, :caused_by, :category, :type, :ts, :payload_json
2526
+ )`,
2527
+ ).run({
2528
+ ":event_id": `milestone-commit-attribution:${entry.milestoneId}:${entry.commitSha}`,
2529
+ ":trace_id": "milestone-commit-attribution",
2530
+ ":turn_id": null,
2531
+ ":caused_by": null,
2532
+ ":category": "git",
2533
+ ":type": "milestone-commit-attribution-recorded",
2534
+ ":ts": entry.createdAt,
2535
+ ":payload_json": JSON.stringify({
2536
+ commitSha: entry.commitSha,
2537
+ milestoneId: entry.milestoneId,
2538
+ sliceId: entry.sliceId ?? null,
2539
+ taskId: entry.taskId ?? null,
2540
+ source: entry.source,
2541
+ confidence: entry.confidence,
2542
+ files: entry.files,
2543
+ }),
2544
+ });
2545
+ });
2546
+ }
2547
+
3827
2548
  export function insertAuditEvent(entry: {
3828
2549
  eventId: string;
3829
2550
  traceId: string;
@@ -3927,6 +2648,7 @@ export function clearEngineHierarchy(): void {
3927
2648
  currentDb!.exec("DELETE FROM slice_dependencies");
3928
2649
  currentDb!.exec("DELETE FROM assessments");
3929
2650
  currentDb!.exec("DELETE FROM replan_history");
2651
+ currentDb!.exec("DELETE FROM milestone_commit_attributions");
3930
2652
  currentDb!.exec("DELETE FROM tasks");
3931
2653
  currentDb!.exec("DELETE FROM slices");
3932
2654
  currentDb!.exec("DELETE FROM milestone_leases");
@@ -4377,8 +3099,8 @@ export function updateMemoryContentRow(
4377
3099
  export function incrementMemoryHitCount(id: string, updatedAt: string): void {
4378
3100
  if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
4379
3101
  currentDb.prepare(
4380
- "UPDATE memories SET hit_count = hit_count + 1, updated_at = :updated_at WHERE id = :id",
4381
- ).run({ ":updated_at": updatedAt, ":id": id });
3102
+ "UPDATE memories SET hit_count = hit_count + 1, updated_at = :updated_at, last_hit_at = :last_hit_at WHERE id = :id",
3103
+ ).run({ ":updated_at": updatedAt, ":last_hit_at": updatedAt, ":id": id });
4382
3104
  }
4383
3105
 
4384
3106
  export function supersedeMemoryRow(oldId: string, newId: string, updatedAt: string): void {