gsd-pi 2.45.0 → 2.46.0-dev.cc9d310

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 (347) hide show
  1. package/dist/help-text.js +1 -1
  2. package/dist/loader.js +34 -0
  3. package/dist/resources/extensions/gsd/auto/phases.js +27 -42
  4. package/dist/resources/extensions/gsd/auto/run-unit.js +6 -3
  5. package/dist/resources/extensions/gsd/auto/session.js +0 -11
  6. package/dist/resources/extensions/gsd/auto-artifact-paths.js +112 -0
  7. package/dist/resources/extensions/gsd/auto-post-unit.js +25 -96
  8. package/dist/resources/extensions/gsd/auto-start.js +2 -3
  9. package/dist/resources/extensions/gsd/auto-worktree.js +5 -4
  10. package/dist/resources/extensions/gsd/auto.js +12 -57
  11. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +15 -12
  12. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +18 -0
  13. package/dist/resources/extensions/gsd/commands/context.js +0 -4
  14. package/dist/resources/extensions/gsd/commands/handlers/parallel.js +1 -1
  15. package/dist/resources/extensions/gsd/crash-recovery.js +2 -4
  16. package/dist/resources/extensions/gsd/dashboard-overlay.js +0 -44
  17. package/dist/resources/extensions/gsd/db-writer.js +9 -9
  18. package/dist/resources/extensions/gsd/doctor-checks.js +167 -2
  19. package/dist/resources/extensions/gsd/doctor.js +5 -3
  20. package/dist/resources/extensions/gsd/gsd-db.js +16 -3
  21. package/dist/resources/extensions/gsd/guided-flow.js +1 -2
  22. package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
  23. package/dist/resources/extensions/gsd/parallel-orchestrator.js +5 -18
  24. package/dist/resources/extensions/gsd/preferences-types.js +2 -2
  25. package/dist/resources/extensions/gsd/preferences.js +8 -4
  26. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +21 -8
  27. package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -23
  28. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
  29. package/dist/resources/extensions/gsd/prompts/execute-task.md +5 -15
  30. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  31. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  32. package/dist/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  33. package/dist/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  34. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  35. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -2
  36. package/dist/resources/extensions/gsd/prompts/queue.md +2 -2
  37. package/dist/resources/extensions/gsd/prompts/quick-task.md +2 -0
  38. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
  39. package/dist/resources/extensions/gsd/prompts/research-slice.md +3 -3
  40. package/dist/resources/extensions/gsd/prompts/rethink.md +7 -2
  41. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  42. package/dist/resources/extensions/gsd/session-lock.js +1 -3
  43. package/dist/resources/extensions/gsd/state.js +7 -0
  44. package/dist/resources/extensions/gsd/sync-lock.js +89 -0
  45. package/dist/resources/extensions/gsd/tools/complete-milestone.js +61 -11
  46. package/dist/resources/extensions/gsd/tools/complete-slice.js +56 -11
  47. package/dist/resources/extensions/gsd/tools/complete-task.js +50 -2
  48. package/dist/resources/extensions/gsd/tools/plan-milestone.js +37 -1
  49. package/dist/resources/extensions/gsd/tools/plan-slice.js +30 -1
  50. package/dist/resources/extensions/gsd/tools/plan-task.js +27 -1
  51. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +32 -2
  52. package/dist/resources/extensions/gsd/tools/reopen-slice.js +86 -0
  53. package/dist/resources/extensions/gsd/tools/reopen-task.js +90 -0
  54. package/dist/resources/extensions/gsd/tools/replan-slice.js +32 -2
  55. package/dist/resources/extensions/gsd/unit-ownership.js +85 -0
  56. package/dist/resources/extensions/gsd/workflow-events.js +102 -0
  57. package/dist/resources/extensions/gsd/workflow-logger.js +193 -0
  58. package/dist/resources/extensions/gsd/workflow-manifest.js +244 -0
  59. package/dist/resources/extensions/gsd/workflow-migration.js +280 -0
  60. package/dist/resources/extensions/gsd/workflow-projections.js +373 -0
  61. package/dist/resources/extensions/gsd/workflow-reconcile.js +411 -0
  62. package/dist/resources/extensions/gsd/worktree-manager.js +4 -3
  63. package/dist/resources/extensions/gsd/worktree-resolver.js +37 -0
  64. package/dist/resources/extensions/gsd/write-intercept.js +84 -0
  65. package/dist/resources/extensions/voice/index.js +11 -16
  66. package/dist/resources/extensions/voice/linux-ready.js +67 -0
  67. package/dist/web/standalone/.next/BUILD_ID +1 -1
  68. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  69. package/dist/web/standalone/.next/build-manifest.json +3 -3
  70. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  71. package/dist/web/standalone/.next/required-server-files.json +3 -3
  72. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  73. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  74. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  75. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  83. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  99. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  137. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  143. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  157. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  159. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  161. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  163. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/index.html +1 -1
  173. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  174. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  175. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  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 +3 -3
  178. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  179. package/dist/web/standalone/.next/server/app/page.js +2 -2
  180. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  182. package/dist/web/standalone/.next/server/chunks/229.js +1 -1
  183. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  184. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/middleware.js +2 -2
  186. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  188. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  189. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  190. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  191. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  192. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  193. package/dist/web/standalone/.next/static/chunks/app/page-6654a8cca61a3d1c.js +1 -0
  194. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  195. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  196. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  197. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  198. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  199. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  200. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  201. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  202. package/dist/web/standalone/server.js +1 -1
  203. package/package.json +2 -1
  204. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  205. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +2 -0
  206. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  207. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
  208. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  209. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  210. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +4 -0
  211. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -1
  212. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +10 -5
  213. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -1
  214. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts +2 -0
  215. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts.map +1 -0
  216. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js +185 -0
  217. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js.map +1 -0
  218. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +239 -10
  219. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  220. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +2 -1
  221. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/core/model-registry.js +20 -2
  223. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  224. package/packages/pi-coding-agent/dist/core/package-commands.test.js +206 -195
  225. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -1
  226. package/packages/pi-coding-agent/package.json +1 -1
  227. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +2 -0
  228. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
  229. package/packages/pi-coding-agent/src/core/lifecycle-hooks.test.ts +227 -0
  230. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +11 -5
  231. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +297 -11
  232. package/packages/pi-coding-agent/src/core/model-registry.ts +30 -3
  233. package/packages/pi-coding-agent/src/core/package-commands.test.ts +227 -205
  234. package/pkg/package.json +1 -1
  235. package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -19
  236. package/src/resources/extensions/gsd/auto/phases.ts +24 -44
  237. package/src/resources/extensions/gsd/auto/run-unit.ts +6 -3
  238. package/src/resources/extensions/gsd/auto/session.ts +0 -18
  239. package/src/resources/extensions/gsd/auto-artifact-paths.ts +131 -0
  240. package/src/resources/extensions/gsd/auto-dashboard.ts +0 -1
  241. package/src/resources/extensions/gsd/auto-post-unit.ts +25 -106
  242. package/src/resources/extensions/gsd/auto-start.ts +1 -3
  243. package/src/resources/extensions/gsd/auto-worktree.ts +8 -5
  244. package/src/resources/extensions/gsd/auto.ts +7 -83
  245. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +15 -12
  246. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -0
  247. package/src/resources/extensions/gsd/commands/context.ts +0 -5
  248. package/src/resources/extensions/gsd/commands/handlers/parallel.ts +1 -1
  249. package/src/resources/extensions/gsd/crash-recovery.ts +1 -5
  250. package/src/resources/extensions/gsd/dashboard-overlay.ts +0 -50
  251. package/src/resources/extensions/gsd/db-writer.ts +9 -17
  252. package/src/resources/extensions/gsd/doctor-checks.ts +180 -2
  253. package/src/resources/extensions/gsd/doctor-types.ts +7 -1
  254. package/src/resources/extensions/gsd/doctor.ts +6 -3
  255. package/src/resources/extensions/gsd/gsd-db.ts +16 -3
  256. package/src/resources/extensions/gsd/guided-flow.ts +1 -2
  257. package/src/resources/extensions/gsd/journal.ts +6 -1
  258. package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
  259. package/src/resources/extensions/gsd/parallel-orchestrator.ts +5 -21
  260. package/src/resources/extensions/gsd/preferences-types.ts +2 -2
  261. package/src/resources/extensions/gsd/preferences.ts +7 -3
  262. package/src/resources/extensions/gsd/prompts/complete-milestone.md +21 -8
  263. package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -23
  264. package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
  265. package/src/resources/extensions/gsd/prompts/execute-task.md +5 -15
  266. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +1 -1
  267. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +1 -1
  268. package/src/resources/extensions/gsd/prompts/guided-plan-slice.md +1 -1
  269. package/src/resources/extensions/gsd/prompts/guided-research-slice.md +1 -1
  270. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  271. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -2
  272. package/src/resources/extensions/gsd/prompts/queue.md +2 -2
  273. package/src/resources/extensions/gsd/prompts/quick-task.md +2 -0
  274. package/src/resources/extensions/gsd/prompts/reactive-execute.md +1 -1
  275. package/src/resources/extensions/gsd/prompts/research-slice.md +3 -3
  276. package/src/resources/extensions/gsd/prompts/rethink.md +7 -2
  277. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  278. package/src/resources/extensions/gsd/session-lock.ts +0 -4
  279. package/src/resources/extensions/gsd/state.ts +8 -0
  280. package/src/resources/extensions/gsd/sync-lock.ts +94 -0
  281. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +5 -13
  282. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +6 -10
  283. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +96 -0
  284. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +264 -228
  285. package/src/resources/extensions/gsd/tests/complete-task.test.ts +317 -250
  286. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +2 -8
  287. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -3
  288. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +1 -1
  289. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +1 -1
  290. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +15 -24
  291. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
  292. package/src/resources/extensions/gsd/tests/md-importer.test.ts +1 -1
  293. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  294. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +1 -1
  295. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +8 -9
  296. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +42 -3
  297. package/src/resources/extensions/gsd/tests/parallel-budget-atomicity.test.ts +0 -1
  298. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +0 -7
  299. package/src/resources/extensions/gsd/tests/parallel-merge.test.ts +7 -8
  300. package/src/resources/extensions/gsd/tests/parallel-orchestration.test.ts +20 -24
  301. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +0 -2
  302. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +9 -6
  303. package/src/resources/extensions/gsd/tests/post-mutation-hook.test.ts +171 -0
  304. package/src/resources/extensions/gsd/tests/preferences.test.ts +7 -9
  305. package/src/resources/extensions/gsd/tests/projection-regression.test.ts +174 -0
  306. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +15 -14
  307. package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +155 -0
  308. package/src/resources/extensions/gsd/tests/reopen-task.test.ts +165 -0
  309. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +1 -4
  310. package/src/resources/extensions/gsd/tests/stop-auto-remote.test.ts +2 -3
  311. package/src/resources/extensions/gsd/tests/sync-lock.test.ts +122 -0
  312. package/src/resources/extensions/gsd/tests/unit-ownership.test.ts +175 -0
  313. package/src/resources/extensions/gsd/tests/workflow-events.test.ts +205 -0
  314. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +275 -0
  315. package/src/resources/extensions/gsd/tests/workflow-manifest.test.ts +186 -0
  316. package/src/resources/extensions/gsd/tests/workflow-projections.test.ts +171 -0
  317. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +220 -0
  318. package/src/resources/extensions/gsd/tests/write-intercept.test.ts +76 -0
  319. package/src/resources/extensions/gsd/tools/complete-milestone.ts +74 -11
  320. package/src/resources/extensions/gsd/tools/complete-slice.ts +68 -11
  321. package/src/resources/extensions/gsd/tools/complete-task.ts +63 -1
  322. package/src/resources/extensions/gsd/tools/plan-milestone.ts +45 -0
  323. package/src/resources/extensions/gsd/tools/plan-slice.ts +38 -0
  324. package/src/resources/extensions/gsd/tools/plan-task.ts +35 -1
  325. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +39 -1
  326. package/src/resources/extensions/gsd/tools/reopen-slice.ts +125 -0
  327. package/src/resources/extensions/gsd/tools/reopen-task.ts +129 -0
  328. package/src/resources/extensions/gsd/tools/replan-slice.ts +38 -1
  329. package/src/resources/extensions/gsd/types.ts +8 -0
  330. package/src/resources/extensions/gsd/unit-ownership.ts +104 -0
  331. package/src/resources/extensions/gsd/workflow-events.ts +154 -0
  332. package/src/resources/extensions/gsd/workflow-logger.ts +243 -0
  333. package/src/resources/extensions/gsd/workflow-manifest.ts +334 -0
  334. package/src/resources/extensions/gsd/workflow-migration.ts +345 -0
  335. package/src/resources/extensions/gsd/workflow-projections.ts +425 -0
  336. package/src/resources/extensions/gsd/workflow-reconcile.ts +503 -0
  337. package/src/resources/extensions/gsd/worktree-manager.ts +4 -9
  338. package/src/resources/extensions/gsd/worktree-resolver.ts +37 -0
  339. package/src/resources/extensions/gsd/write-intercept.ts +90 -0
  340. package/src/resources/extensions/voice/index.ts +11 -21
  341. package/src/resources/extensions/voice/linux-ready.ts +87 -0
  342. package/src/resources/extensions/voice/tests/linux-ready.test.ts +124 -0
  343. package/dist/web/standalone/.next/static/chunks/app/page-12dd5ece0df4badc.js +0 -1
  344. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  345. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  346. /package/dist/web/standalone/.next/static/{wUzEX1U3CmFcMry2SUDJn → ZIDqryyYDroh_8AnaAOSG}/_buildManifest.js +0 -0
  347. /package/dist/web/standalone/.next/static/{wUzEX1U3CmFcMry2SUDJn → ZIDqryyYDroh_8AnaAOSG}/_ssgManifest.js +0 -0
@@ -15,14 +15,20 @@ import {
15
15
  transaction,
16
16
  insertMilestone,
17
17
  insertSlice,
18
+ getSlice,
18
19
  getSliceTasks,
20
+ getMilestone,
19
21
  updateSliceStatus,
20
22
  _getAdapter,
21
23
  } from "../gsd-db.js";
22
24
  import { resolveSliceFile, resolveSlicePath, clearPathCache } from "../paths.js";
25
+ import { checkOwnership, sliceUnitKey } from "../unit-ownership.js";
23
26
  import { saveFile, clearParseCache } from "../files.js";
24
27
  import { invalidateStateCache } from "../state.js";
25
28
  import { renderRoadmapCheckboxes } from "../markdown-renderer.js";
29
+ import { renderAllProjections } from "../workflow-projections.js";
30
+ import { writeManifest } from "../workflow-manifest.js";
31
+ import { appendEvent } from "../workflow-events.js";
26
32
 
27
33
  export interface CompleteSliceResult {
28
34
  sliceId: string;
@@ -200,27 +206,60 @@ export async function handleCompleteSlice(
200
206
  return { error: "milestoneId is required and must be a non-empty string" };
201
207
  }
202
208
 
203
- // ── Verify all tasks are complete ───────────────────────────────────────
204
- const tasks = getSliceTasks(params.milestoneId, params.sliceId);
205
- if (tasks.length === 0) {
206
- return { error: `no tasks found for slice ${params.sliceId} in milestone ${params.milestoneId}` };
209
+ // ── Ownership check (opt-in: only enforced when claim file exists) ──────
210
+ const ownershipErr = checkOwnership(
211
+ basePath,
212
+ sliceUnitKey(params.milestoneId, params.sliceId),
213
+ params.actorName,
214
+ );
215
+ if (ownershipErr) {
216
+ return { error: ownershipErr };
207
217
  }
208
218
 
209
- const incompleteTasks = tasks.filter(t => t.status !== "complete");
210
- if (incompleteTasks.length > 0) {
211
- const incompleteIds = incompleteTasks.map(t => `${t.id} (status: ${t.status})`).join(", ");
212
- return { error: `incomplete tasks: ${incompleteIds}` };
213
- }
214
-
215
- // ── DB writes inside a transaction ──────────────────────────────────────
219
+ // ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
216
220
  const completedAt = new Date().toISOString();
221
+ let guardError: string | null = null;
217
222
 
218
223
  transaction(() => {
224
+ // State machine preconditions (inside txn for atomicity).
225
+ // Milestone/slice not existing is OK — insertMilestone/insertSlice below will auto-create.
226
+ // Only block if they exist and are closed.
227
+ const milestone = getMilestone(params.milestoneId);
228
+ if (milestone && (milestone.status === "complete" || milestone.status === "done")) {
229
+ guardError = `cannot complete slice in a closed milestone: ${params.milestoneId} (status: ${milestone.status})`;
230
+ return;
231
+ }
232
+
233
+ const slice = getSlice(params.milestoneId, params.sliceId);
234
+ if (slice && (slice.status === "complete" || slice.status === "done")) {
235
+ guardError = `slice ${params.sliceId} is already complete — use gsd_slice_reopen first if you need to redo it`;
236
+ return;
237
+ }
238
+
239
+ // Verify all tasks are complete
240
+ const tasks = getSliceTasks(params.milestoneId, params.sliceId);
241
+ if (tasks.length === 0) {
242
+ guardError = `no tasks found for slice ${params.sliceId} in milestone ${params.milestoneId}`;
243
+ return;
244
+ }
245
+
246
+ const incompleteTasks = tasks.filter(t => t.status !== "complete" && t.status !== "done");
247
+ if (incompleteTasks.length > 0) {
248
+ const incompleteIds = incompleteTasks.map(t => `${t.id} (status: ${t.status})`).join(", ");
249
+ guardError = `incomplete tasks: ${incompleteIds}`;
250
+ return;
251
+ }
252
+
253
+ // All guards passed — perform writes
219
254
  insertMilestone({ id: params.milestoneId });
220
255
  insertSlice({ id: params.sliceId, milestoneId: params.milestoneId });
221
256
  updateSliceStatus(params.milestoneId, params.sliceId, "complete", completedAt);
222
257
  });
223
258
 
259
+ if (guardError) {
260
+ return { error: guardError };
261
+ }
262
+
224
263
  // ── Filesystem operations (outside transaction) ─────────────────────────
225
264
  // If disk render fails, roll back the DB status so deriveState() and
226
265
  // verifyExpectedArtifact() stay consistent (both say "not done").
@@ -291,6 +330,24 @@ export async function handleCompleteSlice(
291
330
  clearPathCache();
292
331
  clearParseCache();
293
332
 
333
+ // ── Post-mutation hook: projections, manifest, event log ───────────────
334
+ try {
335
+ await renderAllProjections(basePath, params.milestoneId);
336
+ writeManifest(basePath);
337
+ appendEvent(basePath, {
338
+ cmd: "complete-slice",
339
+ params: { milestoneId: params.milestoneId, sliceId: params.sliceId },
340
+ ts: new Date().toISOString(),
341
+ actor: "agent",
342
+ actor_name: params.actorName,
343
+ trigger_reason: params.triggerReason,
344
+ });
345
+ } catch (hookErr) {
346
+ process.stderr.write(
347
+ `gsd: complete-slice post-mutation hook warning: ${(hookErr as Error).message}\n`,
348
+ );
349
+ }
350
+
294
351
  return {
295
352
  sliceId: params.sliceId,
296
353
  milestoneId: params.milestoneId,
@@ -17,12 +17,19 @@ import {
17
17
  insertSlice,
18
18
  insertTask,
19
19
  insertVerificationEvidence,
20
+ getMilestone,
21
+ getSlice,
22
+ getTask,
20
23
  _getAdapter,
21
24
  } from "../gsd-db.js";
22
25
  import { resolveSliceFile, resolveTasksDir, clearPathCache } from "../paths.js";
26
+ import { checkOwnership, taskUnitKey } from "../unit-ownership.js";
23
27
  import { saveFile, clearParseCache } from "../files.js";
24
28
  import { invalidateStateCache } from "../state.js";
25
29
  import { renderPlanCheckboxes } from "../markdown-renderer.js";
30
+ import { renderAllProjections } from "../workflow-projections.js";
31
+ import { writeManifest } from "../workflow-manifest.js";
32
+ import { appendEvent } from "../workflow-events.js";
26
33
 
27
34
  export interface CompleteTaskResult {
28
35
  taskId: string;
@@ -131,10 +138,43 @@ export async function handleCompleteTask(
131
138
  return { error: "milestoneId is required and must be a non-empty string" };
132
139
  }
133
140
 
134
- // ── DB writes inside a transaction ──────────────────────────────────────
141
+ // ── Ownership check (opt-in: only enforced when claim file exists) ──────
142
+ const ownershipErr = checkOwnership(
143
+ basePath,
144
+ taskUnitKey(params.milestoneId, params.sliceId, params.taskId),
145
+ params.actorName,
146
+ );
147
+ if (ownershipErr) {
148
+ return { error: ownershipErr };
149
+ }
150
+
151
+ // ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
135
152
  const completedAt = new Date().toISOString();
153
+ let guardError: string | null = null;
136
154
 
137
155
  transaction(() => {
156
+ // State machine preconditions (inside txn for atomicity).
157
+ // Milestone/slice not existing is OK — insertMilestone/insertSlice below will auto-create.
158
+ // Only block if they exist and are closed.
159
+ const milestone = getMilestone(params.milestoneId);
160
+ if (milestone && (milestone.status === "complete" || milestone.status === "done")) {
161
+ guardError = `cannot complete task in a closed milestone: ${params.milestoneId} (status: ${milestone.status})`;
162
+ return;
163
+ }
164
+
165
+ const slice = getSlice(params.milestoneId, params.sliceId);
166
+ if (slice && (slice.status === "complete" || slice.status === "done")) {
167
+ guardError = `cannot complete task in a closed slice: ${params.sliceId} (status: ${slice.status})`;
168
+ return;
169
+ }
170
+
171
+ const existingTask = getTask(params.milestoneId, params.sliceId, params.taskId);
172
+ if (existingTask && (existingTask.status === "complete" || existingTask.status === "done")) {
173
+ guardError = `task ${params.taskId} is already complete — use gsd_task_reopen first if you need to redo it`;
174
+ return;
175
+ }
176
+
177
+ // All guards passed — perform writes
138
178
  insertMilestone({ id: params.milestoneId });
139
179
  insertSlice({ id: params.sliceId, milestoneId: params.milestoneId });
140
180
  insertTask({
@@ -167,6 +207,10 @@ export async function handleCompleteTask(
167
207
  }
168
208
  });
169
209
 
210
+ if (guardError) {
211
+ return { error: guardError };
212
+ }
213
+
170
214
  // ── Filesystem operations (outside transaction) ─────────────────────────
171
215
  // If disk render fails, roll back the DB status so deriveState() and
172
216
  // verifyExpectedArtifact() stay consistent (both say "not done").
@@ -236,6 +280,24 @@ export async function handleCompleteTask(
236
280
  clearPathCache();
237
281
  clearParseCache();
238
282
 
283
+ // ── Post-mutation hook: projections, manifest, event log ───────────────
284
+ try {
285
+ await renderAllProjections(basePath, params.milestoneId);
286
+ writeManifest(basePath);
287
+ appendEvent(basePath, {
288
+ cmd: "complete-task",
289
+ params: { milestoneId: params.milestoneId, sliceId: params.sliceId, taskId: params.taskId },
290
+ ts: new Date().toISOString(),
291
+ actor: "agent",
292
+ actor_name: params.actorName,
293
+ trigger_reason: params.triggerReason,
294
+ });
295
+ } catch (hookErr) {
296
+ process.stderr.write(
297
+ `gsd: complete-task post-mutation hook warning: ${(hookErr as Error).message}\n`,
298
+ );
299
+ }
300
+
239
301
  return {
240
302
  taskId: params.taskId,
241
303
  sliceId: params.sliceId,
@@ -1,6 +1,7 @@
1
1
  import { clearParseCache } from "../files.js";
2
2
  import {
3
3
  transaction,
4
+ getMilestone,
4
5
  insertMilestone,
5
6
  insertSlice,
6
7
  upsertMilestonePlanning,
@@ -9,6 +10,9 @@ import {
9
10
  } from "../gsd-db.js";
10
11
  import { invalidateStateCache } from "../state.js";
11
12
  import { renderRoadmapFromDb } from "../markdown-renderer.js";
13
+ import { renderAllProjections } from "../workflow-projections.js";
14
+ import { writeManifest } from "../workflow-manifest.js";
15
+ import { appendEvent } from "../workflow-events.js";
12
16
 
13
17
  export interface PlanMilestoneSliceInput {
14
18
  sliceId: string;
@@ -28,6 +32,10 @@ export interface PlanMilestoneParams {
28
32
  title: string;
29
33
  status?: string;
30
34
  dependsOn?: string[];
35
+ /** Optional caller-provided identity for audit trail */
36
+ actorName?: string;
37
+ /** Optional caller-provided reason this action was triggered */
38
+ triggerReason?: string;
31
39
  vision: string;
32
40
  successCriteria: string[];
33
41
  keyRisks: Array<{ risk: string; whyItMatters: string }>;
@@ -181,6 +189,25 @@ export async function handlePlanMilestone(
181
189
  return { error: `validation failed: ${(err as Error).message}` };
182
190
  }
183
191
 
192
+ // ── State machine preconditions ─────────────────────────────────────────
193
+ const existingMilestone = getMilestone(params.milestoneId);
194
+ if (existingMilestone && (existingMilestone.status === "complete" || existingMilestone.status === "done")) {
195
+ return { error: `cannot re-plan milestone ${params.milestoneId}: it is already complete` };
196
+ }
197
+
198
+ // Validate depends_on: all dependencies must exist and be complete
199
+ if (params.dependsOn && params.dependsOn.length > 0) {
200
+ for (const depId of params.dependsOn) {
201
+ const dep = getMilestone(depId);
202
+ if (!dep) {
203
+ return { error: `depends_on references unknown milestone: ${depId}` };
204
+ }
205
+ if (dep.status !== "complete" && dep.status !== "done") {
206
+ return { error: `depends_on milestone ${depId} is not yet complete (status: ${dep.status})` };
207
+ }
208
+ }
209
+ }
210
+
184
211
  try {
185
212
  transaction(() => {
186
213
  insertMilestone({
@@ -242,6 +269,24 @@ export async function handlePlanMilestone(
242
269
  invalidateStateCache();
243
270
  clearParseCache();
244
271
 
272
+ // ── Post-mutation hook: projections, manifest, event log ───────────────
273
+ try {
274
+ await renderAllProjections(basePath, params.milestoneId);
275
+ writeManifest(basePath);
276
+ appendEvent(basePath, {
277
+ cmd: "plan-milestone",
278
+ params: { milestoneId: params.milestoneId },
279
+ ts: new Date().toISOString(),
280
+ actor: "agent",
281
+ actor_name: params.actorName,
282
+ trigger_reason: params.triggerReason,
283
+ });
284
+ } catch (hookErr) {
285
+ process.stderr.write(
286
+ `gsd: plan-milestone post-mutation hook warning: ${(hookErr as Error).message}\n`,
287
+ );
288
+ }
289
+
245
290
  return {
246
291
  milestoneId: params.milestoneId,
247
292
  roadmapPath,
@@ -1,6 +1,7 @@
1
1
  import { clearParseCache } from "../files.js";
2
2
  import {
3
3
  transaction,
4
+ getMilestone,
4
5
  getSlice,
5
6
  insertTask,
6
7
  upsertSlicePlanning,
@@ -9,6 +10,9 @@ import {
9
10
  } from "../gsd-db.js";
10
11
  import { invalidateStateCache } from "../state.js";
11
12
  import { renderPlanFromDb } from "../markdown-renderer.js";
13
+ import { renderAllProjections } from "../workflow-projections.js";
14
+ import { writeManifest } from "../workflow-manifest.js";
15
+ import { appendEvent } from "../workflow-events.js";
12
16
 
13
17
  export interface PlanSliceTaskInput {
14
18
  taskId: string;
@@ -32,6 +36,10 @@ export interface PlanSliceParams {
32
36
  integrationClosure: string;
33
37
  observabilityImpact: string;
34
38
  tasks: PlanSliceTaskInput[];
39
+ /** Optional caller-provided identity for audit trail */
40
+ actorName?: string;
41
+ /** Optional caller-provided reason this action was triggered */
42
+ triggerReason?: string;
35
43
  }
36
44
 
37
45
  export interface PlanSliceResult {
@@ -136,10 +144,21 @@ export async function handlePlanSlice(
136
144
  return { error: `validation failed: ${(err as Error).message}` };
137
145
  }
138
146
 
147
+ const parentMilestone = getMilestone(params.milestoneId);
148
+ if (!parentMilestone) {
149
+ return { error: `milestone not found: ${params.milestoneId}` };
150
+ }
151
+ if (parentMilestone.status === "complete" || parentMilestone.status === "done") {
152
+ return { error: `cannot plan slice in a closed milestone: ${params.milestoneId} (status: ${parentMilestone.status})` };
153
+ }
154
+
139
155
  const parentSlice = getSlice(params.milestoneId, params.sliceId);
140
156
  if (!parentSlice) {
141
157
  return { error: `missing parent slice: ${params.milestoneId}/${params.sliceId}` };
142
158
  }
159
+ if (parentSlice.status === "complete" || parentSlice.status === "done") {
160
+ return { error: `cannot re-plan slice ${params.sliceId}: it is already complete — use gsd_slice_reopen first` };
161
+ }
143
162
 
144
163
  try {
145
164
  transaction(() => {
@@ -180,6 +199,25 @@ export async function handlePlanSlice(
180
199
  const renderResult = await renderPlanFromDb(basePath, params.milestoneId, params.sliceId);
181
200
  invalidateStateCache();
182
201
  clearParseCache();
202
+
203
+ // ── Post-mutation hook: projections, manifest, event log ─────────────
204
+ try {
205
+ await renderAllProjections(basePath, params.milestoneId);
206
+ writeManifest(basePath);
207
+ appendEvent(basePath, {
208
+ cmd: "plan-slice",
209
+ params: { milestoneId: params.milestoneId, sliceId: params.sliceId },
210
+ ts: new Date().toISOString(),
211
+ actor: "agent",
212
+ actor_name: params.actorName,
213
+ trigger_reason: params.triggerReason,
214
+ });
215
+ } catch (hookErr) {
216
+ process.stderr.write(
217
+ `gsd: plan-slice post-mutation hook warning: ${(hookErr as Error).message}\n`,
218
+ );
219
+ }
220
+
183
221
  return {
184
222
  milestoneId: params.milestoneId,
185
223
  sliceId: params.sliceId,
@@ -2,6 +2,9 @@ import { clearParseCache } from "../files.js";
2
2
  import { transaction, getSlice, getTask, insertTask, upsertTaskPlanning } from "../gsd-db.js";
3
3
  import { invalidateStateCache } from "../state.js";
4
4
  import { renderTaskPlanFromDb } from "../markdown-renderer.js";
5
+ import { renderAllProjections } from "../workflow-projections.js";
6
+ import { writeManifest } from "../workflow-manifest.js";
7
+ import { appendEvent } from "../workflow-events.js";
5
8
 
6
9
  export interface PlanTaskParams {
7
10
  milestoneId: string;
@@ -16,6 +19,10 @@ export interface PlanTaskParams {
16
19
  expectedOutput: string[];
17
20
  observabilityImpact?: string;
18
21
  fullPlanMd?: string;
22
+ /** Optional caller-provided identity for audit trail */
23
+ actorName?: string;
24
+ /** Optional caller-provided reason this action was triggered */
25
+ triggerReason?: string;
19
26
  }
20
27
 
21
28
  export interface PlanTaskResult {
@@ -74,10 +81,18 @@ export async function handlePlanTask(
74
81
  if (!parentSlice) {
75
82
  return { error: `missing parent slice: ${params.milestoneId}/${params.sliceId}` };
76
83
  }
84
+ if (parentSlice.status === "complete" || parentSlice.status === "done") {
85
+ return { error: `cannot plan task in a closed slice: ${params.sliceId} (status: ${parentSlice.status})` };
86
+ }
87
+
88
+ const existingTask = getTask(params.milestoneId, params.sliceId, params.taskId);
89
+ if (existingTask && (existingTask.status === "complete" || existingTask.status === "done")) {
90
+ return { error: `cannot re-plan task ${params.taskId}: it is already complete — use gsd_task_reopen first` };
91
+ }
77
92
 
78
93
  try {
79
94
  transaction(() => {
80
- if (!getTask(params.milestoneId, params.sliceId, params.taskId)) {
95
+ if (!existingTask) {
81
96
  insertTask({
82
97
  id: params.taskId,
83
98
  sliceId: params.sliceId,
@@ -106,6 +121,25 @@ export async function handlePlanTask(
106
121
  const renderResult = await renderTaskPlanFromDb(basePath, params.milestoneId, params.sliceId, params.taskId);
107
122
  invalidateStateCache();
108
123
  clearParseCache();
124
+
125
+ // ── Post-mutation hook: projections, manifest, event log ─────────────
126
+ try {
127
+ await renderAllProjections(basePath, params.milestoneId);
128
+ writeManifest(basePath);
129
+ appendEvent(basePath, {
130
+ cmd: "plan-task",
131
+ params: { milestoneId: params.milestoneId, sliceId: params.sliceId, taskId: params.taskId },
132
+ ts: new Date().toISOString(),
133
+ actor: "agent",
134
+ actor_name: params.actorName,
135
+ trigger_reason: params.triggerReason,
136
+ });
137
+ } catch (hookErr) {
138
+ process.stderr.write(
139
+ `gsd: plan-task post-mutation hook warning: ${(hookErr as Error).message}\n`,
140
+ );
141
+ }
142
+
109
143
  return {
110
144
  milestoneId: params.milestoneId,
111
145
  sliceId: params.sliceId,
@@ -3,6 +3,7 @@ import {
3
3
  transaction,
4
4
  getMilestone,
5
5
  getMilestoneSlices,
6
+ getSlice,
6
7
  insertSlice,
7
8
  updateSliceFields,
8
9
  insertAssessment,
@@ -10,6 +11,9 @@ import {
10
11
  } from "../gsd-db.js";
11
12
  import { invalidateStateCache } from "../state.js";
12
13
  import { renderRoadmapFromDb, renderAssessmentFromDb } from "../markdown-renderer.js";
14
+ import { renderAllProjections } from "../workflow-projections.js";
15
+ import { writeManifest } from "../workflow-manifest.js";
16
+ import { appendEvent } from "../workflow-events.js";
13
17
  import { join } from "node:path";
14
18
 
15
19
  export interface SliceChangeInput {
@@ -30,6 +34,10 @@ export interface ReassessRoadmapParams {
30
34
  added: SliceChangeInput[];
31
35
  removed: string[];
32
36
  };
37
+ /** Optional caller-provided identity for audit trail */
38
+ actorName?: string;
39
+ /** Optional caller-provided reason this action was triggered */
40
+ triggerReason?: string;
33
41
  }
34
42
 
35
43
  export interface ReassessRoadmapResult {
@@ -96,11 +104,23 @@ export async function handleReassessRoadmap(
96
104
  return { error: `validation failed: ${(err as Error).message}` };
97
105
  }
98
106
 
99
- // ── Verify milestone exists ───────────────────────────────────────
107
+ // ── Verify milestone exists and is active ────────────────────────
100
108
  const milestone = getMilestone(params.milestoneId);
101
109
  if (!milestone) {
102
110
  return { error: `milestone not found: ${params.milestoneId}` };
103
111
  }
112
+ if (milestone.status === "complete" || milestone.status === "done") {
113
+ return { error: `cannot reassess a closed milestone: ${params.milestoneId} (status: ${milestone.status})` };
114
+ }
115
+
116
+ // ── Verify completedSliceId is actually complete ──────────────────
117
+ const completedSlice = getSlice(params.milestoneId, params.completedSliceId);
118
+ if (!completedSlice) {
119
+ return { error: `completedSliceId not found: ${params.milestoneId}/${params.completedSliceId}` };
120
+ }
121
+ if (completedSlice.status !== "complete" && completedSlice.status !== "done") {
122
+ return { error: `completedSliceId ${params.completedSliceId} is not complete (status: ${completedSlice.status}) — reassess can only be called after a slice finishes` };
123
+ }
104
124
 
105
125
  // ── Structural enforcement ────────────────────────────────────────
106
126
  const existingSlices = getMilestoneSlices(params.milestoneId);
@@ -191,6 +211,24 @@ export async function handleReassessRoadmap(
191
211
  invalidateStateCache();
192
212
  clearParseCache();
193
213
 
214
+ // ── Post-mutation hook: projections, manifest, event log ─────
215
+ try {
216
+ await renderAllProjections(basePath, params.milestoneId);
217
+ writeManifest(basePath);
218
+ appendEvent(basePath, {
219
+ cmd: "reassess-roadmap",
220
+ params: { milestoneId: params.milestoneId, completedSliceId: params.completedSliceId },
221
+ ts: new Date().toISOString(),
222
+ actor: "agent",
223
+ actor_name: params.actorName,
224
+ trigger_reason: params.triggerReason,
225
+ });
226
+ } catch (hookErr) {
227
+ process.stderr.write(
228
+ `gsd: reassess-roadmap post-mutation hook warning: ${(hookErr as Error).message}\n`,
229
+ );
230
+ }
231
+
194
232
  return {
195
233
  milestoneId: params.milestoneId,
196
234
  completedSliceId: params.completedSliceId,
@@ -0,0 +1,125 @@
1
+ /**
2
+ * reopen-slice handler — the core operation behind gsd_slice_reopen.
3
+ *
4
+ * Resets a completed slice back to "in_progress" and resets ALL of its
5
+ * tasks back to "pending". This is intentional — if you're reopening a
6
+ * slice, you're re-doing the work. Partial resets create ambiguous state.
7
+ *
8
+ * The parent milestone must still be open (not complete).
9
+ */
10
+
11
+ // GSD — reopen-slice tool handler
12
+ // Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
13
+
14
+ import {
15
+ getMilestone,
16
+ getSlice,
17
+ getSliceTasks,
18
+ updateSliceStatus,
19
+ updateTaskStatus,
20
+ transaction,
21
+ } from "../gsd-db.js";
22
+ import { invalidateStateCache } from "../state.js";
23
+ import { renderAllProjections } from "../workflow-projections.js";
24
+ import { writeManifest } from "../workflow-manifest.js";
25
+ import { appendEvent } from "../workflow-events.js";
26
+
27
+ export interface ReopenSliceParams {
28
+ milestoneId: string;
29
+ sliceId: string;
30
+ reason?: string;
31
+ /** Optional caller-provided identity for audit trail */
32
+ actorName?: string;
33
+ /** Optional caller-provided reason this action was triggered */
34
+ triggerReason?: string;
35
+ }
36
+
37
+ export interface ReopenSliceResult {
38
+ milestoneId: string;
39
+ sliceId: string;
40
+ tasksReset: number;
41
+ }
42
+
43
+ export async function handleReopenSlice(
44
+ params: ReopenSliceParams,
45
+ basePath: string,
46
+ ): Promise<ReopenSliceResult | { error: string }> {
47
+ // ── Validate required fields ────────────────────────────────────────────
48
+ if (!params.sliceId || typeof params.sliceId !== "string" || params.sliceId.trim() === "") {
49
+ return { error: "sliceId is required and must be a non-empty string" };
50
+ }
51
+ if (!params.milestoneId || typeof params.milestoneId !== "string" || params.milestoneId.trim() === "") {
52
+ return { error: "milestoneId is required and must be a non-empty string" };
53
+ }
54
+
55
+ // ── Guards + DB writes inside a single transaction (prevents TOCTOU) ───
56
+ let guardError: string | null = null;
57
+ let tasksResetCount = 0;
58
+
59
+ transaction(() => {
60
+ const milestone = getMilestone(params.milestoneId);
61
+ if (!milestone) {
62
+ guardError = `milestone not found: ${params.milestoneId}`;
63
+ return;
64
+ }
65
+ if (milestone.status === "complete" || milestone.status === "done") {
66
+ guardError = `cannot reopen slice inside a closed milestone: ${params.milestoneId} (status: ${milestone.status})`;
67
+ return;
68
+ }
69
+
70
+ const slice = getSlice(params.milestoneId, params.sliceId);
71
+ if (!slice) {
72
+ guardError = `slice not found: ${params.milestoneId}/${params.sliceId}`;
73
+ return;
74
+ }
75
+ if (slice.status !== "complete" && slice.status !== "done") {
76
+ guardError = `slice ${params.sliceId} is not complete (status: ${slice.status}) — nothing to reopen`;
77
+ return;
78
+ }
79
+
80
+ // Fetch tasks inside txn so the list is consistent with the slice status check
81
+ const tasks = getSliceTasks(params.milestoneId, params.sliceId);
82
+ tasksResetCount = tasks.length;
83
+
84
+ updateSliceStatus(params.milestoneId, params.sliceId, "in_progress");
85
+ for (const task of tasks) {
86
+ updateTaskStatus(params.milestoneId, params.sliceId, task.id, "pending");
87
+ }
88
+ });
89
+
90
+ if (guardError) {
91
+ return { error: guardError };
92
+ }
93
+
94
+ // ── Invalidate caches ────────────────────────────────────────────────────
95
+ invalidateStateCache();
96
+
97
+ // ── Post-mutation hook ───────────────────────────────────────────────────
98
+ try {
99
+ await renderAllProjections(basePath, params.milestoneId);
100
+ writeManifest(basePath);
101
+ appendEvent(basePath, {
102
+ cmd: "reopen-slice",
103
+ params: {
104
+ milestoneId: params.milestoneId,
105
+ sliceId: params.sliceId,
106
+ reason: params.reason ?? null,
107
+ tasksReset: tasksResetCount,
108
+ },
109
+ ts: new Date().toISOString(),
110
+ actor: "agent",
111
+ actor_name: params.actorName,
112
+ trigger_reason: params.triggerReason,
113
+ });
114
+ } catch (hookErr) {
115
+ process.stderr.write(
116
+ `gsd: reopen-slice post-mutation hook warning: ${(hookErr as Error).message}\n`,
117
+ );
118
+ }
119
+
120
+ return {
121
+ milestoneId: params.milestoneId,
122
+ sliceId: params.sliceId,
123
+ tasksReset: tasksResetCount,
124
+ };
125
+ }