@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
@@ -5,7 +5,7 @@
5
5
  // Exports: parseDecisionsTable, parseRequirementsSections, migrateFromMarkdown
6
6
 
7
7
  import { readFileSync, readdirSync, existsSync, statSync } from 'node:fs';
8
- import { join, relative, basename } from 'node:path';
8
+ import { join, relative, basename, dirname } from 'node:path';
9
9
  import type { Decision, Requirement } from './types.js';
10
10
  import {
11
11
  upsertDecision,
@@ -24,6 +24,7 @@ import {
24
24
  resolveGsdRootFile,
25
25
  resolveMilestoneFile,
26
26
  resolveSliceFile,
27
+ resolveSlicePath,
27
28
  resolveTasksDir,
28
29
  legacyMilestonesDir,
29
30
  gsdRoot,
@@ -33,7 +34,7 @@ import {
33
34
  import { findMilestoneIds } from './guided-flow.js';
34
35
  import { milestoneIdToPhaseNum } from './layout-policy.js';
35
36
  import { parseRoadmap, parsePlan } from './parsers-legacy.js';
36
- import { parseContextDependsOn } from './files.js';
37
+ import { parseContextDependsOn, parseSummary } from './files.js';
37
38
  import { logWarning } from './workflow-logger.js';
38
39
 
39
40
  // ─── DECISIONS.md Parser ───────────────────────────────────────────────────
@@ -816,23 +817,68 @@ export function migrateHierarchyToDb(basePath: string): {
816
817
  // Per K002: use 'complete' not 'done'
817
818
  let taskStatus: string = taskEntry.done ? 'complete' : 'pending';
818
819
 
819
- // Pre-migration consistency (legacy layout only): if a task is marked
820
- // done but has no per-task SUMMARY.md, import it as pending so it gets
821
- // re-executed rather than silently entering the DB as complete.
822
- // Flat-phase has no per-task summary files by design the checkbox
823
- // state is the authoritative completion signal and is imported as-is.
824
- if (taskStatus === 'complete') {
825
- const tDir = resolveTasksDir(basePath, milestoneId, sliceEntry.id);
826
- if (tDir) {
827
- const summaryFile = join(tDir, `${taskEntry.id}-SUMMARY.md`);
828
- if (!existsSync(summaryFile)) {
829
- taskStatus = 'pending';
830
- process.stderr.write(
831
- `gsd-migrate: ${milestoneId}/${sliceEntry.id}/${taskEntry.id} marked done but missing summary importing as pending\n`,
832
- );
833
- }
820
+ // Resolve the per-task SUMMARY.md. Legacy layout keeps summaries under
821
+ // a tasks/ subdir; flat-phase writes TID-SUMMARY.md directly in the
822
+ // phase dir (execute-task's gsd_task_complete writes it there). A tasks/
823
+ // subdir may still exist in flat-phase for auxiliary artifactsits
824
+ // mere existence must NOT redirect summary resolution into tasks/ (#1208).
825
+ const slicePath = resolveSlicePath(basePath, milestoneId, sliceEntry.id);
826
+ let taskSummaryFile: string | null = null;
827
+ let isLegacySlice = false;
828
+ // Legacy layout keeps per-task summaries under a tasks/ subdir. Its
829
+ // presence — not merely "is this a legacy slice" — is what makes a
830
+ // missing summary a downgrade signal. resolveTasksDir returns null when
831
+ // no such dir exists, so a legacy slice whose checkbox is the only
832
+ // completion signal (no tasks/ dir at all) is left complete on import.
833
+ let legacyTasksDir: string | null = null;
834
+ if (slicePath) {
835
+ isLegacySlice = basename(dirname(slicePath)) === 'slices';
836
+ legacyTasksDir = isLegacySlice
837
+ ? resolveTasksDir(basePath, milestoneId, sliceEntry.id)
838
+ : null;
839
+ const summaryDir = legacyTasksDir ?? slicePath;
840
+ taskSummaryFile = join(summaryDir, `${taskEntry.id}-SUMMARY.md`);
841
+ }
842
+ const hasTaskSummary = taskSummaryFile !== null && existsSync(taskSummaryFile);
843
+
844
+ // Pre-migration consistency (legacy tasks/ layout only): if a task is
845
+ // marked done but its tasks/ dir has no per-task SUMMARY.md, import it
846
+ // as pending so it gets re-executed rather than silently entering the DB
847
+ // as complete. A legacy slice with no tasks/ dir (checkbox-only
848
+ // completion) and flat-phase layout are both left as-is here.
849
+ if (taskStatus === 'complete' && legacyTasksDir !== null && !hasTaskSummary) {
850
+ taskStatus = 'pending';
851
+ process.stderr.write(
852
+ `gsd-migrate: ${milestoneId}/${sliceEntry.id}/${taskEntry.id} marked done but missing summary — importing as pending\n`,
853
+ );
854
+ }
855
+
856
+ // Lost-update guard (#1222): a per-task SUMMARY.md is the durable
857
+ // completion attestation written by gsd_task_complete. When the plan
858
+ // checkbox is stale-unchecked but the SUMMARY exists on disk, a
859
+ // re-import must NOT downgrade the completed task back to pending — that
860
+ // silent revert is the lost-update that hard-stopped auto-mode after the
861
+ // first execute-task. The surviving SUMMARY wins over a stale checkbox.
862
+ // reopen-task removes the SUMMARY, so this never re-completes an
863
+ // intentionally reopened task.
864
+ // Flat-phase summaries are phase-scoped (T01-SUMMARY.md); when a milestone
865
+ // has multiple slices, require the summary parent frontmatter to match so
866
+ // one slice's completion does not attest a sibling's same-named task.
867
+ let summaryAttestsCompletion = hasTaskSummary;
868
+ if (summaryAttestsCompletion && !isLegacySlice && roadmap.slices.length > 1 && taskSummaryFile) {
869
+ try {
870
+ const summaryContent = readFileSync(taskSummaryFile, 'utf-8');
871
+ summaryAttestsCompletion = parseSummary(summaryContent).frontmatter.parent === sliceEntry.id;
872
+ } catch {
873
+ summaryAttestsCompletion = false;
834
874
  }
835
875
  }
876
+ if (taskStatus === 'pending' && summaryAttestsCompletion) {
877
+ taskStatus = 'complete';
878
+ process.stderr.write(
879
+ `gsd-migrate: ${milestoneId}/${sliceEntry.id}/${taskEntry.id} unchecked in plan but SUMMARY.md present — importing as complete (#1222)\n`,
880
+ );
881
+ }
836
882
 
837
883
  insertTask({
838
884
  id: taskEntry.id,
@@ -844,6 +890,12 @@ export function migrateHierarchyToDb(basePath: string): {
844
890
  files: taskEntry.files ?? [],
845
891
  verify: taskEntry.verify ?? '',
846
892
  },
893
+ // #1222 (metadata half): re-import derives status from the plan/summary
894
+ // but has none of the execution prose gsd_task_complete wrote to the DB.
895
+ // Preserve the existing row's execution columns and completed_at so a
896
+ // re-import cannot blank a completed task's summary metadata or refresh
897
+ // its completion timestamp — the DB row is strictly richer than the plan.
898
+ preserveCompletionMetadata: true,
847
899
  });
848
900
  counts.tasks++;
849
901
  }
@@ -857,12 +909,31 @@ export function migrateHierarchyToDb(basePath: string): {
857
909
  if (!sliceEntry.done) {
858
910
  const sliceSummaryPath = resolveSliceFile(basePath, milestoneId, sliceEntry.id, 'SUMMARY');
859
911
  const hasSliceSummary = sliceSummaryPath !== null && existsSync(sliceSummaryPath);
912
+ const slicePathForTasks = resolveSlicePath(basePath, milestoneId, sliceEntry.id);
913
+ const isLegacySliceLayout = slicePathForTasks !== null
914
+ && basename(dirname(slicePathForTasks)) === 'slices';
915
+ const taskSummaryDir = slicePathForTasks
916
+ ? (isLegacySliceLayout
917
+ ? (resolveTasksDir(basePath, milestoneId, sliceEntry.id) ?? slicePathForTasks)
918
+ : slicePathForTasks)
919
+ : null;
860
920
  const allTasksDone = plan.tasks.length > 0 && plan.tasks.every(t => {
861
- if (!t.done) return false;
862
- const tDir = resolveTasksDir(basePath, milestoneId, sliceEntry.id);
863
- // Flat-phase has no per-task summary files — checkbox state is authoritative.
864
- if (!tDir) return true;
865
- return existsSync(join(tDir, `${t.id}-SUMMARY.md`));
921
+ const taskSummaryFile = taskSummaryDir !== null
922
+ ? join(taskSummaryDir, `${t.id}-SUMMARY.md`)
923
+ : null;
924
+ const hasTaskSummary = taskSummaryFile !== null && existsSync(taskSummaryFile);
925
+ let summaryAttestsCompletion = hasTaskSummary;
926
+ if (summaryAttestsCompletion && !isLegacySliceLayout && roadmap.slices.length > 1 && taskSummaryFile) {
927
+ try {
928
+ const summaryContent = readFileSync(taskSummaryFile, 'utf-8');
929
+ summaryAttestsCompletion = parseSummary(summaryContent).frontmatter.parent === sliceEntry.id;
930
+ } catch {
931
+ summaryAttestsCompletion = false;
932
+ }
933
+ }
934
+ // Match per-task import rules above: SUMMARY attestation wins over a stale
935
+ // checkbox (#1222); flat-phase checkboxes are authoritative without summary.
936
+ return summaryAttestsCompletion || (t.done && !isLegacySliceLayout);
866
937
  });
867
938
  if (allTasksDone && hasSliceSummary) {
868
939
  if (_getAdapter()) {
@@ -265,7 +265,7 @@ export function snapshotUnitMetrics(
265
265
  }
266
266
  saveLedger(basePath, ledger);
267
267
 
268
- if (isUnifiedAuditEnabled()) {
268
+ if (isUnifiedAuditEnabled(basePath)) {
269
269
  emitUokAuditEvent(
270
270
  basePath,
271
271
  buildAuditEnvelope({
@@ -458,7 +458,7 @@ export function snapshotUnitMetricsByScope(
458
458
  }
459
459
  saveLedger(base, scopedLedger);
460
460
 
461
- if (isUnifiedAuditEnabled()) {
461
+ if (isUnifiedAuditEnabled(base)) {
462
462
  emitUokAuditEvent(
463
463
  base,
464
464
  buildAuditEnvelope({
@@ -102,13 +102,41 @@ function replaceSetPrefix(values: Set<string>, from: string, to: string): void {
102
102
  }
103
103
  }
104
104
 
105
+ /**
106
+ * Rewrite one milestone identity across EVERY markdown identity set. The
107
+ * roadmapless subset is a view of `milestones`, so it must speak the same
108
+ * aligned vocabulary; otherwise the discussion-phase exclusion below keys off
109
+ * the stale bare id, fails its `dbScan.milestones.has(...)` membership check,
110
+ * and decrements the milestone count even though the aligned identity remains
111
+ * in the set, reporting false drift for a milestone that is actually in sync.
112
+ * Centralising the set list here keeps every alignment path from silently
113
+ * missing a set (the defect that regressed the suffixed roadmapless case).
114
+ */
115
+ function realignMilestonePrefix(markdownScan: HierarchyScan, from: string, to: string): void {
116
+ replaceSetPrefix(markdownScan.milestones, from, to);
117
+ replaceSetPrefix(markdownScan.slices, from, to);
118
+ replaceSetPrefix(markdownScan.tasks, from, to);
119
+ replaceSetPrefix(markdownScan.milestonesWithoutRoadmap, from, to);
120
+ }
121
+
105
122
  function alignNumericMarkdownIdsWithDb(markdownScan: HierarchyScan, dbScan: HierarchyScan): void {
106
123
  for (const dbId of dbScan.milestones) {
107
124
  const paddedId = paddedMilestoneId(dbId);
108
125
  if (!paddedId || dbScan.milestones.has(paddedId) || !markdownScan.milestones.has(paddedId)) continue;
109
- replaceSetPrefix(markdownScan.milestones, paddedId, dbId);
110
- replaceSetPrefix(markdownScan.slices, paddedId, dbId);
111
- replaceSetPrefix(markdownScan.tasks, paddedId, dbId);
126
+ realignMilestonePrefix(markdownScan, paddedId, dbId);
127
+ }
128
+ }
129
+
130
+ function bareMilestoneId(id: string): string | null {
131
+ const match = id.match(/^(M\d{3})-[a-z0-9]{6}$/);
132
+ return match?.[1] ?? null;
133
+ }
134
+
135
+ function alignBareMarkdownIdsWithSuffixedDb(markdownScan: HierarchyScan, dbScan: HierarchyScan): void {
136
+ for (const dbId of dbScan.milestones) {
137
+ const bareId = bareMilestoneId(dbId);
138
+ if (!bareId || dbScan.milestones.has(bareId) || !markdownScan.milestones.has(bareId)) continue;
139
+ realignMilestonePrefix(markdownScan, bareId, dbId);
112
140
  }
113
141
  }
114
142
 
@@ -208,6 +236,7 @@ export async function checkMarkdownHierarchyAgainstDb(
208
236
  const dbScan = scanDbHierarchy();
209
237
  const beforeDb = dbScan.counts;
210
238
  alignNumericMarkdownIdsWithDb(markdownScan, dbScan);
239
+ alignBareMarkdownIdsWithSuffixedDb(markdownScan, dbScan);
211
240
 
212
241
  // Discussion-phase scratch: a milestone dir with no ROADMAP and no DB row is
213
242
  // a pre-registration discussion artifact (CONTEXT/CONTEXT-DRAFT only — the
@@ -1,6 +1,8 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Process-level transaction wrapper for milestone merge closeout.
3
3
 
4
+ import { mergeMilestoneToMain } from "./auto-worktree-merge.js";
5
+
4
6
  export interface MilestoneMergeTransactionResult {
5
7
  pushed: boolean;
6
8
  codeFilesChanged: boolean;
@@ -45,3 +47,16 @@ export function createMilestoneMergeTransaction(
45
47
  );
46
48
  };
47
49
  }
50
+
51
+ /**
52
+ * Production merge transaction adapter.
53
+ *
54
+ * This is the only production construction point that knows the legacy
55
+ * `auto-worktree.ts` merge primitive. Lifecycle callers depend on the
56
+ * transaction runner interface, not the legacy implementation module.
57
+ */
58
+ export function createDefaultMilestoneMergeTransaction(
59
+ mergeMilestone: MilestoneMergeTransactionRunner = mergeMilestoneToMain,
60
+ ): MilestoneMergeTransactionRunner {
61
+ return createMilestoneMergeTransaction(mergeMilestone);
62
+ }
@@ -1,7 +1,7 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Milestone closeout settlement state across DB proof, artifacts, merge, and cleanup.
3
3
 
4
- import { isInAutoWorktree } from "./auto-worktree.js";
4
+ import { isInAutoWorktree } from "./auto-worktree-entry.js";
5
5
  import {
6
6
  formatCloseoutProofBlock,
7
7
  proveMilestoneCloseout,
@@ -10,7 +10,7 @@ import { join } from "node:path";
10
10
  import { spawnSync } from "node:child_process";
11
11
  import { resolveGsdPathContract } from "./paths.js";
12
12
  import { worktreePathFor, worktreesDirs } from "./worktree-placement.js";
13
- import { getAutoWorktreePath } from "./auto-worktree.js";
13
+ import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
14
14
  import { buildWorktreeLifecycleDeps } from "./auto.js";
15
15
  import {
16
16
  mergeMilestoneStandalone,
@@ -21,7 +21,9 @@ import { join, dirname } from "node:path";
21
21
  import { fileURLToPath } from "node:url";
22
22
  import { gsdRoot } from "./paths.js";
23
23
  import { createWorktree, worktreePath } from "./worktree-manager.js";
24
- import { autoWorktreeBranch, fastForwardReusedMilestoneBranchIfSafe, runWorktreePostCreateHook, syncGsdStateToWorktreeByScope } from "./auto-worktree.js";
24
+ import { autoWorktreeBranch, fastForwardReusedMilestoneBranchIfSafe } from "./auto-worktree-branch-lifecycle.js";
25
+ import { syncGsdStateToWorktreeByScope } from "./auto-worktree-sync.js";
26
+ import { runWorktreePostCreateHook } from "./worktree-post-create-hook.js";
25
27
  import { nativeBranchExists } from "./native-git-bridge.js";
26
28
  import { readIntegrationBranch } from "./git-service.js";
27
29
  import { createWorkspace, scopeMilestone } from "./workspace.js";
@@ -11,7 +11,7 @@
11
11
  */
12
12
 
13
13
  import { readdirSync, existsSync, realpathSync, statSync, Dirent } from "node:fs";
14
- import { join, dirname, normalize, resolve } from "node:path";
14
+ import { join, dirname, normalize, relative, resolve } from "node:path";
15
15
  import { homedir } from "node:os";
16
16
  import { spawnSync } from "node:child_process";
17
17
  import { nativeScanGsdTree, type GsdTreeEntry } from "./native-parser-bridge.js";
@@ -379,21 +379,26 @@ export function resolveGsdPathContract(
379
379
  const resolvedWorkRoot = resolve(workRoot || process.cwd());
380
380
  const isWorktree = isGsdWorktreePath(resolvedWorkRoot);
381
381
  if (isWorktree && !originalProjectRoot?.trim()) {
382
- const projectGsd = resolveExternalStateProjectGsdFromWorktreePath(resolvedWorkRoot);
383
- if (projectGsd) {
382
+ const rawProjectGsd = resolveExternalStateProjectGsdFromWorktreePath(resolvedWorkRoot);
383
+ if (rawProjectGsd) {
384
+ // Canonicalize the `.gsd` root so the DB path matches what every other
385
+ // accessor (gsdRoot/gsdProjectionRoot) returns — otherwise an unresolved
386
+ // symlink (e.g. `/mnt/c/.../.gsd` → native ext4 on WSL) selects the wrong
387
+ // journal mode and yields a fragile, move-prone handle. See issue #1239.
388
+ const projectGsd = normalizeRealPath(rawProjectGsd);
384
389
  return {
385
390
  projectRoot: dirname(dirname(projectGsd)),
386
391
  workRoot: resolvedWorkRoot,
387
392
  projectGsd,
388
- worktreeGsd: join(resolvedWorkRoot, ".gsd"),
393
+ worktreeGsd: normalizeRealPath(join(resolvedWorkRoot, ".gsd")),
389
394
  projectDb: join(projectGsd, "gsd.db"),
390
395
  isWorktree,
391
396
  };
392
397
  }
393
398
  }
394
399
  const projectRoot = resolve(resolveWorktreeProjectRoot(resolvedWorkRoot, originalProjectRoot));
395
- const projectGsd = join(projectRoot, ".gsd");
396
- const worktreeGsd = isWorktree ? join(resolvedWorkRoot, ".gsd") : null;
400
+ const projectGsd = normalizeRealPath(join(projectRoot, ".gsd"));
401
+ const worktreeGsd = isWorktree ? normalizeRealPath(join(resolvedWorkRoot, ".gsd")) : null;
397
402
 
398
403
  return {
399
404
  projectRoot,
@@ -696,7 +701,16 @@ function pickPreferredPhaseDir(phasesDir: string, matches: string[]): string {
696
701
  return best;
697
702
  }
698
703
 
699
- function phaseDirMatchesMilestoneId(dirName: string, milestoneId: string, phaseNum: number): boolean {
704
+ function slugLooksLikeTeamSuffixProjection(slugPart: string): boolean {
705
+ return /^[a-z0-9]{6}(-|$)/.test(slugPart);
706
+ }
707
+
708
+ function phaseDirMatchesMilestoneId(
709
+ dirName: string,
710
+ milestoneId: string,
711
+ phaseNum: number,
712
+ allowTeamSuffixSlugs = false,
713
+ ): boolean {
700
714
  const numMatch = dirName.match(/^(\d+)-(.*)$/);
701
715
  if (!numMatch || parseInt(numMatch[1]!, 10) !== phaseNum) return false;
702
716
  const slugPart = numMatch[2]!;
@@ -704,8 +718,8 @@ function phaseDirMatchesMilestoneId(dirName: string, milestoneId: string, phaseN
704
718
  if (suffix) {
705
719
  return slugPart === suffix || slugPart.startsWith(`${suffix}-`);
706
720
  }
707
- // Plain sequential IDs must not resolve to unique-suffix phase dirs.
708
- return !/^[a-z0-9]{6}(-|$)/.test(slugPart);
721
+ if (slugLooksLikeTeamSuffixProjection(slugPart) && !allowTeamSuffixSlugs) return false;
722
+ return true;
709
723
  }
710
724
 
711
725
  function resolvePhaseDir(basePath: string, milestoneId: string): string | null {
@@ -726,6 +740,15 @@ function resolvePhaseDir(basePath: string, milestoneId: string): string | null {
726
740
  matches.push(entry.name);
727
741
  }
728
742
  }
743
+ // Bare milestone ids may only have a suffixed team-mode projection on disk.
744
+ if (matches.length === 0 && !milestoneIdUniqueSuffix(milestoneId)) {
745
+ for (const entry of readdirSync(phasesDir, { withFileTypes: true })) {
746
+ if (!entry.isDirectory()) continue;
747
+ if (phaseDirMatchesMilestoneId(entry.name, milestoneId, phaseNum, true)) {
748
+ matches.push(entry.name);
749
+ }
750
+ }
751
+ }
729
752
  } catch {
730
753
  // unreadable — fall through
731
754
  }
@@ -898,10 +921,24 @@ export function resolveTaskFile(
898
921
  basePath: string, milestoneId: string, sliceId: string,
899
922
  taskId: string, suffix: string
900
923
  ): string | null {
924
+ const phaseDir = resolveMilestonePath(basePath, milestoneId);
925
+ if (!phaseDir) return null;
926
+
927
+ const legacyBase = legacyMilestonesDir(basePath);
928
+ const isLegacy = phaseDir.startsWith(legacyBase + "/") || phaseDir.startsWith(legacyBase + "\\");
929
+
930
+ if (suffix !== "PLAN" && !isLegacy) {
931
+ const flatPath = join(phaseDir, buildTaskFileName(taskId, suffix));
932
+ return existsSync(flatPath) ? flatPath : null;
933
+ }
934
+
901
935
  const tDir = resolveTasksDir(basePath, milestoneId, sliceId);
902
- if (!tDir) return null;
903
- const file = resolveFile(tDir, taskId, suffix);
904
- return file ? join(tDir, file) : null;
936
+ if (tDir) {
937
+ const file = resolveFile(tDir, taskId, suffix);
938
+ if (file) return join(tDir, file);
939
+ }
940
+
941
+ return null;
905
942
  }
906
943
 
907
944
  // ─── Relative Path Builders (for prompts — .gsd/milestones/...) ────────────
@@ -936,31 +973,41 @@ export function relMilestonePath(basePath: string, milestoneId: string, title?:
936
973
  }
937
974
 
938
975
  /**
939
- * Build relative .gsd/ path to a milestone file.
940
- * Layout-aware: uses resolveMilestoneFile to find NN-SUFFIX.md (flat-phase)
941
- * or M001-SUFFIX.md (legacy). Falls back to a layout-appropriate canonical
942
- * name when the file doesn't exist yet.
976
+ * Build the canonical absolute write target for a milestone file.
977
+ * Existing compatibility filenames are intentionally ignored; readers that need
978
+ * to preserve an existing file should call resolveMilestoneFile first.
943
979
  */
944
- export function relMilestoneFile(
945
- basePath: string, milestoneId: string, suffix: string
980
+ export function targetMilestoneFile(
981
+ basePath: string, milestoneId: string, suffix: string, title?: string
946
982
  ): string {
947
- const mRel = relMilestonePath(basePath, milestoneId);
948
- // resolveMilestoneFile checks NN-SUFFIX.md (flat-phase) and MID-SUFFIX.md (legacy).
949
- const absFile = resolveMilestoneFile(basePath, milestoneId, suffix);
950
- if (absFile) {
951
- const fileName = absFile.split(/[/\\]/).pop()!;
952
- return `${mRel}/${fileName}`;
953
- }
954
- // File doesn't exist yet — use layout-aware fallback filename.
955
983
  const mDir = resolveMilestonePath(basePath, milestoneId);
956
984
  const legacyBase = legacyMilestonesDir(basePath);
957
985
  const isLegacy = mDir
958
986
  ? mDir.startsWith(legacyBase + "/") || mDir.startsWith(legacyBase + "\\")
959
- : false;
987
+ : isLegacyMilestonesLayout(basePath);
988
+ const dir = mDir ?? join(
989
+ isLegacy ? legacyBase : milestonesDir(basePath),
990
+ isLegacy ? milestoneId : canonicalPhaseDirName(milestoneId, title),
991
+ );
960
992
  const fileName = isLegacy
961
993
  ? `${milestoneId}-${suffix}.md`
962
994
  : `${String(milestoneIdToPhaseNum(milestoneId)).padStart(2, "0")}-${suffix}.md`;
963
- return `${mRel}/${fileName}`;
995
+ return join(dir, fileName);
996
+ }
997
+
998
+ /**
999
+ * Build relative .gsd/ path to a milestone file.
1000
+ * Preserves an existing compatibility filename when present; otherwise falls
1001
+ * back to the canonical write target.
1002
+ */
1003
+ export function relMilestoneFile(
1004
+ basePath: string, milestoneId: string, suffix: string, title?: string
1005
+ ): string {
1006
+ const rel = relative(
1007
+ gsdProjectionRoot(basePath),
1008
+ resolveMilestoneFile(basePath, milestoneId, suffix) ?? targetMilestoneFile(basePath, milestoneId, suffix, title),
1009
+ ).replace(/\\/g, "/");
1010
+ return `.gsd/${rel}`;
964
1011
  }
965
1012
 
966
1013
  /**
@@ -992,34 +1039,44 @@ export function relSlicePath(
992
1039
  }
993
1040
 
994
1041
  /**
995
- * Build relative .gsd/ path to a slice file.
996
- * Layout-aware: legacy uses S01-SUFFIX.md; flat-phase uses NN-MM-SUFFIX.md.
997
- *
998
- * @param milestoneTitle - Optional milestone title forwarded to relSlicePath /
999
- * relMilestonePath for title-aware flat-phase fallback dir naming. Only used
1000
- * when the phase directory does not yet exist on disk.
1042
+ * Build the canonical absolute write target for a slice file.
1043
+ * Existing compatibility filenames are intentionally ignored; readers that need
1044
+ * to preserve an existing file should call resolveSliceFile first.
1001
1045
  */
1002
- export function relSliceFile(
1046
+ export function targetSliceFile(
1003
1047
  basePath: string, milestoneId: string, sliceId: string, suffix: string, milestoneTitle?: string
1004
1048
  ): string {
1005
- const sRel = relSlicePath(basePath, milestoneId, sliceId, milestoneTitle);
1006
- const absPath = resolveSliceFile(basePath, milestoneId, sliceId, suffix);
1007
- if (absPath) {
1008
- const fileName = absPath.split(/[/\\]/).pop()!;
1009
- return `${sRel}/${fileName}`;
1010
- }
1011
- // Fallback when file doesn't exist yet — use layout-aware filename.
1012
1049
  const mDir = resolveMilestonePath(basePath, milestoneId);
1013
1050
  const legacyBase = legacyMilestonesDir(basePath);
1014
1051
  const isLegacy = mDir
1015
1052
  ? mDir.startsWith(legacyBase + "/") || mDir.startsWith(legacyBase + "\\")
1016
- : false;
1017
- if (isLegacy) {
1018
- return `${sRel}/${sliceId}-${suffix}.md`;
1019
- }
1020
- const phaseNum = milestoneIdToPhaseNum(milestoneId);
1021
- const planNum = sliceIdToPlanNum(sliceId);
1022
- return `${sRel}/${planFileName(phaseNum, planNum, suffix)}`;
1053
+ : isLegacyMilestonesLayout(basePath);
1054
+ const milestoneDir = mDir
1055
+ ?? dirname(targetMilestoneFile(basePath, milestoneId, "ROADMAP", milestoneTitle));
1056
+ const slicesDir = join(milestoneDir, "slices");
1057
+ const dir = isLegacy
1058
+ ? join(slicesDir, resolveDir(slicesDir, sliceId) ?? sliceId)
1059
+ : milestoneDir;
1060
+ const fileName = isLegacy
1061
+ ? `${sliceId}-${suffix}.md`
1062
+ : planFileName(milestoneIdToPhaseNum(milestoneId), sliceIdToPlanNum(sliceId), suffix);
1063
+ return join(dir, fileName);
1064
+ }
1065
+
1066
+ /**
1067
+ * Build relative .gsd/ path to a slice file.
1068
+ * Preserves an existing compatibility filename when present; otherwise falls
1069
+ * back to the canonical write target.
1070
+ */
1071
+ export function relSliceFile(
1072
+ basePath: string, milestoneId: string, sliceId: string, suffix: string, milestoneTitle?: string
1073
+ ): string {
1074
+ const rel = relative(
1075
+ gsdProjectionRoot(basePath),
1076
+ resolveSliceFile(basePath, milestoneId, sliceId, suffix)
1077
+ ?? targetSliceFile(basePath, milestoneId, sliceId, suffix, milestoneTitle),
1078
+ ).replace(/\\/g, "/");
1079
+ return `.gsd/${rel}`;
1023
1080
  }
1024
1081
 
1025
1082
  /**
@@ -1031,7 +1088,7 @@ export function relSliceFile(
1031
1088
  */
1032
1089
  export function relTaskFile(
1033
1090
  basePath: string, milestoneId: string, sliceId: string,
1034
- taskId: string, suffix: string
1091
+ taskId: string, suffix: string, milestoneTitle?: string
1035
1092
  ): string {
1036
1093
  const sDir = resolveSlicePath(basePath, milestoneId, sliceId);
1037
1094
  const phaseDir = resolveMilestonePath(basePath, milestoneId);
@@ -1044,6 +1101,6 @@ export function relTaskFile(
1044
1101
  if (suffix === "PLAN") {
1045
1102
  return relSliceFile(basePath, milestoneId, sliceId, "PLAN");
1046
1103
  }
1047
- const relS = relSlicePath(basePath, milestoneId, sliceId);
1104
+ const relS = relSlicePath(basePath, milestoneId, sliceId, milestoneTitle);
1048
1105
  return `${relS}/${buildTaskFileName(taskId, suffix)}`;
1049
1106
  }
@@ -11,6 +11,7 @@ import type {
11
11
  HookStatusEntry,
12
12
  PostUnitGateBlock,
13
13
  } from "./types.js";
14
+ import type { SidecarItem } from "./auto/session.js";
14
15
  import { getOrCreateRegistry, resolveHookArtifactPath } from "./rule-registry.js";
15
16
 
16
17
  // Re-export resolveHookArtifactPath so existing importers still work.
@@ -75,6 +76,37 @@ export function restoreHookState(basePath: string): void {
75
76
  getOrCreateRegistry().restoreState(basePath);
76
77
  }
77
78
 
79
+ /**
80
+ * Reconcile a restored `activeHook` against the session's sidecar queue.
81
+ *
82
+ * The registry persists `activeHook` to disk but the pending hook *dispatch*
83
+ * lives only on the non-persisted `s.sidecarQueue`. After a pause/resume or
84
+ * crash-recovery, `restoreHookState` re-hydrates `activeHook` while the dispatch
85
+ * is gone, so the registry believes a hook is in-flight but nothing will ever
86
+ * complete it — and the next unrelated unit's close-out is falsely charged
87
+ * against the stale hook and blocked. Re-enqueue the missing dispatch so the
88
+ * hook actually runs, restoring the invariant that a persisted `activeHook`
89
+ * always has a live dispatch (#1246).
90
+ */
91
+ export function reconcileRestoredHookDispatch(
92
+ basePath: string,
93
+ sidecarQueue: SidecarItem[],
94
+ ): void {
95
+ const dispatch = getOrCreateRegistry().getPendingHookDispatch(basePath);
96
+ if (!dispatch) return;
97
+ const alreadyQueued = sidecarQueue.some(
98
+ item => item.kind === "hook" && item.unitType === dispatch.unitType,
99
+ );
100
+ if (alreadyQueued) return;
101
+ sidecarQueue.push({
102
+ kind: "hook",
103
+ unitType: dispatch.unitType,
104
+ unitId: dispatch.unitId,
105
+ prompt: dispatch.prompt,
106
+ model: dispatch.model,
107
+ });
108
+ }
109
+
78
110
  export function clearPersistedHookState(basePath: string): void {
79
111
  getOrCreateRegistry().clearPersistedState(basePath);
80
112
  }