@opengsd/gsd-pi 1.2.0-dev.0b870afa → 1.2.0-dev.23d85b63

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 (579) hide show
  1. package/dist/cli-model-override.d.ts +15 -0
  2. package/dist/cli-model-override.js +21 -0
  3. package/dist/cli.js +14 -19
  4. package/dist/headless-events.d.ts +16 -1
  5. package/dist/headless-events.js +19 -2
  6. package/dist/headless.js +8 -1
  7. package/dist/loader.js +6 -4
  8. package/dist/onboarding.js +9 -4
  9. package/dist/provider-migrations.d.ts +23 -0
  10. package/dist/provider-migrations.js +41 -0
  11. package/dist/register-agent-bundles.d.ts +11 -2
  12. package/dist/register-agent-bundles.js +18 -4
  13. package/dist/resource-loader.d.ts +10 -5
  14. package/dist/resource-loader.js +121 -6
  15. package/dist/resources/.managed-resources-content-hash +1 -1
  16. package/dist/resources/extensions/ask-user-questions.js +3 -2
  17. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +447 -215
  18. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +33 -1
  19. package/dist/resources/extensions/google-cli/stream-adapter.js +16 -1
  20. package/dist/resources/extensions/gsd/auto/closeout.js +215 -0
  21. package/dist/resources/extensions/gsd/auto/dispatch-history.js +21 -6
  22. package/dist/resources/extensions/gsd/auto/dispatch.js +365 -0
  23. package/dist/resources/extensions/gsd/auto/finalize.js +347 -0
  24. package/dist/resources/extensions/gsd/auto/loop.js +4 -1
  25. package/dist/resources/extensions/gsd/auto/milestone-lease-reclaim.js +56 -0
  26. package/dist/resources/extensions/gsd/auto/orchestrator.js +119 -18
  27. package/dist/resources/extensions/gsd/auto/phase-helpers.js +146 -0
  28. package/dist/resources/extensions/gsd/auto/phases.js +17 -2372
  29. package/dist/resources/extensions/gsd/auto/pre-dispatch.js +542 -0
  30. package/dist/resources/extensions/gsd/auto/unit-phase.js +694 -0
  31. package/dist/resources/extensions/gsd/auto/workflow-unit-dispatch.js +1 -1
  32. package/dist/resources/extensions/gsd/auto/worktree-safety-phase.js +125 -0
  33. package/dist/resources/extensions/gsd/auto-closeout-messaging.js +90 -0
  34. package/dist/resources/extensions/gsd/auto-dashboard.js +255 -431
  35. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +15 -3
  36. package/dist/resources/extensions/gsd/auto-dispatch.js +19 -1
  37. package/dist/resources/extensions/gsd/auto-model-selection.js +9 -6
  38. package/dist/resources/extensions/gsd/auto-post-unit.js +12 -8
  39. package/dist/resources/extensions/gsd/auto-prompts.js +5 -1
  40. package/dist/resources/extensions/gsd/auto-recovery.js +52 -6
  41. package/dist/resources/extensions/gsd/auto-start.js +28 -7
  42. package/dist/resources/extensions/gsd/auto-worktree.js +48 -3
  43. package/dist/resources/extensions/gsd/auto.js +83 -19
  44. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +4 -2
  45. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -7
  46. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +3 -1
  47. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +32 -3
  48. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +56 -16
  49. package/dist/resources/extensions/gsd/closeout-wizard.js +8 -3
  50. package/dist/resources/extensions/gsd/commands/handlers/core.js +22 -8
  51. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  52. package/dist/resources/extensions/gsd/commands-mcp-status.js +2 -2
  53. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +8 -0
  54. package/dist/resources/extensions/gsd/commands-workflow-templates.js +9 -2
  55. package/dist/resources/extensions/gsd/config-overlay.js +11 -8
  56. package/dist/resources/extensions/gsd/db/engine.js +24 -6
  57. package/dist/resources/extensions/gsd/db/queries.js +30 -0
  58. package/dist/resources/extensions/gsd/db/writers/reconcile.js +19 -1
  59. package/dist/resources/extensions/gsd/db-migration-backup.js +51 -8
  60. package/dist/resources/extensions/gsd/db-transaction.js +27 -23
  61. package/dist/resources/extensions/gsd/db-writer.js +8 -17
  62. package/dist/resources/extensions/gsd/doctor-environment.js +256 -125
  63. package/dist/resources/extensions/gsd/doctor-git-checks.js +5 -1
  64. package/dist/resources/extensions/gsd/doctor-providers.js +1 -1
  65. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +11 -9
  66. package/dist/resources/extensions/gsd/gsd-db.js +15 -20
  67. package/dist/resources/extensions/gsd/guided-flow.js +88 -2
  68. package/dist/resources/extensions/gsd/health-widget.js +87 -28
  69. package/dist/resources/extensions/gsd/mcp-bridge.js +10 -0
  70. package/dist/resources/extensions/gsd/memory-relations.js +1 -1
  71. package/dist/resources/extensions/gsd/milestone-settlement.js +2 -2
  72. package/dist/resources/extensions/gsd/notifications.js +12 -7
  73. package/dist/resources/extensions/gsd/preferences-models.js +17 -9
  74. package/dist/resources/extensions/gsd/preferences.js +91 -5
  75. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +8 -2
  76. package/dist/resources/extensions/gsd/prompts/complete-slice.md +6 -2
  77. package/dist/resources/extensions/gsd/prompts/execute-task.md +7 -2
  78. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -1
  79. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +2 -2
  80. package/dist/resources/extensions/gsd/prompts/run-uat.md +7 -1
  81. package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  82. package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -1
  83. package/dist/resources/extensions/gsd/provider-error-guidance.js +24 -0
  84. package/dist/resources/extensions/gsd/session-lock.js +4 -3
  85. package/dist/resources/extensions/gsd/skill-activation.js +3 -6
  86. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +13 -6
  87. package/dist/resources/extensions/gsd/state.js +6 -2
  88. package/dist/resources/extensions/gsd/tool-surface-readiness.js +83 -31
  89. package/dist/resources/extensions/gsd/tools/complete-task.js +62 -0
  90. package/dist/resources/extensions/gsd/tools/exec-tool.js +2 -109
  91. package/dist/resources/extensions/gsd/tui/render-kit.js +38 -13
  92. package/dist/resources/extensions/gsd/unit-context-composer.js +1 -1
  93. package/dist/resources/extensions/gsd/unit-registry.js +34 -4
  94. package/dist/resources/extensions/gsd/workflow-logger.js +4 -0
  95. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +2 -0
  96. package/dist/resources/extensions/gsd/workflow-mcp-readiness-cache.js +105 -0
  97. package/dist/resources/extensions/gsd/worktree-manager.js +101 -2
  98. package/dist/resources/extensions/gsd/worktree-safety.js +28 -26
  99. package/dist/resources/extensions/gsd/worktree-shell-guard.js +113 -0
  100. package/dist/resources/extensions/gsd/worktree.js +8 -1
  101. package/dist/resources/extensions/mcp-client/manager.js +6 -1
  102. package/dist/resources/extensions/search-the-web/index.js +41 -9
  103. package/dist/resources/extensions/search-the-web/native-search.js +18 -4
  104. package/dist/resources/extensions/shared/gsd-browser-cli.js +40 -2
  105. package/dist/resources/extensions/subagent/index.js +20 -15
  106. package/dist/resources/extensions/subagent/worktree-cwd.js +31 -0
  107. package/dist/resources/skills/create-skill/SKILL.md +3 -0
  108. package/dist/resources/skills/create-skill/references/skill-structure.md +1 -0
  109. package/dist/runtime-checks.d.ts +10 -0
  110. package/dist/runtime-checks.js +27 -0
  111. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  112. package/dist/web/standalone/.next/BUILD_ID +1 -1
  113. package/dist/web/standalone/.next/app-path-routes-manifest.json +10 -10
  114. package/dist/web/standalone/.next/build-manifest.json +2 -2
  115. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  116. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  117. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  125. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  133. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  134. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  135. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  136. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  137. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  138. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  139. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  140. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  141. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  142. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  143. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  144. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  145. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  146. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  147. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  148. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  150. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  152. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  153. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  154. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  156. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  158. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  159. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  160. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  162. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/index.html +1 -1
  167. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  168. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  169. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  170. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  171. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  172. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  173. package/dist/web/standalone/.next/server/app-paths-manifest.json +10 -10
  174. package/dist/web/standalone/.next/server/chunks/{5942.js → 1128.js} +1 -1
  175. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  176. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  178. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  179. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  180. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  181. package/package.json +4 -4
  182. package/packages/cloud-mcp-gateway/package.json +2 -2
  183. package/packages/contracts/package.json +1 -1
  184. package/packages/daemon/package.json +4 -4
  185. package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
  186. package/packages/gsd-agent-core/dist/sdk.js +12 -6
  187. package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
  188. package/packages/gsd-agent-core/package.json +5 -5
  189. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts +5 -5
  190. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  191. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js +12 -24
  192. package/packages/gsd-agent-modes/dist/modes/interactive/components/assistant-message.js.map +1 -1
  193. package/packages/gsd-agent-modes/dist/modes/interactive/components/bash-execution.js +5 -5
  194. package/packages/gsd-agent-modes/dist/modes/interactive/components/bash-execution.js.map +1 -1
  195. package/packages/gsd-agent-modes/dist/modes/interactive/components/branch-summary-message.d.ts +3 -3
  196. package/packages/gsd-agent-modes/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  197. package/packages/gsd-agent-modes/dist/modes/interactive/components/branch-summary-message.js +20 -11
  198. package/packages/gsd-agent-modes/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  199. package/packages/gsd-agent-modes/dist/modes/interactive/components/chat-turn-connect.d.ts +4 -3
  200. package/packages/gsd-agent-modes/dist/modes/interactive/components/chat-turn-connect.d.ts.map +1 -1
  201. package/packages/gsd-agent-modes/dist/modes/interactive/components/chat-turn-connect.js +5 -54
  202. package/packages/gsd-agent-modes/dist/modes/interactive/components/chat-turn-connect.js.map +1 -1
  203. package/packages/gsd-agent-modes/dist/modes/interactive/components/compaction-summary-message.d.ts +2 -4
  204. package/packages/gsd-agent-modes/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  205. package/packages/gsd-agent-modes/dist/modes/interactive/components/compaction-summary-message.js +2 -4
  206. package/packages/gsd-agent-modes/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  207. package/packages/gsd-agent-modes/dist/modes/interactive/components/custom-editor.d.ts +2 -0
  208. package/packages/gsd-agent-modes/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  209. package/packages/gsd-agent-modes/dist/modes/interactive/components/custom-editor.js +4 -0
  210. package/packages/gsd-agent-modes/dist/modes/interactive/components/custom-editor.js.map +1 -1
  211. package/packages/gsd-agent-modes/dist/modes/interactive/components/footer.d.ts +9 -12
  212. package/packages/gsd-agent-modes/dist/modes/interactive/components/footer.d.ts.map +1 -1
  213. package/packages/gsd-agent-modes/dist/modes/interactive/components/footer.js +100 -166
  214. package/packages/gsd-agent-modes/dist/modes/interactive/components/footer.js.map +1 -1
  215. package/packages/gsd-agent-modes/dist/modes/interactive/components/gsd-progress-state.d.ts +2 -0
  216. package/packages/gsd-agent-modes/dist/modes/interactive/components/gsd-progress-state.d.ts.map +1 -0
  217. package/packages/gsd-agent-modes/dist/modes/interactive/components/gsd-progress-state.js +4 -0
  218. package/packages/gsd-agent-modes/dist/modes/interactive/components/gsd-progress-state.js.map +1 -0
  219. package/packages/gsd-agent-modes/dist/modes/interactive/components/gsd-status-widget.d.ts +23 -0
  220. package/packages/gsd-agent-modes/dist/modes/interactive/components/gsd-status-widget.d.ts.map +1 -0
  221. package/packages/gsd-agent-modes/dist/modes/interactive/components/gsd-status-widget.js +178 -0
  222. package/packages/gsd-agent-modes/dist/modes/interactive/components/gsd-status-widget.js.map +1 -0
  223. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts +8 -0
  224. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  225. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js +21 -9
  226. package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js.map +1 -1
  227. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  228. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  229. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
  230. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  231. package/packages/gsd-agent-modes/dist/modes/interactive/components/skill-invocation-message.d.ts +2 -3
  232. package/packages/gsd-agent-modes/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  233. package/packages/gsd-agent-modes/dist/modes/interactive/components/skill-invocation-message.js +2 -3
  234. package/packages/gsd-agent-modes/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  235. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +11 -0
  236. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  237. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +85 -19
  238. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  239. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +71 -3
  240. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  241. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +257 -37
  242. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  243. package/packages/gsd-agent-modes/dist/modes/interactive/components/user-message.d.ts +3 -3
  244. package/packages/gsd-agent-modes/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  245. package/packages/gsd-agent-modes/dist/modes/interactive/components/user-message.js +19 -19
  246. package/packages/gsd-agent-modes/dist/modes/interactive/components/user-message.js.map +1 -1
  247. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts +3 -0
  248. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  249. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +26 -10
  250. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  251. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/extension-ui-controller.d.ts.map +1 -1
  252. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/extension-ui-controller.js +12 -1
  253. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/extension-ui-controller.js.map +1 -1
  254. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  255. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +5 -0
  256. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  257. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.d.ts.map +1 -1
  258. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js +3 -1
  259. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-autocomplete.js.map +1 -1
  260. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  261. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +3 -5
  262. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  263. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js +2 -2
  264. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-dialogs.js.map +1 -1
  265. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts +1 -0
  266. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
  267. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +25 -0
  268. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
  269. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-key-handlers.d.ts.map +1 -1
  270. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-key-handlers.js +1 -0
  271. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-key-handlers.js.map +1 -1
  272. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-init.d.ts +1 -0
  273. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-init.d.ts.map +1 -1
  274. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-init.js +20 -49
  275. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-init.js.map +1 -1
  276. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts +4 -0
  277. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.d.ts.map +1 -1
  278. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode-state.js.map +1 -1
  279. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +10 -2
  280. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  281. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +48 -6
  282. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  283. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
  284. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +4 -0
  285. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
  286. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-ui-messaging.d.ts.map +1 -1
  287. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-ui-messaging.js +0 -1
  288. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-ui-messaging.js.map +1 -1
  289. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  290. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -0
  291. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  292. package/packages/gsd-agent-modes/package.json +7 -7
  293. package/packages/mcp-server/README.md +12 -3
  294. package/packages/mcp-server/dist/cli-runner.d.ts +40 -0
  295. package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -0
  296. package/packages/mcp-server/dist/cli-runner.js +137 -0
  297. package/packages/mcp-server/dist/cli-runner.js.map +1 -0
  298. package/packages/mcp-server/dist/cli.js +2 -58
  299. package/packages/mcp-server/dist/cli.js.map +1 -1
  300. package/packages/mcp-server/dist/pid-registry.d.ts +46 -0
  301. package/packages/mcp-server/dist/pid-registry.d.ts.map +1 -0
  302. package/packages/mcp-server/dist/pid-registry.js +459 -0
  303. package/packages/mcp-server/dist/pid-registry.js.map +1 -0
  304. package/packages/mcp-server/dist/probe-mode.d.ts +4 -0
  305. package/packages/mcp-server/dist/probe-mode.d.ts.map +1 -0
  306. package/packages/mcp-server/dist/probe-mode.js +10 -0
  307. package/packages/mcp-server/dist/probe-mode.js.map +1 -0
  308. package/packages/mcp-server/dist/stdio-watchdog.d.ts +8 -0
  309. package/packages/mcp-server/dist/stdio-watchdog.d.ts.map +1 -0
  310. package/packages/mcp-server/dist/stdio-watchdog.js +40 -0
  311. package/packages/mcp-server/dist/stdio-watchdog.js.map +1 -0
  312. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  313. package/packages/mcp-server/dist/workflow-tools.js +62 -43
  314. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  315. package/packages/mcp-server/package.json +5 -5
  316. package/packages/native/package.json +1 -1
  317. package/packages/pi-agent-core/dist/agent-loop.js +52 -2
  318. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  319. package/packages/pi-agent-core/package.json +1 -1
  320. package/packages/pi-ai/package.json +1 -1
  321. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +28 -2
  322. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
  323. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
  324. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  325. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  326. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  327. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +5 -1
  328. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  329. package/packages/pi-coding-agent/dist/core/extensions/runner.js +3 -1
  330. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  331. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  332. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  333. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  334. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  335. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  336. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  337. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  338. package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
  339. package/packages/pi-coding-agent/dist/theme/theme.js +45 -17
  340. package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
  341. package/packages/pi-coding-agent/package.json +8 -8
  342. package/packages/pi-tui/README.md +15 -0
  343. package/packages/pi-tui/dist/autocomplete.d.ts.map +1 -1
  344. package/packages/pi-tui/dist/autocomplete.js +6 -1
  345. package/packages/pi-tui/dist/autocomplete.js.map +1 -1
  346. package/packages/pi-tui/dist/components/input.js +1 -1
  347. package/packages/pi-tui/dist/components/input.js.map +1 -1
  348. package/packages/pi-tui/dist/components/loader.d.ts.map +1 -1
  349. package/packages/pi-tui/dist/components/loader.js +1 -0
  350. package/packages/pi-tui/dist/components/loader.js.map +1 -1
  351. package/packages/pi-tui/dist/components/select-list.d.ts.map +1 -1
  352. package/packages/pi-tui/dist/components/select-list.js +8 -2
  353. package/packages/pi-tui/dist/components/select-list.js.map +1 -1
  354. package/packages/pi-tui/dist/index.d.ts +2 -2
  355. package/packages/pi-tui/dist/index.d.ts.map +1 -1
  356. package/packages/pi-tui/dist/index.js +2 -2
  357. package/packages/pi-tui/dist/index.js.map +1 -1
  358. package/packages/pi-tui/dist/terminal-image.d.ts +33 -0
  359. package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -1
  360. package/packages/pi-tui/dist/terminal-image.js +54 -2
  361. package/packages/pi-tui/dist/terminal-image.js.map +1 -1
  362. package/packages/pi-tui/dist/terminal.d.ts +12 -0
  363. package/packages/pi-tui/dist/terminal.d.ts.map +1 -1
  364. package/packages/pi-tui/dist/terminal.js +70 -25
  365. package/packages/pi-tui/dist/terminal.js.map +1 -1
  366. package/packages/pi-tui/dist/tui.d.ts +15 -0
  367. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  368. package/packages/pi-tui/dist/tui.js +106 -21
  369. package/packages/pi-tui/dist/tui.js.map +1 -1
  370. package/packages/pi-tui/dist/utils.d.ts.map +1 -1
  371. package/packages/pi-tui/dist/utils.js +110 -36
  372. package/packages/pi-tui/dist/utils.js.map +1 -1
  373. package/packages/pi-tui/package.json +2 -2
  374. package/packages/rpc-client/package.json +2 -2
  375. package/pkg/dist/theme/theme.d.ts.map +1 -1
  376. package/pkg/dist/theme/theme.js +45 -17
  377. package/pkg/dist/theme/theme.js.map +1 -1
  378. package/pkg/package.json +1 -1
  379. package/src/resources/extensions/ask-user-questions.ts +7 -2
  380. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +80 -0
  381. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +531 -226
  382. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +672 -7
  383. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +38 -1
  384. package/src/resources/extensions/google-cli/stream-adapter.ts +22 -1
  385. package/src/resources/extensions/gsd/auto/closeout.ts +309 -0
  386. package/src/resources/extensions/gsd/auto/dispatch-history.ts +22 -6
  387. package/src/resources/extensions/gsd/auto/dispatch.ts +449 -0
  388. package/src/resources/extensions/gsd/auto/finalize.ts +445 -0
  389. package/src/resources/extensions/gsd/auto/loop.ts +4 -1
  390. package/src/resources/extensions/gsd/auto/milestone-lease-reclaim.ts +74 -0
  391. package/src/resources/extensions/gsd/auto/orchestrator.ts +140 -18
  392. package/src/resources/extensions/gsd/auto/phase-helpers.ts +199 -0
  393. package/src/resources/extensions/gsd/auto/phases.ts +58 -3061
  394. package/src/resources/extensions/gsd/auto/pre-dispatch.ts +716 -0
  395. package/src/resources/extensions/gsd/auto/unit-phase.ts +910 -0
  396. package/src/resources/extensions/gsd/auto/workflow-unit-dispatch.ts +1 -1
  397. package/src/resources/extensions/gsd/auto/worktree-safety-phase.ts +149 -0
  398. package/src/resources/extensions/gsd/auto-closeout-messaging.ts +90 -0
  399. package/src/resources/extensions/gsd/auto-dashboard.ts +310 -454
  400. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +15 -2
  401. package/src/resources/extensions/gsd/auto-dispatch.ts +24 -2
  402. package/src/resources/extensions/gsd/auto-model-selection.ts +20 -5
  403. package/src/resources/extensions/gsd/auto-post-unit.ts +16 -9
  404. package/src/resources/extensions/gsd/auto-prompts.ts +5 -1
  405. package/src/resources/extensions/gsd/auto-recovery.ts +62 -8
  406. package/src/resources/extensions/gsd/auto-start.ts +44 -7
  407. package/src/resources/extensions/gsd/auto-worktree.ts +51 -3
  408. package/src/resources/extensions/gsd/auto.ts +118 -18
  409. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +6 -2
  410. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +56 -6
  411. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -1
  412. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +36 -3
  413. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +69 -16
  414. package/src/resources/extensions/gsd/closeout-wizard.ts +11 -2
  415. package/src/resources/extensions/gsd/commands/handlers/core.ts +27 -8
  416. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -2
  417. package/src/resources/extensions/gsd/commands-mcp-status.ts +2 -2
  418. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +7 -0
  419. package/src/resources/extensions/gsd/commands-workflow-templates.ts +11 -4
  420. package/src/resources/extensions/gsd/config-overlay.ts +22 -9
  421. package/src/resources/extensions/gsd/db/engine.ts +26 -6
  422. package/src/resources/extensions/gsd/db/queries.ts +29 -0
  423. package/src/resources/extensions/gsd/db/writers/reconcile.ts +24 -1
  424. package/src/resources/extensions/gsd/db-migration-backup.ts +56 -7
  425. package/src/resources/extensions/gsd/db-transaction.ts +37 -20
  426. package/src/resources/extensions/gsd/db-writer.ts +11 -19
  427. package/src/resources/extensions/gsd/doctor-environment.ts +267 -142
  428. package/src/resources/extensions/gsd/doctor-git-checks.ts +4 -1
  429. package/src/resources/extensions/gsd/doctor-providers.ts +1 -1
  430. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +10 -10
  431. package/src/resources/extensions/gsd/gsd-db.ts +15 -19
  432. package/src/resources/extensions/gsd/guided-flow.ts +128 -2
  433. package/src/resources/extensions/gsd/health-widget.ts +91 -27
  434. package/src/resources/extensions/gsd/mcp-bridge.ts +39 -0
  435. package/src/resources/extensions/gsd/memory-relations.ts +1 -1
  436. package/src/resources/extensions/gsd/milestone-settlement.ts +2 -2
  437. package/src/resources/extensions/gsd/notifications.ts +13 -6
  438. package/src/resources/extensions/gsd/preferences-models.ts +26 -8
  439. package/src/resources/extensions/gsd/preferences.ts +111 -5
  440. package/src/resources/extensions/gsd/prompts/complete-milestone.md +8 -2
  441. package/src/resources/extensions/gsd/prompts/complete-slice.md +6 -2
  442. package/src/resources/extensions/gsd/prompts/execute-task.md +7 -2
  443. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -1
  444. package/src/resources/extensions/gsd/prompts/reactive-execute.md +2 -2
  445. package/src/resources/extensions/gsd/prompts/run-uat.md +7 -1
  446. package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  447. package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -1
  448. package/src/resources/extensions/gsd/provider-error-guidance.ts +32 -0
  449. package/src/resources/extensions/gsd/session-lock.ts +8 -7
  450. package/src/resources/extensions/gsd/skill-activation.ts +3 -6
  451. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +23 -10
  452. package/src/resources/extensions/gsd/state.ts +7 -1
  453. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +1 -1
  454. package/src/resources/extensions/gsd/tests/auto-blocked-remediation-message.test.ts +1 -1
  455. package/src/resources/extensions/gsd/tests/auto-closeout-messaging.test.ts +71 -0
  456. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +68 -116
  457. package/src/resources/extensions/gsd/tests/auto-direct-dispatch-parse.test.ts +33 -0
  458. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +206 -22
  459. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +7 -2
  460. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +16 -1
  461. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +89 -22
  462. package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +1 -1
  463. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +97 -4
  464. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +2 -1
  465. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +236 -0
  466. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +169 -1
  467. package/src/resources/extensions/gsd/tests/auto-verification.test.ts +36 -0
  468. package/src/resources/extensions/gsd/tests/blocker-placeholder-logs.test.ts +218 -0
  469. package/src/resources/extensions/gsd/tests/complete-milestone-prompt-rendering.test.ts +6 -2
  470. package/src/resources/extensions/gsd/tests/complete-task.test.ts +141 -5
  471. package/src/resources/extensions/gsd/tests/core-overlay-fallback.test.ts +1 -0
  472. package/src/resources/extensions/gsd/tests/db-engine-logs.test.ts +207 -0
  473. package/src/resources/extensions/gsd/tests/db-migration-backup.test.ts +68 -19
  474. package/src/resources/extensions/gsd/tests/db-transaction.test.ts +59 -0
  475. package/src/resources/extensions/gsd/tests/db-writer.test.ts +15 -4
  476. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +2 -1
  477. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +62 -0
  478. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +12 -2
  479. package/src/resources/extensions/gsd/tests/dispatch-db-degradation-logs.test.ts +98 -0
  480. package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +55 -0
  481. package/src/resources/extensions/gsd/tests/dispatch-logs.test.ts +103 -0
  482. package/src/resources/extensions/gsd/tests/dispatch-reactive-logs.test.ts +98 -0
  483. package/src/resources/extensions/gsd/tests/dist-redirect.mjs +8 -0
  484. package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +6 -4
  485. package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +117 -91
  486. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +113 -0
  487. package/src/resources/extensions/gsd/tests/flat-rate-routing-guard.test.ts +2 -1
  488. package/src/resources/extensions/gsd/tests/gsd-command-home.test.ts +40 -7
  489. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +19 -0
  490. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +16 -0
  491. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +75 -0
  492. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +15 -0
  493. package/src/resources/extensions/gsd/tests/integration/doctor-environment-async.test.ts +104 -0
  494. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +18 -0
  495. package/src/resources/extensions/gsd/tests/interactive-routing-bypass.test.ts +1 -0
  496. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +47 -16
  497. package/src/resources/extensions/gsd/tests/loop.test.ts +60 -0
  498. package/src/resources/extensions/gsd/tests/mcp-readiness-preflight.test.ts +205 -0
  499. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +6 -5
  500. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +1 -1
  501. package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +1 -1
  502. package/src/resources/extensions/gsd/tests/milestone-settlement.test.ts +92 -0
  503. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +1 -1
  504. package/src/resources/extensions/gsd/tests/model-router.test.ts +139 -0
  505. package/src/resources/extensions/gsd/tests/notifications.test.ts +64 -9
  506. package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +13 -1
  507. package/src/resources/extensions/gsd/tests/orchestrator-legacy-parity.test.ts +1 -1
  508. package/src/resources/extensions/gsd/tests/orchestrator-logs.test.ts +335 -0
  509. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +2 -2
  510. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +5 -0
  511. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +1 -1
  512. package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +1 -1
  513. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +3 -3
  514. package/src/resources/extensions/gsd/tests/prefs-missing-models-crash.test.ts +35 -4
  515. package/src/resources/extensions/gsd/tests/progress-strip-test-helpers.ts +79 -0
  516. package/src/resources/extensions/gsd/tests/prompt-budget-enforcement.test.ts +2 -0
  517. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +11 -2
  518. package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +15 -0
  519. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -4
  520. package/src/resources/extensions/gsd/tests/reconcile-logs.test.ts +244 -0
  521. package/src/resources/extensions/gsd/tests/recovery-finalize-logs.test.ts +119 -0
  522. package/src/resources/extensions/gsd/tests/recovery-verify-logs.test.ts +428 -0
  523. package/src/resources/extensions/gsd/tests/register-extension-guard.test.ts +25 -0
  524. package/src/resources/extensions/gsd/tests/remote-notification-from-desktop.test.ts +31 -81
  525. package/src/resources/extensions/gsd/tests/resume-missing-worktree-warning.test.ts +5 -5
  526. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +7 -1
  527. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +68 -0
  528. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +3 -0
  529. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +170 -48
  530. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -17
  531. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +7 -3
  532. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +17 -1
  533. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +1 -1
  534. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +17 -0
  535. package/src/resources/extensions/gsd/tests/thinking-level-resolution.test.ts +1 -1
  536. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -2
  537. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +184 -10
  538. package/src/resources/extensions/gsd/tests/tui-header-lifecycle.test.ts +40 -86
  539. package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +44 -6
  540. package/src/resources/extensions/gsd/tests/uok-audit.test.ts +194 -0
  541. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
  542. package/src/resources/extensions/gsd/tests/workflow-mcp-readiness-cache.test.ts +119 -0
  543. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +65 -2
  544. package/src/resources/extensions/gsd/tests/workflow-phase-contract-matrix.test.ts +332 -0
  545. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +92 -0
  546. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +1 -1
  547. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +36 -0
  548. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +1 -1
  549. package/src/resources/extensions/gsd/tests/worktree-safety-phase.test.ts +100 -0
  550. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +72 -0
  551. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +22 -0
  552. package/src/resources/extensions/gsd/tests/worktree-write-gate.test.ts +75 -3
  553. package/src/resources/extensions/gsd/tests/worktree.test.ts +18 -0
  554. package/src/resources/extensions/gsd/tool-surface-readiness.ts +126 -19
  555. package/src/resources/extensions/gsd/tools/complete-task.ts +87 -0
  556. package/src/resources/extensions/gsd/tools/exec-tool.ts +2 -118
  557. package/src/resources/extensions/gsd/tui/render-kit.ts +56 -13
  558. package/src/resources/extensions/gsd/unit-context-composer.ts +1 -1
  559. package/src/resources/extensions/gsd/unit-registry.ts +34 -4
  560. package/src/resources/extensions/gsd/workflow-logger.ts +5 -0
  561. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -0
  562. package/src/resources/extensions/gsd/workflow-mcp-readiness-cache.ts +150 -0
  563. package/src/resources/extensions/gsd/worktree-manager.ts +97 -2
  564. package/src/resources/extensions/gsd/worktree-safety.ts +41 -39
  565. package/src/resources/extensions/gsd/worktree-shell-guard.ts +123 -0
  566. package/src/resources/extensions/gsd/worktree.ts +7 -1
  567. package/src/resources/extensions/mcp-client/manager.ts +7 -1
  568. package/src/resources/extensions/search-the-web/index.ts +45 -9
  569. package/src/resources/extensions/search-the-web/native-search.ts +16 -4
  570. package/src/resources/extensions/shared/gsd-browser-cli.ts +41 -2
  571. package/src/resources/extensions/subagent/index.ts +20 -15
  572. package/src/resources/extensions/subagent/tests/worktree-cwd.test.ts +57 -0
  573. package/src/resources/extensions/subagent/worktree-cwd.ts +35 -0
  574. package/src/resources/skills/create-skill/SKILL.md +3 -0
  575. package/src/resources/skills/create-skill/references/skill-structure.md +1 -0
  576. package/dist/resources/skills/gsd-browser/SKILL.md +0 -41
  577. package/src/resources/skills/gsd-browser/SKILL.md +0 -41
  578. /package/dist/web/standalone/.next/static/{T-LTxEw5wir5Lm5T3qEVd → Wn9u2NYq0cyUigB_3Z0_N}/_buildManifest.js +0 -0
  579. /package/dist/web/standalone/.next/static/{T-LTxEw5wir5Lm5T3qEVd → Wn9u2NYq0cyUigB_3Z0_N}/_ssgManifest.js +0 -0
@@ -4,7 +4,7 @@ import type { GSDState } from "../../types.js";
4
4
  import { createRequire } from "node:module";
5
5
 
6
6
  import { computeProgressScore, formatProgressLine } from "../../progress-score.js";
7
- import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath } from "../../preferences.js";
7
+ import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, availableModelIdsFromRegistry, modelIdsForProfileResolution, resolveProfileAnchorProvider, resolveDisabledModelProvidersFromPreferences } from "../../preferences.js";
8
8
  import { ensurePreferencesFile, handlePrefs, handlePrefsMode, handlePrefsWizard, handleLanguage } from "../../commands-prefs-wizard.js";
9
9
  import { runEnvironmentChecks } from "../../doctor-environment.js";
10
10
  import { deriveState } from "../../state.js";
@@ -282,7 +282,10 @@ export async function handleSetup(args: string, ctx: ExtensionCommandContext, pi
282
282
  return;
283
283
  }
284
284
  if (args === "model") {
285
- await handleModel("", ctx, pi);
285
+ // Default model picker: persist settings.json default only — do not pin the
286
+ // session override that /gsd model uses, or PREFERENCES.md per-phase models
287
+ // are ignored for the rest of this session (#model-prefs-precedence).
288
+ await handleModel("", ctx, pi, { pinSession: false });
286
289
  return;
287
290
  }
288
291
  if (args === "keys") {
@@ -412,7 +415,12 @@ async function resolveRequestedModel(
412
415
  return selectModelByProvider(`Multiple models match "${query}"`, partialMatches, ctx, ctx.model);
413
416
  }
414
417
 
415
- async function handleModel(trimmedArgs: string, ctx: ExtensionCommandContext, pi: ExtensionAPI | undefined): Promise<void> {
418
+ async function handleModel(
419
+ trimmedArgs: string,
420
+ ctx: ExtensionCommandContext,
421
+ pi: ExtensionAPI | undefined,
422
+ options?: { pinSession?: boolean },
423
+ ): Promise<void> {
416
424
  const availableModels = ctx.modelRegistry.getAvailable();
417
425
  if (availableModels.length === 0) {
418
426
  ctx.ui.notify("No available models found. Check provider auth and model discovery.", "warning");
@@ -451,16 +459,19 @@ async function handleModel(trimmedArgs: string, ctx: ExtensionCommandContext, pi
451
459
 
452
460
  // /gsd model is an explicit per-session pin for GSD dispatches.
453
461
  // This is captured at auto bootstrap so it survives internal session
454
- // switches during /gsd auto and /gsd next runs.
462
+ // switches during /gsd auto and /gsd next runs. /gsd setup model skips
463
+ // this pin so PREFERENCES.md per-phase models keep precedence.
464
+ const pinSession = options?.pinSession !== false;
455
465
  const sessionId = ctx.sessionManager?.getSessionId?.();
456
- if (sessionId) {
466
+ if (pinSession && sessionId) {
457
467
  setSessionModelOverride(sessionId, {
458
468
  provider: targetModel.provider,
459
469
  id: targetModel.id,
460
470
  });
461
471
  }
462
472
 
463
- ctx.ui.notify(`Model: ${targetModel.provider}/${targetModel.id}`, "info");
473
+ const pinNote = pinSession ? "" : " (default updated; per-phase prefs still apply in auto)";
474
+ ctx.ui.notify(`Model: ${targetModel.provider}/${targetModel.id}${pinNote}`, "info");
464
475
  }
465
476
 
466
477
  export async function handleCoreCommand(
@@ -531,8 +542,16 @@ export async function handleCoreCommand(
531
542
  }
532
543
  if (trimmed === "show-config") {
533
544
  const { GSDConfigOverlay, formatConfigText } = await import("../../config-overlay.js");
545
+ const basePath = projectRoot();
546
+ const anchorProvider = resolveProfileAnchorProvider(ctx.model?.provider);
547
+ const disabledProviders = resolveDisabledModelProvidersFromPreferences();
548
+ const availableModelIds = modelIdsForProfileResolution(ctx.modelRegistry, anchorProvider, disabledProviders);
549
+ const configOptions = {
550
+ basePath,
551
+ ...(availableModelIds && availableModelIds.length > 0 ? { availableModelIds } : {}),
552
+ };
534
553
  const result = await ctx.ui.custom<boolean>(
535
- (tui, theme, _kb, done) => new GSDConfigOverlay(tui, theme, () => done(true)),
554
+ (tui, theme, _kb, done) => new GSDConfigOverlay(tui, theme, () => done(true), configOptions),
536
555
  {
537
556
  overlay: true,
538
557
  overlayOptions: {
@@ -544,7 +563,7 @@ export async function handleCoreCommand(
544
563
  },
545
564
  );
546
565
  if (result === undefined) {
547
- ctx.ui.notify(formatConfigText(), "info");
566
+ ctx.ui.notify(formatConfigText(configOptions), "info");
548
567
  }
549
568
  return true;
550
569
  }
@@ -58,7 +58,7 @@ export async function handleOpsCommand(trimmed: string, ctx: ExtensionCommandCon
58
58
  ["execute-task", "execute"],
59
59
  ["complete-slice", "complete"],
60
60
  ["validate-milestone", "validate-milestone"],
61
- ["complete-milestone", "complete"],
61
+ ["complete-milestone", "complete-milestone"],
62
62
  ]);
63
63
  const aliasPhase = directDispatchAlias.get(trimmed);
64
64
  if (aliasPhase) {
@@ -238,7 +238,10 @@ Examples:
238
238
  if (trimmed === "dispatch" || trimmed.startsWith("dispatch ")) {
239
239
  const phase = trimmed.replace(/^dispatch\s*/, "").trim();
240
240
  if (!phase) {
241
- ctx.ui.notify("Usage: /gsd dispatch <phase> (research|plan|execute|complete|validate|reassess|uat|replan)", "warning");
241
+ ctx.ui.notify(
242
+ "Usage: /gsd dispatch <phase> (research|plan|execute|complete|complete-milestone|validate|reassess|uat|replan)",
243
+ "warning",
244
+ );
242
245
  return true;
243
246
  }
244
247
  const basePath = projectRoot();
@@ -102,7 +102,7 @@ export function formatMcpStatusReport(servers: McpServerStatus[]): string {
102
102
  : s.connected
103
103
  ? `connected — ${s.toolCount} tools`
104
104
  : s.available
105
- ? `available — ${s.toolCount} tools`
105
+ ? `probe available — ${s.toolCount} tools`
106
106
  : "disconnected";
107
107
  const warningText = s.envWarnings?.length ? ` — ${s.envWarnings.length} warning(s)` : "";
108
108
  lines.push(` ${icon} ${s.name} (${s.transport}) — ${status}${warningText}`);
@@ -128,7 +128,7 @@ export function formatMcpServerDetail(server: McpServerDetail): string {
128
128
  lines.push(` Status: error`);
129
129
  lines.push(` Error: ${server.error}`);
130
130
  } else if (server.connected || server.available) {
131
- lines.push(` Status: ${server.connected ? "connected" : "available"}`);
131
+ lines.push(` Status: ${server.connected ? "connected" : "probe available"}`);
132
132
  lines.push(` Tools: ${server.toolCount}`);
133
133
  if (server.tools.length > 0) {
134
134
  lines.push("");
@@ -22,6 +22,7 @@ import {
22
22
  } from "./preferences.js";
23
23
  import { loadFile, saveFile, splitFrontmatter, parseFrontmatterMap } from "./files.js";
24
24
  import { runClaudeImportFlow } from "./claude-import.js";
25
+ import { clearSessionModelOverride } from "./session-model-override.js";
25
26
 
26
27
  const DEFAULT_WIDGET_MODE = "small";
27
28
  const WIDGET_MODE_OPTIONS = [DEFAULT_WIDGET_MODE, "full", "min", "off"] as const;
@@ -1678,6 +1679,12 @@ export async function writePreferencesFile(
1678
1679
  await saveFile(path, content);
1679
1680
 
1680
1681
  if (ctx) {
1682
+ // Per-phase model prefs must beat an earlier /gsd model session pin.
1683
+ const models = prefs.models;
1684
+ if (models && typeof models === "object" && Object.keys(models as object).length > 0) {
1685
+ const sessionId = ctx.sessionManager?.getSessionId?.();
1686
+ if (sessionId) clearSessionModelOverride(sessionId);
1687
+ }
1681
1688
  await ctx.waitForIdle();
1682
1689
  await ctx.reload();
1683
1690
  if (opts?.notifyOnSave !== false) {
@@ -80,13 +80,13 @@ function datePrefix(): string {
80
80
 
81
81
  // ─── State Types ─────────────────────────────────────────────────────────────
82
82
 
83
- interface WorkflowPhaseState {
83
+ export interface WorkflowPhaseState {
84
84
  name: string;
85
85
  index: number;
86
86
  status: "pending" | "active" | "completed";
87
87
  }
88
88
 
89
- interface WorkflowState {
89
+ export interface WorkflowState {
90
90
  template: string;
91
91
  templateName: string;
92
92
  description: string;
@@ -99,6 +99,13 @@ interface WorkflowState {
99
99
  artifactDir: string;
100
100
  }
101
101
 
102
+ export function isWorkflowStateComplete(state: WorkflowState): boolean {
103
+ if (state.completedAt) return true;
104
+ return Array.isArray(state.phases) &&
105
+ state.phases.length > 0 &&
106
+ state.phases.every((phase) => phase.status === "completed");
107
+ }
108
+
102
109
  /**
103
110
  * Write a STATE.json file to track workflow execution state.
104
111
  */
@@ -133,7 +140,7 @@ function writeWorkflowState(
133
140
  * Scan all workflow artifact directories for in-progress STATE.json files.
134
141
  * Returns workflows that were started but not completed.
135
142
  */
136
- function findInProgressWorkflows(basePath: string): WorkflowState[] {
143
+ export function findInProgressWorkflows(basePath: string): WorkflowState[] {
137
144
  const workflowsRoot = join(gsdRoot(basePath), "workflows");
138
145
  if (!existsSync(workflowsRoot)) return [];
139
146
 
@@ -152,7 +159,7 @@ function findInProgressWorkflows(basePath: string): WorkflowState[] {
152
159
  try {
153
160
  const raw = readFileSync(statePath, "utf-8");
154
161
  const state = JSON.parse(raw) as WorkflowState;
155
- if (!state.completedAt) {
162
+ if (!isWorkflowStateComplete(state)) {
156
163
  results.push(state);
157
164
  }
158
165
  } catch { /* corrupted state file — skip */ }
@@ -25,19 +25,27 @@ import {
25
25
 
26
26
  const DEFAULT_WIDGET_MODE = "small";
27
27
 
28
- // ─── Data Collection ──────────────────────────────────────────────────────
29
-
30
28
  interface ConfigSection {
31
29
  title: string;
32
30
  rows: Array<{ label: string; value: string; accent?: boolean }>;
33
31
  }
34
32
 
35
- function collectConfigSections(): ConfigSection[] {
33
+ // ─── Data Collection ──────────────────────────────────────────────────────
34
+
35
+ export interface CollectConfigOptions {
36
+ basePath?: string;
37
+ availableModelIds?: string[];
38
+ }
39
+
40
+ function collectConfigSections(options?: CollectConfigOptions): ConfigSection[] {
36
41
  const sections: ConfigSection[] = [];
37
42
 
38
43
  const globalPrefs = loadGlobalGSDPreferences();
39
- const projectPrefs = loadProjectGSDPreferences();
40
- const effective = loadEffectiveGSDPreferences();
44
+ const projectPrefs = loadProjectGSDPreferences(options?.basePath);
45
+ const loadOpts = options?.availableModelIds
46
+ ? { availableModelIds: options.availableModelIds }
47
+ : undefined;
48
+ const effective = loadEffectiveGSDPreferences(options?.basePath, loadOpts);
41
49
  const prefs = effective?.preferences;
42
50
 
43
51
  // ─── Sources ─────────────────────────────────────────────────────────
@@ -69,7 +77,11 @@ function collectConfigSections(): ConfigSection[] {
69
77
 
70
78
  const modelRows: ConfigSection["rows"] = [];
71
79
  for (const [label, unitType] of unitTypes) {
72
- const resolved = resolveModelWithFallbacksForUnit(unitType);
80
+ const resolved = resolveModelWithFallbacksForUnit(
81
+ unitType,
82
+ options?.basePath,
83
+ options?.availableModelIds,
84
+ );
73
85
  if (resolved) {
74
86
  let val = resolved.primary;
75
87
  if (resolved.fallbacks.length > 0) {
@@ -204,8 +216,8 @@ function collectConfigSections(): ConfigSection[] {
204
216
 
205
217
  // ─── Plain Text Formatter (headless/RPC fallback) ─────────────────────────
206
218
 
207
- export function formatConfigText(): string {
208
- const sections = collectConfigSections();
219
+ export function formatConfigText(options?: CollectConfigOptions): string {
220
+ const sections = collectConfigSections(options);
209
221
  const lines: string[] = ["GSD Configuration\n"];
210
222
 
211
223
  let maxLabel = 0;
@@ -243,11 +255,12 @@ export class GSDConfigOverlay {
243
255
  tui: { requestRender: () => void },
244
256
  theme: Theme,
245
257
  onClose: () => void,
258
+ options?: CollectConfigOptions,
246
259
  ) {
247
260
  this.tui = tui;
248
261
  this.theme = theme;
249
262
  this.onClose = onClose;
250
- this.sections = collectConfigSections();
263
+ this.sections = collectConfigSections(options);
251
264
  }
252
265
 
253
266
  invalidate(): void {
@@ -1,11 +1,13 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: GSD engine — connection ownership, lifecycle, schema/migrations,
3
3
  // and transaction primitives for the single-writer layer. The shared handle
4
- // (currentDb) lives here; writers (db/writers/*) and the Query Module
5
- // (db/queries.ts) read it through getDb()/getDbOrNull().
4
+ // (currentDb) lives here; domain writers, allowlisted coordination/runtime
5
+ // writers, schema/migration helpers, and the Query Module (db/queries.ts) read
6
+ // it through getDb()/getDbOrNull().
6
7
  //
7
8
  // This file legitimately holds DDL and BEGIN/COMMIT control, so it is
8
- // allowlisted in tests/single-writer-invariant.test.ts alongside db/writers/.
9
+ // allowlisted in tests/single-writer-invariant.test.ts alongside the explicit
10
+ // writer layer.
9
11
  import { createRequire } from "node:module";
10
12
  import { existsSync, copyFileSync, mkdirSync, realpathSync } from "node:fs";
11
13
  import { dirname, join } from "node:path";
@@ -16,7 +18,7 @@ import { createDbAdapter, type DbAdapter } from "../db-adapter.js";
16
18
  import { createBaseSchemaObjects } from "../db-base-schema.js";
17
19
  import { createCoordinationTablesV24 } from "../db-coordination-schema.js";
18
20
  import { createDbConnectionCache, type DbConnectionCacheEntry } from "../db-connection-cache.js";
19
- import { backupDatabaseBeforeMigration } from "../db-migration-backup.js";
21
+ import { backupDatabaseBeforeMigration, isMigrationBackupError } from "../db-migration-backup.js";
20
22
  import {
21
23
  applyMigrationV2Artifacts,
22
24
  applyMigrationV3Memories,
@@ -601,8 +603,9 @@ export function openDatabase(path: string): boolean {
601
603
  initSchema(adapter, fileBacked, path);
602
604
  } catch (err) {
603
605
  // Corrupt freelist: DDL fails with "malformed" but VACUUM can rebuild.
604
- // Attempt VACUUM recovery before giving up (see #2519).
605
- if (fileBacked && err instanceof Error && err.message?.includes("malformed")) {
606
+ // Pre-migration backup failures are already pre-DDL and must propagate
607
+ // instead of being masked by VACUUM recovery (see #2519).
608
+ if (shouldAttemptVacuumRecovery(fileBacked, err)) {
606
609
  try {
607
610
  adapter.exec("VACUUM");
608
611
  initSchema(adapter, fileBacked, path);
@@ -634,6 +637,12 @@ export function openDatabase(path: string): boolean {
634
637
  return true;
635
638
  }
636
639
 
640
+ function shouldAttemptVacuumRecovery(fileBacked: boolean, err: unknown): boolean {
641
+ return fileBacked && err instanceof Error && err.message.includes("malformed") && !isMigrationBackupError(err);
642
+ }
643
+
644
+ export const _shouldAttemptVacuumRecoveryForTest = shouldAttemptVacuumRecovery;
645
+
637
646
  export function closeDatabase(): void {
638
647
  if (currentDb) {
639
648
  try {
@@ -735,6 +744,7 @@ function createTransactionControls(db: DbAdapter) {
735
744
  return {
736
745
  begin: () => db.exec("BEGIN"),
737
746
  beginRead: () => db.exec("BEGIN DEFERRED"),
747
+ beginImmediate: () => db.exec("BEGIN IMMEDIATE"),
738
748
  commit: () => db.exec("COMMIT"),
739
749
  rollback: () => db.exec("ROLLBACK"),
740
750
  };
@@ -755,6 +765,16 @@ export function transaction<T>(fn: () => T): T {
755
765
  return _transactionRunner.transaction(createTransactionControls(currentDb), fn);
756
766
  }
757
767
 
768
+ /**
769
+ * Run a BEGIN IMMEDIATE write transaction for operations that need SQLite's
770
+ * reserved writer lock before issuing updates. Re-entrant like transaction():
771
+ * nested calls run inside the outer transaction without a nested BEGIN.
772
+ */
773
+ export function immediateTransaction<T>(fn: () => T): T {
774
+ if (!currentDb) throw new GSDError(GSD_STALE_STATE, "gsd-db: No database open");
775
+ return _transactionRunner.immediateTransaction(createTransactionControls(currentDb), fn);
776
+ }
777
+
758
778
  /**
759
779
  * Wrap a block of reads in a DEFERRED transaction so that all SELECTs observe
760
780
  * a consistent snapshot of the DB even if a concurrent writer commits between
@@ -270,6 +270,35 @@ export function getMilestoneSlices(milestoneId: string): SliceRow[] {
270
270
  return rows.map(rowToSlice);
271
271
  }
272
272
 
273
+ /**
274
+ * Load slices for many milestones in a single query. Returns a Map keyed by
275
+ * milestone_id, preserving `ORDER BY sequence, id` within each bucket.
276
+ */
277
+ export function getSlicesByMilestoneIds(milestoneIds: readonly string[]): Map<string, SliceRow[]> {
278
+ const db = getDbOrNull();
279
+ if (!db || milestoneIds.length === 0) return new Map();
280
+ const idList = [...milestoneIds];
281
+ const placeholders = idList.map((_, i) => `:mid${i}`).join(",");
282
+ const params: Record<string, unknown> = {};
283
+ idList.forEach((id, i) => {
284
+ params[`:mid${i}`] = id;
285
+ });
286
+ const rows = db
287
+ .prepare(`SELECT * FROM slices WHERE milestone_id IN (${placeholders}) ORDER BY milestone_id, sequence, id`)
288
+ .all(params) as Record<string, unknown>[];
289
+ const byMilestone = new Map<string, SliceRow[]>();
290
+ for (const row of rows) {
291
+ const slice = rowToSlice(row);
292
+ const bucket = byMilestone.get(slice.milestone_id);
293
+ if (bucket) {
294
+ bucket.push(slice);
295
+ } else {
296
+ byMilestone.set(slice.milestone_id, [slice]);
297
+ }
298
+ }
299
+ return byMilestone;
300
+ }
301
+
273
302
  /** Dispatch-eligibility shape consumed by decision-path callers (ADR-017). */
274
303
  export interface MilestoneSliceSummary {
275
304
  id: string;
@@ -11,6 +11,29 @@ import { logError, logWarning } from "../../workflow-logger.js";
11
11
  import { getDbOrNull, openDatabase } from "../engine.js";
12
12
  import { TERMINAL_STATUS_SQL } from "../sql-constants.js";
13
13
 
14
+ /**
15
+ * Optional override for the project-root DB open inside reconcileWorktreeDb.
16
+ * Production leaves this null so the real engine.openDatabase runs; tests
17
+ * inject a function returning false to deterministically exercise the
18
+ * cannot-open-main-DB branch (reconcile.ts:82), which is otherwise unreachable
19
+ * without a contrived provider/OS fault (openDatabase rethrows on real failures
20
+ * rather than returning false across providers).
21
+ * @internal
22
+ */
23
+ let _mainDbOpenerFn: ((mainDbPath: string) => boolean) | null = null;
24
+
25
+ export function _setMainDbOpenerFnForTests(
26
+ fn: ((mainDbPath: string) => boolean) | null,
27
+ ): () => void {
28
+ const previous = _mainDbOpenerFn;
29
+ _mainDbOpenerFn = fn;
30
+ return () => { _mainDbOpenerFn = previous; };
31
+ }
32
+
33
+ function openMainDb(mainDbPath: string): boolean {
34
+ return _mainDbOpenerFn ? _mainDbOpenerFn(mainDbPath) : openDatabase(mainDbPath);
35
+ }
36
+
14
37
  export function copyWorktreeDb(srcDbPath: string, destDbPath: string): boolean {
15
38
  try {
16
39
  if (!existsSync(srcDbPath)) return false;
@@ -77,7 +100,7 @@ export function reconcileWorktreeDb(
77
100
  return zero;
78
101
  }
79
102
  if (!getDbOrNull()!) {
80
- const opened = openDatabase(mainDbPath);
103
+ const opened = openMainDb(mainDbPath);
81
104
  if (!opened) {
82
105
  logError("db", "worktree DB reconciliation failed: cannot open main DB");
83
106
  return zero;
@@ -9,6 +9,26 @@ export interface MigrationBackupDeps {
9
9
  logWarning(scope: string, message: string): void;
10
10
  }
11
11
 
12
+ /** Marks pre-migration backup failures so DB-open recovery cannot mask them. */
13
+ export class MigrationBackupError extends Error {
14
+ constructor(message: string, cause?: unknown) {
15
+ super(message, { cause });
16
+ this.name = "MigrationBackupError";
17
+ }
18
+ }
19
+
20
+ /** Returns true for errors raised while checkpointing or copying a migration backup. */
21
+ export function isMigrationBackupError(err: unknown): err is MigrationBackupError {
22
+ return err instanceof MigrationBackupError;
23
+ }
24
+
25
+ /**
26
+ * Creates a same-version backup before file-backed schema migrations.
27
+ *
28
+ * Existing same-version backups are reused. New backups fail closed: WAL
29
+ * checkpoint failures, incomplete checkpoints, and copy failures are logged
30
+ * and then rethrown before migration DDL runs.
31
+ */
12
32
  export function backupDatabaseBeforeMigration(
13
33
  db: DbAdapter,
14
34
  dbPath: string | null,
@@ -21,14 +41,43 @@ export function backupDatabaseBeforeMigration(
21
41
  const backupPath = `${dbPath}.backup-v${currentVersion}`;
22
42
  if (deps.existsSync(backupPath)) return;
23
43
 
24
- try {
25
- db.exec("PRAGMA wal_checkpoint(TRUNCATE)");
26
- } catch {
27
- // Checkpoint is best effort; copying the base file is still better than no backup.
28
- }
44
+ checkpointWal(db);
29
45
  deps.copyFileSync(dbPath, backupPath);
30
46
  } catch (backupErr) {
31
- const message = backupErr instanceof Error ? backupErr.message : String(backupErr);
32
- deps.logWarning("db", `Pre-migration backup failed: ${message}`);
47
+ const error = toMigrationBackupError(backupErr);
48
+ deps.logWarning("db", `Pre-migration backup failed: ${error.message}`);
49
+ throw error;
50
+ }
51
+ }
52
+
53
+ function checkpointWal(db: DbAdapter): void {
54
+ const row = db.prepare("PRAGMA wal_checkpoint(TRUNCATE)").get();
55
+ if (!isCheckpointComplete(row)) {
56
+ const busy = formatCheckpointValue(row, "busy");
57
+ const log = formatCheckpointValue(row, "log");
58
+ const checkpointed = formatCheckpointValue(row, "checkpointed");
59
+ throw new MigrationBackupError(
60
+ `WAL checkpoint incomplete: busy=${busy} log=${log} checkpointed=${checkpointed}`,
61
+ );
33
62
  }
34
63
  }
64
+
65
+ function isCheckpointComplete(row: Record<string, unknown> | undefined): boolean {
66
+ if (!row) return false;
67
+ const busy = Number(row["busy"]);
68
+ const log = Number(row["log"]);
69
+ const checkpointed = Number(row["checkpointed"]);
70
+ if (!Number.isFinite(busy) || !Number.isFinite(log) || !Number.isFinite(checkpointed)) return false;
71
+ return busy === 0 && log === checkpointed;
72
+ }
73
+
74
+ function formatCheckpointValue(row: Record<string, unknown> | undefined, key: string): string {
75
+ const value = row?.[key];
76
+ return value === undefined ? "unknown" : String(value);
77
+ }
78
+
79
+ function toMigrationBackupError(err: unknown): MigrationBackupError {
80
+ if (isMigrationBackupError(err)) return err;
81
+ const message = err instanceof Error ? err.message : String(err);
82
+ return new MigrationBackupError(message, err);
83
+ }
@@ -4,6 +4,8 @@
4
4
  export interface DbTransactionControls {
5
5
  begin(): void;
6
6
  beginRead(): void;
7
+ /** Starts a write transaction that obtains SQLite's reserved lock up front. */
8
+ beginImmediate?(): void;
7
9
  commit(): void;
8
10
  rollback(): void;
9
11
  }
@@ -16,45 +18,47 @@ export class DbTransactionRunner {
16
18
  }
17
19
 
18
20
  transaction<T>(controls: DbTransactionControls, fn: () => T): T {
19
- if (this.depth > 0) {
20
- return this.runNested(fn);
21
- }
21
+ return this.runTransaction(controls, () => controls.begin(), fn);
22
+ }
22
23
 
23
- controls.begin();
24
- this.depth++;
25
- try {
26
- const result = fn();
27
- controls.commit();
28
- return result;
29
- } catch (err) {
30
- controls.rollback();
31
- throw err;
32
- } finally {
33
- this.depth--;
24
+ /**
25
+ * Run a BEGIN IMMEDIATE transaction through the same depth counter as regular
26
+ * transactions so callers can compose it inside existing transaction scopes.
27
+ */
28
+ immediateTransaction<T>(controls: DbTransactionControls, fn: () => T): T {
29
+ if (!controls.beginImmediate) {
30
+ throw new Error("db transaction controls do not support immediate transactions");
34
31
  }
32
+
33
+ return this.runTransaction(controls, () => controls.beginImmediate!(), fn);
35
34
  }
36
35
 
37
36
  readTransaction<T>(
38
37
  controls: DbTransactionControls,
39
38
  fn: () => T,
40
39
  logRollbackError: (error: Error) => void,
40
+ ): T {
41
+ return this.runTransaction(controls, () => controls.beginRead(), fn, logRollbackError);
42
+ }
43
+
44
+ private runTransaction<T>(
45
+ controls: DbTransactionControls,
46
+ begin: () => void,
47
+ fn: () => T,
48
+ logRollbackError?: (error: Error) => void,
41
49
  ): T {
42
50
  if (this.depth > 0) {
43
51
  return this.runNested(fn);
44
52
  }
45
53
 
46
- controls.beginRead();
54
+ begin();
47
55
  this.depth++;
48
56
  try {
49
57
  const result = fn();
50
58
  controls.commit();
51
59
  return result;
52
60
  } catch (err) {
53
- try {
54
- controls.rollback();
55
- } catch (rollbackErr) {
56
- logRollbackError(rollbackErr instanceof Error ? rollbackErr : new Error(String(rollbackErr)));
57
- }
61
+ this.rollback(controls, logRollbackError);
58
62
  throw err;
59
63
  } finally {
60
64
  this.depth--;
@@ -69,6 +73,19 @@ export class DbTransactionRunner {
69
73
  this.depth--;
70
74
  }
71
75
  }
76
+
77
+ private rollback(controls: DbTransactionControls, logRollbackError?: (error: Error) => void): void {
78
+ if (!logRollbackError) {
79
+ controls.rollback();
80
+ return;
81
+ }
82
+
83
+ try {
84
+ controls.rollback();
85
+ } catch (rollbackErr) {
86
+ logRollbackError(rollbackErr instanceof Error ? rollbackErr : new Error(String(rollbackErr)));
87
+ }
88
+ }
72
89
  }
73
90
 
74
91
  export function createDbTransactionRunner(): DbTransactionRunner {
@@ -714,31 +714,23 @@ async function mirrorDecisionToMemory(
714
714
  /**
715
715
  * Extract a milestone/slice reference from a deferral decision.
716
716
  *
717
- * Detects deferrals by checking:
718
- * - scope contains "defer" (e.g., "deferral", "defer")
719
- * - choice or decision contains "defer" + an M###/S## pattern
717
+ * Detects deferrals when the slice reference is part of the deferral phrase.
720
718
  *
721
719
  * Returns { milestoneId, sliceId } if found, null otherwise.
722
720
  */
723
721
  export function extractDeferredSliceRef(
724
722
  fields: Pick<SaveDecisionFields, 'scope' | 'decision' | 'choice'>,
725
723
  ): { milestoneId: string; sliceId: string } | null {
726
- const isDeferral =
727
- /\bdefer(?:ral|red|ring|s)?\b/i.test(fields.scope) ||
728
- /\bdefer(?:ral|red|ring|s)?\b/i.test(fields.choice) ||
729
- /\bdefer(?:ral|red|ring|s)?\b/i.test(fields.decision);
730
-
731
- if (!isDeferral) return null;
732
-
733
- // Look for M###/S## pattern in choice first, then decision
734
- const slicePattern = /\b(M\d{3,4})\/(S\d{2,3})\b/;
735
- const choiceMatch = fields.choice.match(slicePattern);
736
- if (choiceMatch) {
737
- return { milestoneId: choiceMatch[1], sliceId: choiceMatch[2] };
738
- }
739
- const decisionMatch = fields.decision.match(slicePattern);
740
- if (decisionMatch) {
741
- return { milestoneId: decisionMatch[1], sliceId: decisionMatch[2] };
724
+ const defersSlicePattern =
725
+ /\bdefer(?:ral|red|ring|s)?\b\s+(?:(?:of|the)\s+)*(?:slice\s+)?\b(M\d{3,4})\/(S\d{2,3})\b/i;
726
+ const sliceIsDeferredPattern =
727
+ /\b(M\d{3,4})\/(S\d{2,3})\b\s+(?:is|was|will be|should be|can be)\s+defer(?:red|ring)?\b/i;
728
+
729
+ for (const text of [fields.choice, fields.decision, fields.scope]) {
730
+ const match = text.match(defersSlicePattern) ?? text.match(sliceIsDeferredPattern);
731
+ if (match) {
732
+ return { milestoneId: match[1], sliceId: match[2] };
733
+ }
742
734
  }
743
735
 
744
736
  return null;