@opengsd/gsd-pi 1.5.0 → 1.6.0

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 (499) hide show
  1. package/README.md +10 -10
  2. package/dist/resources/.managed-resources-content-hash +1 -1
  3. package/dist/resources/extensions/ask-user-questions.js +1 -1
  4. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +114 -36
  5. package/dist/resources/extensions/gsd/activity-log.js +1 -1
  6. package/dist/resources/extensions/gsd/auto/closeout.js +97 -5
  7. package/dist/resources/extensions/gsd/auto/orchestrator.js +20 -13
  8. package/dist/resources/extensions/gsd/auto/pre-dispatch.js +6 -3
  9. package/dist/resources/extensions/gsd/auto/unit-phase.js +5 -9
  10. package/dist/resources/extensions/gsd/auto-artifact-paths.js +14 -5
  11. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -7
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +69 -17
  13. package/dist/resources/extensions/gsd/auto-model-selection.js +28 -1
  14. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
  15. package/dist/resources/extensions/gsd/auto-prompts.js +29 -117
  16. package/dist/resources/extensions/gsd/auto-recovery.js +50 -6
  17. package/dist/resources/extensions/gsd/auto-start.js +57 -33
  18. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +12 -2
  19. package/dist/resources/extensions/gsd/auto-timers.js +9 -2
  20. package/dist/resources/extensions/gsd/auto-worktree-branch-lifecycle.js +189 -0
  21. package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +133 -0
  22. package/dist/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.js +35 -0
  23. package/dist/resources/extensions/gsd/auto-worktree-creation.js +130 -0
  24. package/dist/resources/extensions/gsd/auto-worktree-entry.js +118 -0
  25. package/dist/resources/extensions/gsd/auto-worktree-merge-already-merged.js +98 -0
  26. package/dist/resources/extensions/gsd/auto-worktree-merge-branch-head.js +52 -0
  27. package/dist/resources/extensions/gsd/auto-worktree-merge-cleanup.js +87 -0
  28. package/dist/resources/extensions/gsd/auto-worktree-merge-code-changes.js +46 -0
  29. package/dist/resources/extensions/gsd/auto-worktree-merge-db-ready.js +68 -0
  30. package/dist/resources/extensions/gsd/auto-worktree-merge-integration-branch.js +51 -0
  31. package/dist/resources/extensions/gsd/auto-worktree-merge-message.js +106 -0
  32. package/dist/resources/extensions/gsd/auto-worktree-merge-pre-teardown.js +64 -0
  33. package/dist/resources/extensions/gsd/auto-worktree-merge-stash.js +168 -0
  34. package/dist/resources/extensions/gsd/auto-worktree-merge.js +302 -0
  35. package/dist/resources/extensions/gsd/auto-worktree-milestone-shelter.js +119 -0
  36. package/dist/resources/extensions/gsd/auto-worktree-path-resolution.js +5 -0
  37. package/dist/resources/extensions/gsd/auto-worktree-path-utils.js +5 -0
  38. package/dist/resources/extensions/gsd/auto-worktree-resource-version.js +41 -0
  39. package/dist/resources/extensions/gsd/auto-worktree-runtime-cleanup.js +99 -0
  40. package/dist/resources/extensions/gsd/auto-worktree-session-registry.js +57 -0
  41. package/dist/resources/extensions/gsd/auto-worktree-sync.js +249 -0
  42. package/dist/resources/extensions/gsd/auto-worktree-teardown.js +120 -0
  43. package/dist/resources/extensions/gsd/auto-worktree.js +20 -2073
  44. package/dist/resources/extensions/gsd/auto.js +106 -34
  45. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -1
  46. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +20 -2
  47. package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
  48. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +185 -27
  49. package/dist/resources/extensions/gsd/codebase-generator.js +7 -1
  50. package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
  51. package/dist/resources/extensions/gsd/commands-workflow-templates.js +3 -3
  52. package/dist/resources/extensions/gsd/compat/compat-marker.js +44 -0
  53. package/dist/resources/extensions/gsd/config-overlay.js +7 -2
  54. package/dist/resources/extensions/gsd/db/engine.js +33 -0
  55. package/dist/resources/extensions/gsd/db/queries.js +9 -9
  56. package/dist/resources/extensions/gsd/db/writers/cascades.js +20 -2
  57. package/dist/resources/extensions/gsd/db-adapter.js +30 -3
  58. package/dist/resources/extensions/gsd/docs/preferences-reference.md +3 -3
  59. package/dist/resources/extensions/gsd/doctor-engine-checks.js +93 -11
  60. package/dist/resources/extensions/gsd/flat-phase-migration.js +32 -3
  61. package/dist/resources/extensions/gsd/forensics.js +1 -1
  62. package/dist/resources/extensions/gsd/git-conflict-resolve.js +2 -2
  63. package/dist/resources/extensions/gsd/git-service.js +45 -0
  64. package/dist/resources/extensions/gsd/gsd-db.js +23 -11
  65. package/dist/resources/extensions/gsd/guided-flow.js +22 -17
  66. package/dist/resources/extensions/gsd/journal.js +1 -1
  67. package/dist/resources/extensions/gsd/markdown-renderer.js +34 -79
  68. package/dist/resources/extensions/gsd/md-importer.js +89 -23
  69. package/dist/resources/extensions/gsd/metrics.js +2 -2
  70. package/dist/resources/extensions/gsd/migration-auto-check.js +30 -3
  71. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +11 -0
  72. package/dist/resources/extensions/gsd/milestone-settlement.js +1 -1
  73. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  74. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -1
  75. package/dist/resources/extensions/gsd/paths.js +87 -52
  76. package/dist/resources/extensions/gsd/post-unit-hooks.js +27 -0
  77. package/dist/resources/extensions/gsd/preferences-models.js +66 -15
  78. package/dist/resources/extensions/gsd/preferences-skills.js +10 -16
  79. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  80. package/dist/resources/extensions/gsd/preferences-validation.js +148 -10
  81. package/dist/resources/extensions/gsd/preferences.js +20 -0
  82. package/dist/resources/extensions/gsd/prompts/system.md +6 -6
  83. package/dist/resources/extensions/gsd/quick.js +12 -3
  84. package/dist/resources/extensions/gsd/rule-registry.js +106 -10
  85. package/dist/resources/extensions/gsd/skill-discovery.js +36 -23
  86. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +2 -1
  87. package/dist/resources/extensions/gsd/state/derive/from-db.js +88 -153
  88. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +1 -10
  89. package/dist/resources/extensions/gsd/state-reconciliation/drift/completion.js +3 -24
  90. package/dist/resources/extensions/gsd/state-reconciliation/index.js +10 -0
  91. package/dist/resources/extensions/gsd/tool-contract.js +14 -0
  92. package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -5
  93. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +16 -10
  94. package/dist/resources/extensions/gsd/tools/reopen-slice.js +5 -0
  95. package/dist/resources/extensions/gsd/tools/reopen-task.js +13 -5
  96. package/dist/resources/extensions/gsd/tools/validate-milestone.js +3 -8
  97. package/dist/resources/extensions/gsd/uat-dispatch.js +94 -0
  98. package/dist/resources/extensions/gsd/unit-registry.js +12 -2
  99. package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +1 -1
  100. package/dist/resources/extensions/gsd/uok/audit-toggle.js +31 -2
  101. package/dist/resources/extensions/gsd/uok/audit.js +3 -0
  102. package/dist/resources/extensions/gsd/uok/gate-runner.js +22 -30
  103. package/dist/resources/extensions/gsd/uok/gitops.js +18 -15
  104. package/dist/resources/extensions/gsd/uok/kernel.js +120 -46
  105. package/dist/resources/extensions/gsd/uok/model-policy.js +17 -14
  106. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -1
  107. package/dist/resources/extensions/gsd/workflow-event-ledger.js +1 -1
  108. package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
  109. package/dist/resources/extensions/gsd/workflow-projections.js +9 -26
  110. package/dist/resources/extensions/gsd/workspace-git-preflight.js +2 -2
  111. package/dist/resources/extensions/gsd/workspace.js +5 -14
  112. package/dist/resources/extensions/gsd/worktree-command.js +1 -1
  113. package/dist/resources/extensions/gsd/worktree-lifecycle.js +14 -9
  114. package/dist/resources/extensions/gsd/worktree-reentry.js +2 -1
  115. package/dist/resources/extensions/shared/gsd-browser-cli.js +29 -0
  116. package/dist/resources/extensions/shared/interview-ui.js +62 -9
  117. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  118. package/dist/web/standalone/.next/BUILD_ID +1 -1
  119. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  120. package/dist/web/standalone/.next/build-manifest.json +2 -2
  121. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  122. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  123. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  131. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  139. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  140. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  141. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  142. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  143. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  144. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  145. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  146. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  147. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  148. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  150. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  152. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  153. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  154. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  156. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  158. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  159. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  160. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  162. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  168. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  170. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  172. package/dist/web/standalone/.next/server/app/index.html +1 -1
  173. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  174. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  175. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  176. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  177. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  178. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  179. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  180. package/dist/web/standalone/.next/server/chunks/{1128.js → 1991.js} +1 -1
  181. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  182. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  184. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  185. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  186. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  187. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  188. package/dist/worktree-cli-create.d.ts +10 -0
  189. package/dist/worktree-cli-create.js +11 -0
  190. package/dist/worktree-cli-format.d.ts +12 -0
  191. package/dist/worktree-cli-format.js +38 -0
  192. package/dist/worktree-cli-plan.d.ts +16 -0
  193. package/dist/worktree-cli-plan.js +19 -0
  194. package/dist/worktree-cli-session.d.ts +13 -0
  195. package/dist/worktree-cli-session.js +18 -0
  196. package/dist/worktree-cli-status.d.ts +35 -0
  197. package/dist/worktree-cli-status.js +54 -0
  198. package/dist/worktree-cli.d.ts +1 -16
  199. package/dist/worktree-cli.js +28 -122
  200. package/integrations/hermes/open_gsd_hermes/gsd_client.py +25 -36
  201. package/integrations/hermes/pyproject.toml +1 -1
  202. package/integrations/hermes/tests/test_gsd_client_timeout.py +4 -4
  203. package/package.json +6 -6
  204. package/packages/cloud-mcp-gateway/package.json +2 -2
  205. package/packages/contracts/package.json +1 -1
  206. package/packages/daemon/dist/orchestrator-agent.d.ts +21 -0
  207. package/packages/daemon/dist/orchestrator-agent.d.ts.map +1 -0
  208. package/packages/daemon/dist/orchestrator-agent.js +113 -0
  209. package/packages/daemon/dist/orchestrator-agent.js.map +1 -0
  210. package/packages/daemon/dist/orchestrator-tools.d.ts +12 -0
  211. package/packages/daemon/dist/orchestrator-tools.d.ts.map +1 -0
  212. package/packages/daemon/dist/orchestrator-tools.js +137 -0
  213. package/packages/daemon/dist/orchestrator-tools.js.map +1 -0
  214. package/packages/daemon/dist/orchestrator.d.ts +4 -56
  215. package/packages/daemon/dist/orchestrator.d.ts.map +1 -1
  216. package/packages/daemon/dist/orchestrator.js +13 -303
  217. package/packages/daemon/dist/orchestrator.js.map +1 -1
  218. package/packages/daemon/dist/orchestrator.test.js +11 -1
  219. package/packages/daemon/dist/orchestrator.test.js.map +1 -1
  220. package/packages/daemon/package.json +4 -4
  221. package/packages/gsd-agent-core/dist/export-html/template.js +53 -4
  222. package/packages/gsd-agent-core/package.json +5 -5
  223. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  224. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +3 -2
  225. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  226. package/packages/gsd-agent-modes/package.json +7 -7
  227. package/packages/mcp-server/package.json +4 -4
  228. package/packages/native/package.json +1 -1
  229. package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
  230. package/packages/pi-agent-core/dist/agent-loop.js +14 -9
  231. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  232. package/packages/pi-agent-core/package.json +1 -1
  233. package/packages/pi-ai/dist/index.d.ts +1 -0
  234. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  235. package/packages/pi-ai/dist/index.js +1 -0
  236. package/packages/pi-ai/dist/index.js.map +1 -1
  237. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  238. package/packages/pi-ai/dist/providers/transform-messages.js +7 -3
  239. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  240. package/packages/pi-ai/dist/tool-result-content.d.ts +3 -0
  241. package/packages/pi-ai/dist/tool-result-content.d.ts.map +1 -0
  242. package/packages/pi-ai/dist/tool-result-content.js +62 -0
  243. package/packages/pi-ai/dist/tool-result-content.js.map +1 -0
  244. package/packages/pi-ai/dist/types.d.ts +8 -20
  245. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  246. package/packages/pi-ai/dist/types.js.map +1 -1
  247. package/packages/pi-ai/package.json +1 -1
  248. package/packages/pi-coding-agent/dist/core/package-manager.d.ts +9 -0
  249. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  250. package/packages/pi-coding-agent/dist/core/package-manager.js +74 -53
  251. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  252. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +6 -0
  253. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  254. package/packages/pi-coding-agent/dist/core/resource-loader.js +30 -2
  255. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  256. package/packages/pi-coding-agent/dist/core/skill-directories.d.ts +66 -0
  257. package/packages/pi-coding-agent/dist/core/skill-directories.d.ts.map +1 -0
  258. package/packages/pi-coding-agent/dist/core/skill-directories.js +138 -0
  259. package/packages/pi-coding-agent/dist/core/skill-directories.js.map +1 -0
  260. package/packages/pi-coding-agent/dist/core/skills.d.ts +4 -1
  261. package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/core/skills.js +4 -1
  263. package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
  264. package/packages/pi-coding-agent/dist/index.d.ts +1 -0
  265. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/index.js +1 -0
  267. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  268. package/packages/pi-coding-agent/package.json +7 -7
  269. package/packages/pi-tui/package.json +2 -2
  270. package/packages/rpc-client/package.json +2 -2
  271. package/pkg/dist/core/export-html/template.js +53 -4
  272. package/pkg/package.json +1 -1
  273. package/src/resources/extensions/ask-user-questions.ts +1 -1
  274. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +146 -33
  275. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +25 -0
  276. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +93 -0
  277. package/src/resources/extensions/gsd/activity-log.ts +1 -1
  278. package/src/resources/extensions/gsd/auto/closeout.ts +114 -7
  279. package/src/resources/extensions/gsd/auto/orchestrator.ts +21 -14
  280. package/src/resources/extensions/gsd/auto/pre-dispatch.ts +6 -3
  281. package/src/resources/extensions/gsd/auto/unit-phase.ts +5 -9
  282. package/src/resources/extensions/gsd/auto-artifact-paths.ts +14 -4
  283. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +13 -7
  284. package/src/resources/extensions/gsd/auto-dispatch.ts +77 -16
  285. package/src/resources/extensions/gsd/auto-model-selection.ts +33 -1
  286. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -2
  287. package/src/resources/extensions/gsd/auto-prompts.ts +53 -113
  288. package/src/resources/extensions/gsd/auto-recovery.ts +50 -6
  289. package/src/resources/extensions/gsd/auto-start.ts +62 -31
  290. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -2
  291. package/src/resources/extensions/gsd/auto-timers.ts +9 -2
  292. package/src/resources/extensions/gsd/auto-worktree-branch-lifecycle.ts +237 -0
  293. package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +166 -0
  294. package/src/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.ts +37 -0
  295. package/src/resources/extensions/gsd/auto-worktree-creation.ts +171 -0
  296. package/src/resources/extensions/gsd/auto-worktree-entry.ts +154 -0
  297. package/src/resources/extensions/gsd/auto-worktree-merge-already-merged.ts +161 -0
  298. package/src/resources/extensions/gsd/auto-worktree-merge-branch-head.ts +83 -0
  299. package/src/resources/extensions/gsd/auto-worktree-merge-cleanup.ts +132 -0
  300. package/src/resources/extensions/gsd/auto-worktree-merge-code-changes.ts +71 -0
  301. package/src/resources/extensions/gsd/auto-worktree-merge-db-ready.ts +112 -0
  302. package/src/resources/extensions/gsd/auto-worktree-merge-integration-branch.ts +99 -0
  303. package/src/resources/extensions/gsd/auto-worktree-merge-message.ts +166 -0
  304. package/src/resources/extensions/gsd/auto-worktree-merge-pre-teardown.ts +93 -0
  305. package/src/resources/extensions/gsd/auto-worktree-merge-stash.ts +213 -0
  306. package/src/resources/extensions/gsd/auto-worktree-merge.ts +391 -0
  307. package/src/resources/extensions/gsd/auto-worktree-milestone-shelter.ts +159 -0
  308. package/src/resources/extensions/gsd/auto-worktree-path-resolution.ts +6 -0
  309. package/src/resources/extensions/gsd/auto-worktree-path-utils.ts +10 -0
  310. package/src/resources/extensions/gsd/auto-worktree-resource-version.ts +44 -0
  311. package/src/resources/extensions/gsd/auto-worktree-runtime-cleanup.ts +119 -0
  312. package/src/resources/extensions/gsd/auto-worktree-session-registry.ts +71 -0
  313. package/src/resources/extensions/gsd/auto-worktree-sync.ts +370 -0
  314. package/src/resources/extensions/gsd/auto-worktree-teardown.ts +161 -0
  315. package/src/resources/extensions/gsd/auto-worktree.ts +69 -2429
  316. package/src/resources/extensions/gsd/auto.ts +114 -47
  317. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -1
  318. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +20 -2
  319. package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
  320. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +218 -27
  321. package/src/resources/extensions/gsd/codebase-generator.ts +7 -1
  322. package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
  323. package/src/resources/extensions/gsd/commands-workflow-templates.ts +3 -3
  324. package/src/resources/extensions/gsd/compat/compat-marker.ts +47 -0
  325. package/src/resources/extensions/gsd/config-overlay.ts +7 -1
  326. package/src/resources/extensions/gsd/db/engine.ts +36 -0
  327. package/src/resources/extensions/gsd/db/queries.ts +9 -9
  328. package/src/resources/extensions/gsd/db/writers/cascades.ts +23 -1
  329. package/src/resources/extensions/gsd/db-adapter.ts +29 -3
  330. package/src/resources/extensions/gsd/docs/preferences-reference.md +3 -3
  331. package/src/resources/extensions/gsd/doctor-engine-checks.ts +109 -10
  332. package/src/resources/extensions/gsd/flat-phase-migration.ts +34 -3
  333. package/src/resources/extensions/gsd/forensics.ts +1 -1
  334. package/src/resources/extensions/gsd/git-conflict-resolve.ts +2 -2
  335. package/src/resources/extensions/gsd/git-service.ts +53 -0
  336. package/src/resources/extensions/gsd/gsd-db.ts +33 -11
  337. package/src/resources/extensions/gsd/guided-flow.ts +26 -18
  338. package/src/resources/extensions/gsd/journal.ts +1 -1
  339. package/src/resources/extensions/gsd/markdown-renderer.ts +52 -91
  340. package/src/resources/extensions/gsd/md-importer.ts +93 -22
  341. package/src/resources/extensions/gsd/metrics.ts +2 -2
  342. package/src/resources/extensions/gsd/migration-auto-check.ts +32 -3
  343. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +15 -0
  344. package/src/resources/extensions/gsd/milestone-settlement.ts +1 -1
  345. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  346. package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -1
  347. package/src/resources/extensions/gsd/paths.ts +108 -51
  348. package/src/resources/extensions/gsd/post-unit-hooks.ts +32 -0
  349. package/src/resources/extensions/gsd/preferences-models.ts +74 -20
  350. package/src/resources/extensions/gsd/preferences-skills.ts +10 -16
  351. package/src/resources/extensions/gsd/preferences-types.ts +54 -1
  352. package/src/resources/extensions/gsd/preferences-validation.ts +146 -9
  353. package/src/resources/extensions/gsd/preferences.ts +20 -0
  354. package/src/resources/extensions/gsd/prompts/system.md +6 -6
  355. package/src/resources/extensions/gsd/quick.ts +11 -3
  356. package/src/resources/extensions/gsd/rule-registry.ts +111 -9
  357. package/src/resources/extensions/gsd/skill-discovery.ts +47 -23
  358. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +3 -1
  359. package/src/resources/extensions/gsd/state/derive/from-db.ts +201 -157
  360. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +1 -9
  361. package/src/resources/extensions/gsd/state-reconciliation/drift/completion.ts +2 -22
  362. package/src/resources/extensions/gsd/state-reconciliation/index.ts +14 -0
  363. package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +169 -1
  364. package/src/resources/extensions/gsd/tests/auto-loop-no-copy-artifacts.test.ts +2 -1
  365. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +41 -2
  366. package/src/resources/extensions/gsd/tests/auto-post-unit-artifact-diagnostic.test.ts +48 -1
  367. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +57 -0
  368. package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +1 -1
  369. package/src/resources/extensions/gsd/tests/auto-start-project-milestone-reconcile.test.ts +29 -1
  370. package/src/resources/extensions/gsd/tests/auto-timeout-recovery-supervisor-inflight-guard.test.ts +159 -0
  371. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +2 -1
  372. package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +1 -1
  373. package/src/resources/extensions/gsd/tests/auto-worktree-merge-already-merged.test.ts +177 -0
  374. package/src/resources/extensions/gsd/tests/auto-worktree-merge-branch-head.test.ts +118 -0
  375. package/src/resources/extensions/gsd/tests/auto-worktree-merge-cleanup.test.ts +115 -0
  376. package/src/resources/extensions/gsd/tests/auto-worktree-merge-code-changes.test.ts +76 -0
  377. package/src/resources/extensions/gsd/tests/auto-worktree-merge-db-ready.test.ts +140 -0
  378. package/src/resources/extensions/gsd/tests/auto-worktree-merge-integration-branch.test.ts +123 -0
  379. package/src/resources/extensions/gsd/tests/auto-worktree-merge-message.test.ts +114 -0
  380. package/src/resources/extensions/gsd/tests/auto-worktree-merge-pre-teardown.test.ts +84 -0
  381. package/src/resources/extensions/gsd/tests/auto-worktree-merge-stash.test.ts +70 -0
  382. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-shelter.test.ts +52 -0
  383. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +6 -6
  384. package/src/resources/extensions/gsd/tests/auto-worktree-resource-version.test.ts +59 -0
  385. package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +3 -1
  386. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  387. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +3 -1
  388. package/src/resources/extensions/gsd/tests/compat-marker.test.ts +85 -0
  389. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +45 -0
  390. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +1 -1
  391. package/src/resources/extensions/gsd/tests/db-adapter.test.ts +39 -0
  392. package/src/resources/extensions/gsd/tests/db-writable-probe.test.ts +66 -0
  393. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -0
  394. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +174 -0
  395. package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +1 -1
  396. package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +71 -1
  397. package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +46 -1
  398. package/src/resources/extensions/gsd/tests/flat-phase-validation-path.test.ts +72 -32
  399. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +40 -0
  400. package/src/resources/extensions/gsd/tests/import-completion-lost-update.test.ts +196 -0
  401. package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +4 -6
  402. package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +2 -1
  403. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +3 -3
  404. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +7 -8
  405. package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +2 -5
  406. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +76 -0
  407. package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +1 -1
  408. package/src/resources/extensions/gsd/tests/integration/merge-preserve-worktree-on-preteardown-error.test.ts +1 -1
  409. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +2 -1
  410. package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +5 -7
  411. package/src/resources/extensions/gsd/tests/integration/paths.test.ts +88 -1
  412. package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +2 -4
  413. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -15
  414. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +1 -1
  415. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +1 -1
  416. package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +1 -1
  417. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +91 -0
  418. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +2 -1
  419. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +439 -0
  420. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +24 -0
  421. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +1 -1
  422. package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -3
  423. package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +1 -1
  424. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +0 -1
  425. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +269 -0
  426. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +8 -1
  427. package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +1 -4
  428. package/src/resources/extensions/gsd/tests/preferences.test.ts +19 -0
  429. package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +5 -0
  430. package/src/resources/extensions/gsd/tests/read-uat-gate-verdict.test.ts +54 -0
  431. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +49 -1
  432. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +52 -0
  433. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +95 -1
  434. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +20 -0
  435. package/src/resources/extensions/gsd/tests/sibling-model-fallbacks.test.ts +189 -0
  436. package/src/resources/extensions/gsd/tests/single-field-model-thinking.test.ts +156 -0
  437. package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +46 -0
  438. package/src/resources/extensions/gsd/tests/skipped-validation-db-atomicity.test.ts +6 -1
  439. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -5
  440. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +32 -0
  441. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +2 -1
  442. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +2 -1
  443. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +1 -1
  444. package/src/resources/extensions/gsd/tests/supervisor-model-swap-inflight-guard.test.ts +181 -0
  445. package/src/resources/extensions/gsd/tests/supervisor-model-swap-thinking-clamp.test.ts +122 -0
  446. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +1 -1
  447. package/src/resources/extensions/gsd/tests/system-flat-phase-layout.test.ts +33 -0
  448. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +4 -4
  449. package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +2 -1
  450. package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +4 -4
  451. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +196 -0
  452. package/src/resources/extensions/gsd/tests/uat-dispatch.test.ts +211 -0
  453. package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +1 -1
  454. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +26 -1
  455. package/src/resources/extensions/gsd/tests/uok-gate-runner.test.ts +39 -0
  456. package/src/resources/extensions/gsd/tests/uok-kernel-path.test.ts +226 -2
  457. package/src/resources/extensions/gsd/tests/uok-model-policy.test.ts +6 -0
  458. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +213 -2
  459. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -1
  460. package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +1 -1
  461. package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +1 -3
  462. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +1 -1
  463. package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +1 -1
  464. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +1 -1
  465. package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +1 -1
  466. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +2 -1
  467. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +5 -2
  468. package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +1 -1
  469. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +1 -1
  470. package/src/resources/extensions/gsd/tool-contract.ts +29 -0
  471. package/src/resources/extensions/gsd/tools/complete-milestone.ts +9 -5
  472. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +19 -8
  473. package/src/resources/extensions/gsd/tools/reopen-slice.ts +5 -0
  474. package/src/resources/extensions/gsd/tools/reopen-task.ts +13 -5
  475. package/src/resources/extensions/gsd/tools/validate-milestone.ts +13 -9
  476. package/src/resources/extensions/gsd/types.ts +23 -4
  477. package/src/resources/extensions/gsd/uat-dispatch.ts +176 -0
  478. package/src/resources/extensions/gsd/unit-registry.ts +16 -2
  479. package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +1 -1
  480. package/src/resources/extensions/gsd/uok/audit-toggle.ts +32 -2
  481. package/src/resources/extensions/gsd/uok/audit.ts +2 -0
  482. package/src/resources/extensions/gsd/uok/gate-runner.ts +26 -36
  483. package/src/resources/extensions/gsd/uok/gitops.ts +21 -18
  484. package/src/resources/extensions/gsd/uok/kernel.ts +169 -48
  485. package/src/resources/extensions/gsd/uok/model-policy.ts +20 -17
  486. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -1
  487. package/src/resources/extensions/gsd/workflow-event-ledger.ts +1 -1
  488. package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
  489. package/src/resources/extensions/gsd/workflow-projections.ts +9 -24
  490. package/src/resources/extensions/gsd/workspace-git-preflight.ts +2 -2
  491. package/src/resources/extensions/gsd/workspace.ts +5 -21
  492. package/src/resources/extensions/gsd/worktree-command.ts +1 -1
  493. package/src/resources/extensions/gsd/worktree-lifecycle.ts +19 -15
  494. package/src/resources/extensions/gsd/worktree-reentry.ts +2 -1
  495. package/src/resources/extensions/shared/gsd-browser-cli.ts +29 -0
  496. package/src/resources/extensions/shared/interview-ui.ts +58 -11
  497. package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +32 -0
  498. /package/dist/web/standalone/.next/static/{bCg3aYrFN1DKZr2dqgE7L → 6xYMOzxVhsQgryneJ5KRc}/_buildManifest.js +0 -0
  499. /package/dist/web/standalone/.next/static/{bCg3aYrFN1DKZr2dqgE7L → 6xYMOzxVhsQgryneJ5KRc}/_ssgManifest.js +0 -0
@@ -1,5 +1,6 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Declarative auto-mode dispatch rules and dispatch resolver.
3
+ import { renderLanguageDirectiveForPrompt } from "./preferences.js";
3
4
  import { loadFile, extractUatType, loadActiveOverrides } from "./files.js";
4
5
  import { getUatBrowserToolSupportError } from "./uat-policy.js";
5
6
  import { isDbAvailable, getMilestoneSlices, getMilestoneSliceSummaries, getClosedSliceIds, getPendingGatesForTurn, markPendingGatesOmittedForTurn, getMilestone, insertArtifact, insertAssessment, setSliceSketchFlag, transaction, getAssessment, getSliceRunUatAssessment, } from "./gsd-db.js";
@@ -11,8 +12,9 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync, readdir
11
12
  import { logWarning, logError } from "./workflow-logger.js";
12
13
  import { dirname, join, sep } from "node:path";
13
14
  import { hasImplementationArtifacts } from "./milestone-implementation-evidence.js";
14
- import { buildDiscussMilestonePrompt, buildDiscussProjectPrompt, buildDiscussRequirementsPrompt, buildResearchDecisionPrompt, buildResearchProjectPrompt, buildResearchMilestonePrompt, buildPlanMilestonePrompt, buildResearchSlicePrompt, buildPlanSlicePrompt, buildRefineSlicePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReplanSlicePrompt, buildRunUatPrompt, buildReassessRoadmapPrompt, buildRewriteDocsPrompt, buildReactiveExecutePrompt, buildGateEvaluatePrompt, buildParallelResearchSlicesPrompt, checkNeedsReassessment, checkNeedsRunUat, } from "./auto-prompts.js";
15
- import { resolveModelWithFallbacksForUnit, resolveThinkingLevelForUnit } from "./preferences-models.js";
15
+ import { buildDiscussMilestonePrompt, buildDiscussProjectPrompt, buildDiscussRequirementsPrompt, buildResearchDecisionPrompt, buildResearchProjectPrompt, buildResearchMilestonePrompt, buildPlanMilestonePrompt, buildResearchSlicePrompt, buildPlanSlicePrompt, buildRefineSlicePrompt, buildExecuteTaskPrompt, buildCompleteSlicePrompt, buildCompleteMilestonePrompt, buildValidateMilestonePrompt, buildReplanSlicePrompt, buildRunUatPrompt, buildReassessRoadmapPrompt, buildRewriteDocsPrompt, buildReactiveExecutePrompt, buildGateEvaluatePrompt, buildParallelResearchSlicesPrompt, checkNeedsReassessment, loadRoadmapCompletedSliceCandidates, } from "./auto-prompts.js";
16
+ import { checkNeedsRunUat } from "./uat-dispatch.js";
17
+ import { normalizeModelFieldConfig, resolveModelWithFallbacksForUnit, resolveThinkingLevelForUnit } from "./preferences-models.js";
16
18
  import { resolveUokFlags } from "./uok/flags.js";
17
19
  import { selectReactiveDispatchBatch } from "./uok/execution-graph.js";
18
20
  import { getMilestonePipelineVariant } from "./milestone-scope-classifier.js";
@@ -141,12 +143,21 @@ export async function readUatGateVerdict(basePath, mid, sliceId) {
141
143
  if (assessmentScope === "roadmap") {
142
144
  return null;
143
145
  }
144
- const assessmentVerdict = extractVerdict(assessmentContent);
145
- if (assessmentVerdict) {
146
- return {
147
- verdict: assessmentVerdict,
148
- uatType: uatType ?? extractUatType(assessmentContent),
149
- };
146
+ // Backfilled assessments (#1258) are placeholders created during milestone
147
+ // validation for completed slices that never produced a real UAT ASSESSMENT
148
+ // (e.g. artifact-driven UAT that was never dispatched). Their fabricated
149
+ // verdict must not be treated as a genuine UAT sign-off — otherwise "never
150
+ // checked" is silently read as "passed". Skip the placeholder and fall
151
+ // through to the authoritative run-uat DB row (which stays null unless a
152
+ // real UAT was actually recorded).
153
+ if (assessmentScope !== BACKFILL_ASSESSMENT_SCOPE) {
154
+ const assessmentVerdict = extractVerdict(assessmentContent);
155
+ if (assessmentVerdict) {
156
+ return {
157
+ verdict: assessmentVerdict,
158
+ uatType: uatType ?? extractUatType(assessmentContent),
159
+ };
160
+ }
150
161
  }
151
162
  }
152
163
  if (uatContent) {
@@ -290,11 +301,20 @@ function stringField(row, key) {
290
301
  function stripGsdPrefix(path) {
291
302
  return path.startsWith(".gsd/") ? path.slice(".gsd/".length) : path;
292
303
  }
293
- function persistSliceAssessmentBackfill(assessmentRelPath, mid, sliceId, content) {
304
+ // Scope marker for assessments fabricated by the milestone-validation backfill
305
+ // (#1258). It keeps these placeholders distinguishable from genuine `run-uat`
306
+ // sign-offs so `readUatGateVerdict` never mistakes "never checked" for "passed".
307
+ const BACKFILL_ASSESSMENT_SCOPE = "backfill";
308
+ function persistSliceAssessmentBackfill(assessmentRelPath, mid, sliceId, content, fabricated) {
294
309
  const artifactPath = stripGsdPrefix(assessmentRelPath);
295
310
  const existingAssessment = getAssessment(assessmentRelPath) ??
296
311
  getAssessment(artifactPath);
297
- const scope = stringField(existingAssessment, "scope") ?? "run-uat";
312
+ // A newly fabricated placeholder is filed under a distinct scope; a pre-existing
313
+ // on-disk ASSESSMENT keeps its real scope (default `run-uat`) so genuine
314
+ // sign-offs are still honored.
315
+ const scope = fabricated
316
+ ? BACKFILL_ASSESSMENT_SCOPE
317
+ : stringField(existingAssessment, "scope") ?? "run-uat";
298
318
  const status = stringField(existingAssessment, "status") ??
299
319
  extractVerdict(content)?.toLowerCase() ??
300
320
  "unknown";
@@ -342,18 +362,24 @@ function backfillMissingAssessmentsFromSummaries(basePath, mid) {
342
362
  "---",
343
363
  `sliceId: ${sliceId}`,
344
364
  "verdict: PASS",
365
+ // Distinguishing marker (#1258): this ASSESSMENT was fabricated to satisfy
366
+ // the per-slice artifact requirement, NOT produced by a real UAT run. It
367
+ // must not be read as a genuine UAT sign-off.
368
+ "backfilled: true",
369
+ "verified: false",
345
370
  `date: ${now}`,
346
371
  "---",
347
372
  "",
348
373
  `# Assessment — ${sliceId}`,
349
374
  "",
350
375
  "Auto-created during milestone validation because this completed slice had a SUMMARY but no ASSESSMENT artifact.",
376
+ "This is a placeholder: no UAT was executed for this slice, so its verdict is not an independent sign-off.",
351
377
  "No additional reassessment changes were detected in this backfill step.",
352
378
  "",
353
379
  ].join("\n") : readFileSync(assessmentPath, "utf-8");
354
380
  if (isDbAvailable()) {
355
381
  try {
356
- persistSliceAssessmentBackfill(assessmentRelPath, mid, sliceId, content);
382
+ persistSliceAssessmentBackfill(assessmentRelPath, mid, sliceId, content, didCreateAssessment);
357
383
  }
358
384
  catch (err) {
359
385
  logWarning("dispatch", `failed to backfill assessment DB rows for ${mid}/${sliceId}: ${err.message}`);
@@ -533,7 +559,7 @@ export const DISPATCH_RULES = [
533
559
  {
534
560
  name: "run-uat (post-completion)",
535
561
  match: async ({ state, mid, basePath, prefs, sessionProvider, sessionAuthMode, activeTools, registeredTools, sessionBaseUrl, }) => {
536
- const needsRunUat = await checkNeedsRunUat(basePath, mid, state, prefs);
562
+ const needsRunUat = await checkNeedsRunUat(basePath, mid, prefs, await loadRoadmapCompletedSliceCandidates(basePath, mid));
537
563
  if (!needsRunUat)
538
564
  return null;
539
565
  const { sliceId, uatType } = needsRunUat;
@@ -1167,8 +1193,15 @@ export const DISPATCH_RULES = [
1167
1193
  if (resolveSliceFile(basePath, mid, sid, "REACTIVE-BLOCKER"))
1168
1194
  return null;
1169
1195
  const maxParallel = reactiveConfig?.max_parallel ?? 2;
1170
- const subagentModel = reactiveConfig?.subagent_model ?? resolveModelWithFallbacksForUnit("subagent")?.primary;
1171
- const subagentThinking = resolveThinkingLevelForUnit("subagent");
1196
+ // `subagent_model` accepts the phase-bucket object form (#1229); honor the
1197
+ // full primary→fallbacks chain in the dispatch prompt (the reactive
1198
+ // subagent model is embedded there rather than set as the session model).
1199
+ const subagentModelConfig = normalizeModelFieldConfig(reactiveConfig?.subagent_model)
1200
+ ?? resolveModelWithFallbacksForUnit("subagent");
1201
+ const subagentModel = subagentModelConfig?.primary;
1202
+ // Prefer the per-field `thinking` carried on `reactive_execution.subagent_model`'s
1203
+ // object form over the phase-bucket `subagent` level (#1269).
1204
+ const subagentThinking = subagentModelConfig?.thinking ?? resolveThinkingLevelForUnit("subagent");
1172
1205
  // Default-on safety threshold: only activate reactive dispatch when at
1173
1206
  // least N tasks are ready. Users who explicitly enabled reactive_execution
1174
1207
  // keep the legacy threshold of 2 (matches the prior "any parallelism is
@@ -1228,7 +1261,13 @@ export const DISPATCH_RULES = [
1228
1261
  action: "dispatch",
1229
1262
  unitType: "reactive-execute",
1230
1263
  unitId: `${mid}/${sid}/reactive+${batchSuffix}`,
1231
- prompt: await buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, selected, basePath, subagentModel, { sessionContextWindow, modelRegistry, sessionProvider, subagentThinking }),
1264
+ prompt: await buildReactiveExecutePrompt(mid, midTitle, sid, sTitle, selected, basePath, subagentModel, {
1265
+ sessionContextWindow,
1266
+ modelRegistry,
1267
+ sessionProvider,
1268
+ subagentThinking,
1269
+ subagentModelFallbacks: subagentModelConfig?.fallbacks,
1270
+ }),
1232
1271
  };
1233
1272
  }
1234
1273
  catch (err) {
@@ -1500,6 +1539,19 @@ export const DISPATCH_RULES = [
1500
1539
  },
1501
1540
  ];
1502
1541
  import { getRegistry } from "./rule-registry.js";
1542
+ /**
1543
+ * Prepend the configured response-language directive to a dispatched unit
1544
+ * prompt so auto-execution units respond in the language set in PREFERENCES.md
1545
+ * (#1210). No-op for non-dispatch actions or when no language is configured.
1546
+ */
1547
+ function applyLanguageDirectiveToDispatch(action, prefs) {
1548
+ if (action.action !== "dispatch" || !action.prompt)
1549
+ return action;
1550
+ const directive = renderLanguageDirectiveForPrompt(prefs);
1551
+ if (!directive)
1552
+ return action;
1553
+ return { ...action, prompt: `${directive}\n\n${action.prompt}` };
1554
+ }
1503
1555
  // ─── Resolver ─────────────────────────────────────────────────────────────
1504
1556
  /**
1505
1557
  * Evaluate dispatch rules in order. Returns the first matching action,
@@ -1551,7 +1603,7 @@ export async function resolveDispatch(ctx) {
1551
1603
  level: "error",
1552
1604
  };
1553
1605
  }
1554
- return action;
1606
+ return applyLanguageDirectiveToDispatch(action, ctx.prefs);
1555
1607
  }
1556
1608
  catch (err) {
1557
1609
  // Registry not initialized — fall back to inline loop
@@ -1572,7 +1624,7 @@ export async function resolveDispatch(ctx) {
1572
1624
  matchedRule: rule.name,
1573
1625
  };
1574
1626
  }
1575
- return action;
1627
+ return applyLanguageDirectiveToDispatch(action, ctx.prefs);
1576
1628
  }
1577
1629
  }
1578
1630
  // No rule matched — unhandled phase.
@@ -219,10 +219,37 @@ function buildModelPolicyBlockReasons(policyDenyReasons, availableModels, routin
219
219
  reason: `configured model(s) did not resolve against policy-eligible registry [${eligibleSummary}]`,
220
220
  }];
221
221
  }
222
- function isModelUnavailable(basePath, provider, id) {
222
+ export function isModelUnavailable(basePath, provider, id) {
223
223
  return isModelBlocked(basePath, provider, id) ||
224
224
  isModelTemporarilyUnavailable(basePath, provider, id);
225
225
  }
226
+ /** Apply `auto_supervisor.model`, walking configured fallbacks on unavailability (#1229). */
227
+ export async function applySupervisorModelIfConfigured(ctx, pi, basePath) {
228
+ const modelConfig = resolveModelWithFallbacksForUnit("supervisor", basePath);
229
+ if (!modelConfig)
230
+ return;
231
+ const availableModels = ctx.modelRegistry.getAvailable();
232
+ for (const candidate of [modelConfig.primary, ...modelConfig.fallbacks]) {
233
+ const match = resolveModelId(candidate, availableModels, ctx.model?.provider);
234
+ if (!match)
235
+ continue;
236
+ if (isModelUnavailable(basePath, match.provider, match.id))
237
+ continue;
238
+ try {
239
+ if (await pi.setModel(match, { persist: false })) {
240
+ // Prefer the per-field `thinking` from `auto_supervisor.model`'s object
241
+ // form over the session level so a configured supervisor level actually
242
+ // applies (#1269).
243
+ applyThinkingLevelForModel(pi, modelConfig.thinking ?? pi.getThinkingLevel(), match, ctx);
244
+ return;
245
+ }
246
+ }
247
+ catch (err) {
248
+ // Non-fatal — try the next fallback.
249
+ logWarning("dispatch", `supervisor model set failed for ${candidate}: ${err instanceof Error ? err.message : String(err)}`);
250
+ }
251
+ }
252
+ }
226
253
  function restoreToolBaseline(pi) {
227
254
  const key = pi;
228
255
  const baseline = TOOL_BASELINE.get(key);
@@ -17,7 +17,7 @@ import { logWarning, logError } from "./workflow-logger.js";
17
17
  import { loadFile, parseSummary, resolveAllOverrides } from "./files.js";
18
18
  import { loadPrompt } from "./prompt-loader.js";
19
19
  import { isAwaitingUserInput } from "./consent-question.js";
20
- import { resolveSliceFile, resolveSlicePath, relSlicePath, resolveTaskFile, resolveMilestoneFile, resolveTasksDir, resolveFile, relMilestoneFile, relSliceFile, relTaskFile, } from "./paths.js";
20
+ import { resolveSliceFile, resolveSlicePath, relSlicePath, resolveTaskFile, resolveMilestoneFile, resolveTasksDir, resolveFile, relMilestoneFile, relSliceFile, relTaskFile, normalizeRealPath, } from "./paths.js";
21
21
  import { invalidateAllCaches } from "./cache.js";
22
22
  import { rebuildState } from "./doctor.js";
23
23
  import { parseUnitId } from "./unit-id.js";
@@ -770,7 +770,7 @@ function describeArtifactVerificationFailure(unitType, unitId, basePath, agentEn
770
770
  if (!artifactPath) {
771
771
  return `Artifact verification failed: ${unitType} "${unitId}" has no resolvable artifact path.`;
772
772
  }
773
- const relPath = relative(basePath, artifactPath);
773
+ const relPath = relative(normalizeRealPath(basePath), artifactPath);
774
774
  if (!existsSync(artifactPath)) {
775
775
  const completionToolHint = unitType === "execute-task" && !hasTaskCompletionToolCall(agentEndMessages)
776
776
  ? " No completion tool call detected (`gsd_task_complete`/alias)."
@@ -1987,7 +1987,8 @@ export async function postUnitPostVerification(pctx) {
1987
1987
  persistHookState(s.basePath);
1988
1988
  const verdict = gateBlock.verdict ? ` verdict=${gateBlock.verdict};` : "";
1989
1989
  const artifact = gateBlock.artifact ? ` artifact=${gateBlock.artifact};` : "";
1990
- const message = `Post-unit gate "${gateBlock.hookName}" blocked ${gateBlock.triggerUnitType} ${gateBlock.triggerUnitId}:` +
1990
+ const message = `Post-unit gate "${gateBlock.hookName}" blocked ${gateBlock.triggerUnitType} ${gateBlock.triggerUnitId} ` +
1991
+ `(detected on completion of ${s.currentUnit.type} ${s.currentUnit.id}):` +
1991
1992
  `${verdict}${artifact} ${gateBlock.reason}. Run /gsd status to inspect, then /gsd auto after recovery.`;
1992
1993
  ctx.ui.notify(message, "warning");
1993
1994
  await pauseAuto(ctx, pi);
@@ -8,7 +8,7 @@
8
8
  * utility.
9
9
  */
10
10
  import { loadFile, parseContinue, parseSummary, loadActiveOverrides, formatOverridesSection } from "./files.js";
11
- import { hasVerdict, extractVerdict } from "./verdict-parser.js";
11
+ import { extractVerdict } from "./verdict-parser.js";
12
12
  import { loadPrompt, inlineTemplate } from "./prompt-loader.js";
13
13
  import { resolveMilestoneFile, resolveSliceFile, resolveSlicePath, resolveTasksDir, resolveTaskFiles, resolveTaskFile, relMilestoneFile, relSliceFile, relSlicePath, relMilestonePath, relTaskFile, resolveGsdRootFile, relGsdRootFile, resolveRuntimeFile, } from "./paths.js";
14
14
  import { resolveInlineLevel, loadEffectiveGSDPreferences } from "./preferences.js";
@@ -35,7 +35,8 @@ import { debugLog } from "./debug-logger.js";
35
35
  import { buildSkillActivationBlock, buildSkillDiscoveryVars } from "./skill-activation.js";
36
36
  import { findMilestoneIds } from "./milestone-ids.js";
37
37
  import { buildRunUatPresentationForType, RUN_UAT_TOOL_PRESENTATION_PLAN_ID } from "./tool-presentation-plan.js";
38
- import { classifyUatContentForRun, shouldDispatchUatForContent, } from "./uat-policy.js";
38
+ import { classifyUatContentForRun } from "./uat-policy.js";
39
+ import { checkNeedsRunUat as resolveNeedsRunUat } from "./uat-dispatch.js";
39
40
  import { buildWebAppUatGuidanceBlock } from "./web-app-uat.js";
40
41
  export { buildSkillActivationBlock, buildSkillDiscoveryVars };
41
42
  // ─── Preamble Cap ─────────────────────────────────────────────────────────────
@@ -1320,120 +1321,26 @@ export async function checkNeedsReassessment(base, mid, state) {
1320
1321
  return null;
1321
1322
  return { sliceId: lastDone };
1322
1323
  }
1324
+ export function getRoadmapCompletedSliceCandidates(roadmapContent) {
1325
+ return parseRoadmap(roadmapContent)
1326
+ .slices.filter((slice) => slice.done)
1327
+ .map((slice) => ({ sliceId: slice.id }))
1328
+ .reverse();
1329
+ }
1330
+ export async function loadRoadmapCompletedSliceCandidates(base, mid) {
1331
+ const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
1332
+ const roadmapContent = roadmapPath ? await loadFile(roadmapPath) : null;
1333
+ return roadmapContent ? getRoadmapCompletedSliceCandidates(roadmapContent) : [];
1334
+ }
1323
1335
  /**
1324
- * Check if the most recently completed slice needs a UAT run.
1325
- * Returns { sliceId, uatType } if UAT should be dispatched, null otherwise.
1326
- *
1327
- * Skips when:
1328
- * - No roadmap or no completed slices
1329
- * - uat_dispatch is not enabled and the UAT spec does not require runtime/browser evidence
1330
- * - No UAT file exists for the slice
1331
- * - UAT result file already exists (idempotent — already ran)
1332
- */
1333
- /**
1334
- * Resolve the effective UAT mode for the dispatch gate the same way
1335
- * `buildRunUatPrompt` does: classify the UAT body with the slice's SUMMARY as
1336
- * supplemental context, so a `browser-executable` UAT whose slice references a
1337
- * self-contained harness (`npm run test:uat`, `search-uat.mjs`, `npx
1338
- * playwright test`) is promoted to `runtime-executable` for the gate too.
1339
- *
1340
- * Without this, `checkNeedsRunUat` returns `browser-executable` while the
1341
- * prompt instructs runtime-only execution, causing the dispatch gate to
1342
- * require browser tools / warm up the browser daemon (or stop dispatch when
1343
- * browser MCP is unavailable) for UAT runs that never touch the browser. See
1344
- * cursor[bot] review on PR #696 for the M007/S01 regression.
1336
+ * Back-compat wrapper for callers that import UAT dispatch checks from the
1337
+ * prompt module. UAT dispatch architecture lives in `uat-dispatch.ts`; the
1338
+ * `state` parameter is intentionally ignored because DB/roadmap artifacts are
1339
+ * the source of truth for completed-slice discovery.
1345
1340
  */
1346
- async function resolveRunUatEffectiveType(base, mid, sliceId, uatContent) {
1347
- let summaryContent = "";
1348
- try {
1349
- const summaryPath = resolveSliceFile(base, mid, sliceId, "SUMMARY");
1350
- if (summaryPath) {
1351
- summaryContent = (await loadFile(summaryPath)) ?? "";
1352
- }
1353
- }
1354
- catch (err) {
1355
- logWarning("prompt", `resolveRunUatEffectiveType SUMMARY load failed: ${err instanceof Error ? err.message : String(err)}`);
1356
- }
1357
- return classifyUatContentForRun(uatContent, summaryContent).effectiveType;
1358
- }
1359
1341
  export async function checkNeedsRunUat(base, mid, state, prefs) {
1360
- // DB primary path — fall through to file-based when DB has no data for this milestone
1361
- try {
1362
- const { isDbAvailable, getMilestoneSlices } = await import("./gsd-db.js");
1363
- if (isDbAvailable()) {
1364
- const slices = getMilestoneSlices(mid);
1365
- if (slices.length > 0) {
1366
- const completedSlices = slices.filter(s => s.status === "complete");
1367
- if (completedSlices.length === 0)
1368
- return null;
1369
- for (const completed of [...completedSlices].reverse()) {
1370
- const sid = completed.id;
1371
- const uatFile = resolveSliceFile(base, mid, sid, "UAT");
1372
- if (!uatFile)
1373
- continue;
1374
- const uatContent = await loadFile(uatFile);
1375
- if (!uatContent)
1376
- continue;
1377
- // If the UAT file already contains a verdict, UAT has been run — skip
1378
- if (hasVerdict(uatContent))
1379
- continue;
1380
- // Also check the ASSESSMENT file — the run-uat prompt writes the verdict
1381
- // there (via gsd_uat_result_save), not into the
1382
- // UAT spec file. Without this check the unit re-dispatches indefinitely.
1383
- const assessmentFile = resolveSliceFile(base, mid, sid, "ASSESSMENT");
1384
- if (assessmentFile) {
1385
- const assessmentContent = await loadFile(assessmentFile);
1386
- if (assessmentContent && hasVerdict(assessmentContent))
1387
- continue;
1388
- }
1389
- if (!shouldDispatchUatForContent(uatContent, prefs))
1390
- continue;
1391
- const uatType = await resolveRunUatEffectiveType(base, mid, sid, uatContent);
1392
- return { sliceId: sid, uatType };
1393
- }
1394
- return null;
1395
- }
1396
- }
1397
- }
1398
- catch (err) {
1399
- logWarning("prompt", `checkNeedsRunUat DB lookup failed: ${err instanceof Error ? err.message : String(err)}`);
1400
- }
1401
- // File-based fallback using roadmap checkboxes
1402
- const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
1403
- if (!roadmapPath)
1404
- return null;
1405
- const roadmapContent = await loadFile(roadmapPath);
1406
- if (!roadmapContent)
1407
- return null;
1408
- const parsed = parseRoadmap(roadmapContent);
1409
- const completedFileSlices = parsed.slices.filter(s => s.done);
1410
- if (completedFileSlices.length === 0)
1411
- return null;
1412
- for (const completed of [...completedFileSlices].reverse()) {
1413
- const uatSid = completed.id;
1414
- const uatFileFb = resolveSliceFile(base, mid, uatSid, "UAT");
1415
- if (!uatFileFb)
1416
- continue;
1417
- const uatContentFb = await loadFile(uatFileFb);
1418
- if (!uatContentFb)
1419
- continue;
1420
- // If the UAT file already contains a verdict, UAT has been run — skip
1421
- if (hasVerdict(uatContentFb))
1422
- continue;
1423
- // Also check the ASSESSMENT file for the file-based fallback path (same
1424
- // reason as the DB path above — verdict lives in ASSESSMENT, not UAT).
1425
- const assessmentFileFb = resolveSliceFile(base, mid, uatSid, "ASSESSMENT");
1426
- if (assessmentFileFb) {
1427
- const assessmentContentFb = await loadFile(assessmentFileFb);
1428
- if (assessmentContentFb && hasVerdict(assessmentContentFb))
1429
- continue;
1430
- }
1431
- if (!shouldDispatchUatForContent(uatContentFb, prefs))
1432
- continue;
1433
- const uatType = await resolveRunUatEffectiveType(base, mid, uatSid, uatContentFb);
1434
- return { sliceId: uatSid, uatType };
1435
- }
1436
- return null;
1342
+ void state;
1343
+ return resolveNeedsRunUat(base, mid, prefs, await loadRoadmapCompletedSliceCandidates(base, mid));
1437
1344
  }
1438
1345
  export async function buildDiscussMilestoneInlinedContext(mid, base) {
1439
1346
  const inlined = [];
@@ -3401,10 +3308,15 @@ export async function buildReassessRoadmapPrompt(mid, midTitle, completedSliceId
3401
3308
  * that instructs the coordinator how to dispatch a `subagent` call. Either or
3402
3309
  * both may be absent (ADR-026 / #508).
3403
3310
  */
3404
- function subagentCallSuffix(model, thinking) {
3311
+ function subagentCallSuffix(model, thinking, fallbacks) {
3405
3312
  const parts = [];
3406
- if (model)
3407
- parts.push(`model: "${model}"`);
3313
+ if (model) {
3314
+ let modelHint = `model: "${model}"`;
3315
+ if (fallbacks && fallbacks.length > 0) {
3316
+ modelHint += ` (fallbacks, in order: ${fallbacks.map((f) => `"${f}"`).join(", ")})`;
3317
+ }
3318
+ parts.push(modelHint);
3319
+ }
3408
3320
  if (thinking)
3409
3321
  parts.push(`thinking: "${thinking}"`);
3410
3322
  return parts.length > 0 ? ` with ${parts.join(" and ")}` : "";
@@ -3490,7 +3402,7 @@ opts) {
3490
3402
  "",
3491
3403
  `When done, say: "Task ${tid} complete."`,
3492
3404
  ].join("\n");
3493
- const modelSuffix = subagentCallSuffix(subagentModel, opts?.subagentThinking);
3405
+ const modelSuffix = subagentCallSuffix(subagentModel, opts?.subagentThinking, opts?.subagentModelFallbacks);
3494
3406
  subagentSections.push([
3495
3407
  `### ${tid}: ${tTitle}`,
3496
3408
  "",
@@ -149,12 +149,56 @@ export function refreshRecoveryDbForArtifact(unitType, unitId, basePath) {
149
149
  };
150
150
  }
151
151
  if (!isClosedStatus(task.status)) {
152
- return {
153
- ok: false,
154
- fatal: true,
155
- reason: "execute-task-artifact-db-mismatch",
156
- message: `Stuck recovery found execute-task ${unitId} artifacts, but the DB task status is still '${task.status}' after refresh.`,
157
- };
152
+ // The artifact was already confirmed on disk by verifyExpectedArtifact
153
+ // upstream (Gate 1 accepts a checked disk checkbox as proof of completion),
154
+ // but the DB task row is still open. A bare refreshWorkflowDatabaseFromDisk
155
+ // never promotes the disk checkbox into task status (the checkbox is
156
+ // rendered *from* the DB, never *into* it), so this divergence can never
157
+ // self-heal. Promote the task to align the DB with disk instead of failing
158
+ // shut — otherwise the lowest-pending derivation re-picks the same task
159
+ // forever and execute-task hard-stops with "state did not advance" (#1204).
160
+ // Mirrors the promotion pattern used by the context-exhaustion and
161
+ // reactive-execute-blocker recovery paths.
162
+ const ts = new Date().toISOString();
163
+ // Only the DB promotion is load-bearing: if it throws, nothing advanced
164
+ // and failing shut is correct. The plan checkbox rewrite and cache clears
165
+ // are best-effort follow-ups — a throw there must NOT abort recovery, or
166
+ // the DB is left complete without ever emitting the stuck-artifact-recovery
167
+ // event (#1221), stranding worktree reconciliation.
168
+ try {
169
+ updateTaskStatus(mid, sid, tid, "complete", ts);
170
+ }
171
+ catch (e) {
172
+ return {
173
+ ok: false,
174
+ fatal: true,
175
+ reason: "execute-task-artifact-db-promote-failed",
176
+ message: `Stuck recovery found execute-task ${unitId} artifacts, but promoting the DB task status from '${task.status}' failed: ${getErrorMessage(e)}`,
177
+ };
178
+ }
179
+ try {
180
+ const artifactBase = resolveArtifactVerificationBase(unitId, basePath);
181
+ const planPath = resolveExpectedArtifactPath("plan-slice", `${mid}/${sid}`, artifactBase);
182
+ if (planPath && existsSync(planPath)) {
183
+ const planContent = readFileSync(planPath, "utf-8");
184
+ const updatedPlan = planContent.replace(new RegExp(`^(\\s*-\\s+)\\[ \\]\\s+\\*\\*${tid}:`, "m"), `$1[x] **${tid}:`);
185
+ if (updatedPlan !== planContent) {
186
+ atomicWriteSync(planPath, updatedPlan);
187
+ }
188
+ }
189
+ clearPathCache();
190
+ clearParseCache();
191
+ }
192
+ catch (e) {
193
+ logWarning("recovery", `stuck-artifact plan checkbox sync failed after DB promotion of ${unitId}: ${getErrorMessage(e)}`);
194
+ }
195
+ // Append event so worktree reconciliation can replay this recovery completion.
196
+ try {
197
+ appendEvent(basePath, { cmd: "complete-task", params: { milestoneId: mid, sliceId: sid, taskId: tid }, ts, actor: "system", trigger_reason: "stuck-artifact-recovery" });
198
+ }
199
+ catch (e) {
200
+ logWarning("recovery", `appendEvent failed for stuck-artifact task promotion: ${getErrorMessage(e)}`);
201
+ }
158
202
  }
159
203
  return { ok: true };
160
204
  }
@@ -27,18 +27,19 @@ import { ensureGitignore, untrackRuntimeFiles } from "./gitignore.js";
27
27
  import { nativeIsRepo, nativeInit, nativeAddAll, nativeCommit, nativeGetCurrentBranch, nativeDetectMainBranch, nativeBranchList, nativeBranchExists, nativeBranchListMerged, nativeBranchDelete, nativeWorktreeRemove, nativeCommitCountBetween, nativeHasChanges, } from "./native-git-bridge.js";
28
28
  import { GitServiceImpl } from "./git-service.js";
29
29
  import { captureIntegrationBranch, detectWorktreeName, setActiveMilestoneId, } from "./worktree.js";
30
- import { getAutoWorktreePath } from "./auto-worktree.js";
30
+ import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
31
31
  import { checkoutBranchWithStashGuard } from "./worktree-git-recovery.js";
32
- import { readResourceVersion, cleanStaleRuntimeUnits } from "./auto-worktree.js";
32
+ import { cleanStaleRuntimeUnits } from "./auto-worktree-runtime-cleanup.js";
33
+ import { readResourceVersion } from "./auto-worktree-resource-version.js";
33
34
  import { worktreePath as getWorktreeDir, isInsideWorktreesDir } from "./worktree-manager.js";
34
35
  import { emitWorktreeOrphaned } from "./worktree-telemetry.js";
35
36
  import { queryJournal } from "./journal.js";
36
37
  import { initMetrics } from "./metrics.js";
37
38
  import { initRoutingHistory } from "./routing-history.js";
38
- import { restoreHookState, resetHookState } from "./post-unit-hooks.js";
39
+ import { restoreHookState, resetHookState, reconcileRestoredHookDispatch } from "./post-unit-hooks.js";
39
40
  import { resetProactiveHealing, setLevelChangeCallback } from "./doctor-proactive.js";
40
41
  import { snapshotSkills } from "./skill-discovery.js";
41
- import { isDbAvailable, getMilestone, getAllMilestones, insertMilestone, updateMilestoneStatus } from "./gsd-db.js";
42
+ import { isDbAvailable, probeDbWritable, getMilestone, getAllMilestones, insertMilestone, updateMilestoneStatus } from "./gsd-db.js";
42
43
  import { getWorkflowDatabaseStatus, openExistingWorkflowDatabase, openWorkflowDatabase, resolveProjectRootDbPath, } from "./db-workspace.js";
43
44
  import { isClosedStatus } from "./status-guards.js";
44
45
  import { classifyMilestoneSummaryContent } from "./milestone-summary-classifier.js";
@@ -118,36 +119,42 @@ export function reconcileProjectMilestonesFromDisk(basePath) {
118
119
  export function reconcileMergedMilestonesFromJournal(basePath) {
119
120
  if (!isDbAvailable())
120
121
  return 0;
121
- const mergedAtByMilestone = new Map();
122
- for (const entry of queryJournal(basePath, { eventType: "worktree-merged" })) {
123
- const data = entry.data ?? {};
124
- const milestoneId = typeof data.milestoneId === "string" ? data.milestoneId : null;
125
- if (!milestoneId)
126
- continue;
127
- if (data.conflict === true)
128
- continue;
129
- const endedAt = typeof data.endedAt === "string" ? data.endedAt : entry.ts;
130
- const previous = mergedAtByMilestone.get(milestoneId);
131
- if (!previous || endedAt > previous)
132
- mergedAtByMilestone.set(milestoneId, endedAt);
133
- }
134
- let closed = 0;
135
- for (const [milestoneId, completedAt] of mergedAtByMilestone) {
136
- const existing = getMilestone(milestoneId);
137
- if (!existing) {
138
- insertMilestone({ id: milestoneId, title: milestoneId, status: "complete" });
139
- updateMilestoneStatus(milestoneId, "complete", completedAt);
140
- closed++;
141
- continue;
142
- }
143
- if (!isClosedStatus(existing.status)) {
144
- updateMilestoneStatus(milestoneId, "complete", completedAt);
145
- closed++;
122
+ try {
123
+ const mergedAtByMilestone = new Map();
124
+ for (const entry of queryJournal(basePath, { eventType: "worktree-merged" })) {
125
+ const data = entry.data ?? {};
126
+ const milestoneId = typeof data.milestoneId === "string" ? data.milestoneId : null;
127
+ if (!milestoneId)
128
+ continue;
129
+ if (data.conflict === true)
130
+ continue;
131
+ const endedAt = typeof data.endedAt === "string" ? data.endedAt : entry.ts;
132
+ const previous = mergedAtByMilestone.get(milestoneId);
133
+ if (!previous || endedAt > previous)
134
+ mergedAtByMilestone.set(milestoneId, endedAt);
135
+ }
136
+ let closed = 0;
137
+ for (const [milestoneId, completedAt] of mergedAtByMilestone) {
138
+ const existing = getMilestone(milestoneId);
139
+ if (!existing) {
140
+ insertMilestone({ id: milestoneId, title: milestoneId, status: "complete" });
141
+ updateMilestoneStatus(milestoneId, "complete", completedAt);
142
+ closed++;
143
+ continue;
144
+ }
145
+ if (!isClosedStatus(existing.status)) {
146
+ updateMilestoneStatus(milestoneId, "complete", completedAt);
147
+ closed++;
148
+ }
146
149
  }
150
+ if (closed > 0)
151
+ invalidateAllCaches();
152
+ return closed;
153
+ }
154
+ catch (err) {
155
+ logWarning("bootstrap", `merged-milestone journal reconciliation failed: ${err instanceof Error ? err.message : String(err)}`);
156
+ return 0;
147
157
  }
148
- if (closed > 0)
149
- invalidateAllCaches();
150
- return closed;
151
158
  }
152
159
  export function decideSurvivorAction(hasSurvivorBranch, phase) {
153
160
  if (!hasSurvivorBranch)
@@ -1253,6 +1260,10 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
1253
1260
  s.unitLifetimeDispatches.clear();
1254
1261
  resetHookState();
1255
1262
  restoreHookState(base);
1263
+ // A restored activeHook has no live dispatch (the sidecar queue is not
1264
+ // persisted); re-enqueue it so the hook runs instead of blocking the next
1265
+ // unrelated unit's close-out (#1246).
1266
+ reconcileRestoredHookDispatch(base, s.sidecarQueue);
1256
1267
  resetProactiveHealing();
1257
1268
  // Notify user on health level transitions (green→yellow→red and back)
1258
1269
  setLevelChangeCallback((_from, to, summary) => {
@@ -1376,6 +1387,19 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
1376
1387
  ctx.ui.notify(`SQLite database exists but failed to open: ${gsdDbPath}. ${phaseHint}${errorDetail}.${providerHint}`, "error");
1377
1388
  return releaseLockAndReturn();
1378
1389
  }
1390
+ // Gate: confirm the handle is actually writable, not just open. A
1391
+ // schema-current DB does zero writes during open, so a read-only /
1392
+ // DBMOVED handle otherwise passes the check above and only fails much
1393
+ // later at the first authoritative write (the uok-kernel-enter audit)
1394
+ // with an opaque "readonly database" error (#1234).
1395
+ if (existsSync(gsdDbPath) && isDbAvailable()) {
1396
+ const writable = probeDbWritable();
1397
+ if (!writable.ok) {
1398
+ const detail = writable.detail ? ` (${writable.detail})` : "";
1399
+ ctx.ui.notify(`SQLite database is not writable: ${gsdDbPath}.${detail} Check file/WAL permissions or reopen a stale handle before running auto-mode.`, "error");
1400
+ return releaseLockAndReturn();
1401
+ }
1402
+ }
1379
1403
  // Initialize metrics
1380
1404
  initMetrics(s.basePath);
1381
1405
  // Initialize routing history
@@ -1409,7 +1433,7 @@ export async function bootstrapAutoSession(s, ctx, pi, base, verboseMode, reques
1409
1433
  }
1410
1434
  // Snapshot installed skills
1411
1435
  if (resolveSkillDiscoveryMode(base) !== "off") {
1412
- snapshotSkills();
1436
+ snapshotSkills({ cwd: s.basePath });
1413
1437
  }
1414
1438
  setAutoActiveStatus(ctx, s.stepMode ? "next" : "auto");
1415
1439
  ctx.ui.setWidget("gsd-health", undefined);