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
@@ -0,0 +1,129 @@
1
+ /**
2
+ * reopen-task handler — the core operation behind gsd_task_reopen.
3
+ *
4
+ * Resets a completed task back to "pending" so it can be re-done
5
+ * without manual SQL surgery. The parent slice and milestone must
6
+ * still be open (not complete) — you cannot reopen tasks inside a
7
+ * closed slice.
8
+ */
9
+
10
+ // GSD — reopen-task tool handler
11
+ // Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
12
+
13
+ import {
14
+ getMilestone,
15
+ getSlice,
16
+ getTask,
17
+ updateTaskStatus,
18
+ transaction,
19
+ } from "../gsd-db.js";
20
+ import { invalidateStateCache } from "../state.js";
21
+ import { renderAllProjections } from "../workflow-projections.js";
22
+ import { writeManifest } from "../workflow-manifest.js";
23
+ import { appendEvent } from "../workflow-events.js";
24
+
25
+ export interface ReopenTaskParams {
26
+ milestoneId: string;
27
+ sliceId: string;
28
+ taskId: string;
29
+ reason?: string;
30
+ /** Optional caller-provided identity for audit trail */
31
+ actorName?: string;
32
+ /** Optional caller-provided reason this action was triggered */
33
+ triggerReason?: string;
34
+ }
35
+
36
+ export interface ReopenTaskResult {
37
+ milestoneId: string;
38
+ sliceId: string;
39
+ taskId: string;
40
+ }
41
+
42
+ export async function handleReopenTask(
43
+ params: ReopenTaskParams,
44
+ basePath: string,
45
+ ): Promise<ReopenTaskResult | { error: string }> {
46
+ // ── Validate required fields ────────────────────────────────────────────
47
+ if (!params.taskId || typeof params.taskId !== "string" || params.taskId.trim() === "") {
48
+ return { error: "taskId is required and must be a non-empty string" };
49
+ }
50
+ if (!params.sliceId || typeof params.sliceId !== "string" || params.sliceId.trim() === "") {
51
+ return { error: "sliceId is required and must be a non-empty string" };
52
+ }
53
+ if (!params.milestoneId || typeof params.milestoneId !== "string" || params.milestoneId.trim() === "") {
54
+ return { error: "milestoneId is required and must be a non-empty string" };
55
+ }
56
+
57
+ // ── Guards + DB write inside a single transaction (prevents TOCTOU) ────
58
+ let guardError: string | null = null;
59
+
60
+ transaction(() => {
61
+ const milestone = getMilestone(params.milestoneId);
62
+ if (!milestone) {
63
+ guardError = `milestone not found: ${params.milestoneId}`;
64
+ return;
65
+ }
66
+ if (milestone.status === "complete" || milestone.status === "done") {
67
+ guardError = `cannot reopen task in a closed milestone: ${params.milestoneId} (status: ${milestone.status})`;
68
+ return;
69
+ }
70
+
71
+ const slice = getSlice(params.milestoneId, params.sliceId);
72
+ if (!slice) {
73
+ guardError = `slice not found: ${params.milestoneId}/${params.sliceId}`;
74
+ return;
75
+ }
76
+ if (slice.status === "complete" || slice.status === "done") {
77
+ guardError = `cannot reopen task inside a closed slice: ${params.sliceId} (status: ${slice.status}) — use gsd_slice_reopen first`;
78
+ return;
79
+ }
80
+
81
+ const task = getTask(params.milestoneId, params.sliceId, params.taskId);
82
+ if (!task) {
83
+ guardError = `task not found: ${params.milestoneId}/${params.sliceId}/${params.taskId}`;
84
+ return;
85
+ }
86
+ if (task.status !== "complete" && task.status !== "done") {
87
+ guardError = `task ${params.taskId} is not complete (status: ${task.status}) — nothing to reopen`;
88
+ return;
89
+ }
90
+
91
+ updateTaskStatus(params.milestoneId, params.sliceId, params.taskId, "pending");
92
+ });
93
+
94
+ if (guardError) {
95
+ return { error: guardError };
96
+ }
97
+
98
+ // ── Invalidate caches ────────────────────────────────────────────────────
99
+ invalidateStateCache();
100
+
101
+ // ── Post-mutation hook ───────────────────────────────────────────────────
102
+ try {
103
+ await renderAllProjections(basePath, params.milestoneId);
104
+ writeManifest(basePath);
105
+ appendEvent(basePath, {
106
+ cmd: "reopen-task",
107
+ params: {
108
+ milestoneId: params.milestoneId,
109
+ sliceId: params.sliceId,
110
+ taskId: params.taskId,
111
+ reason: params.reason ?? null,
112
+ },
113
+ ts: new Date().toISOString(),
114
+ actor: "agent",
115
+ actor_name: params.actorName,
116
+ trigger_reason: params.triggerReason,
117
+ });
118
+ } catch (hookErr) {
119
+ process.stderr.write(
120
+ `gsd: reopen-task post-mutation hook warning: ${(hookErr as Error).message}\n`,
121
+ );
122
+ }
123
+
124
+ return {
125
+ milestoneId: params.milestoneId,
126
+ sliceId: params.sliceId,
127
+ taskId: params.taskId,
128
+ };
129
+ }
@@ -11,6 +11,9 @@ import {
11
11
  } from "../gsd-db.js";
12
12
  import { invalidateStateCache } from "../state.js";
13
13
  import { renderPlanFromDb, renderReplanFromDb } 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";
14
17
 
15
18
  export interface ReplanSliceTaskInput {
16
19
  taskId: string;
@@ -32,6 +35,10 @@ export interface ReplanSliceParams {
32
35
  whatChanged: string;
33
36
  updatedTasks: ReplanSliceTaskInput[];
34
37
  removedTaskIds: string[];
38
+ /** Optional caller-provided identity for audit trail */
39
+ actorName?: string;
40
+ /** Optional caller-provided reason this action was triggered */
41
+ triggerReason?: string;
35
42
  }
36
43
 
37
44
  export interface ReplanSliceResult {
@@ -83,11 +90,23 @@ export async function handleReplanSlice(
83
90
  return { error: `validation failed: ${(err as Error).message}` };
84
91
  }
85
92
 
86
- // ── Verify parent slice exists ────────────────────────────────────
93
+ // ── Verify parent slice exists and is not closed ─────────────────
87
94
  const parentSlice = getSlice(params.milestoneId, params.sliceId);
88
95
  if (!parentSlice) {
89
96
  return { error: `missing parent slice: ${params.milestoneId}/${params.sliceId}` };
90
97
  }
98
+ if (parentSlice.status === "complete" || parentSlice.status === "done") {
99
+ return { error: `cannot replan a closed slice: ${params.sliceId} (status: ${parentSlice.status})` };
100
+ }
101
+
102
+ // ── Verify blocker task exists and is complete ────────────────────
103
+ const blockerTask = getTask(params.milestoneId, params.sliceId, params.blockerTaskId);
104
+ if (!blockerTask) {
105
+ return { error: `blockerTaskId not found: ${params.milestoneId}/${params.sliceId}/${params.blockerTaskId}` };
106
+ }
107
+ if (blockerTask.status !== "complete" && blockerTask.status !== "done") {
108
+ return { error: `blockerTaskId ${params.blockerTaskId} is not complete (status: ${blockerTask.status}) — the blocker task must be finished before a replan is triggered` };
109
+ }
91
110
 
92
111
  // ── Structural enforcement ────────────────────────────────────────
93
112
  const existingTasks = getSliceTasks(params.milestoneId, params.sliceId);
@@ -183,6 +202,24 @@ export async function handleReplanSlice(
183
202
  invalidateStateCache();
184
203
  clearParseCache();
185
204
 
205
+ // ── Post-mutation hook: projections, manifest, event log ─────
206
+ try {
207
+ await renderAllProjections(basePath, params.milestoneId);
208
+ writeManifest(basePath);
209
+ appendEvent(basePath, {
210
+ cmd: "replan-slice",
211
+ params: { milestoneId: params.milestoneId, sliceId: params.sliceId, blockerTaskId: params.blockerTaskId },
212
+ ts: new Date().toISOString(),
213
+ actor: "agent",
214
+ actor_name: params.actorName,
215
+ trigger_reason: params.triggerReason,
216
+ });
217
+ } catch (hookErr) {
218
+ process.stderr.write(
219
+ `gsd: replan-slice post-mutation hook warning: ${(hookErr as Error).message}\n`,
220
+ );
221
+ }
222
+
186
223
  return {
187
224
  milestoneId: params.milestoneId,
188
225
  sliceId: params.sliceId,
@@ -520,6 +520,10 @@ export interface CompleteTaskParams {
520
520
  verdict: string;
521
521
  durationMs: number;
522
522
  }>;
523
+ /** Optional caller-provided identity for audit trail */
524
+ actorName?: string;
525
+ /** Optional caller-provided reason this action was triggered */
526
+ triggerReason?: string;
523
527
  }
524
528
 
525
529
  // ─── Complete Slice Params (gsd_complete_slice tool input) ───────────────
@@ -548,4 +552,8 @@ export interface CompleteSliceParams {
548
552
  requires: Array<{ slice: string; provides: string }>;
549
553
  affects: string[];
550
554
  drillDownPaths: string[];
555
+ /** Optional caller-provided identity for audit trail */
556
+ actorName?: string;
557
+ /** Optional caller-provided reason this action was triggered */
558
+ triggerReason?: string;
551
559
  }
@@ -0,0 +1,104 @@
1
+ // GSD Extension — Unit Ownership
2
+ // Opt-in per-unit ownership claims for multi-agent safety.
3
+ //
4
+ // An agent can claim a unit (task, slice) before working on it.
5
+ // complete-task and complete-slice enforce ownership when claims exist.
6
+ // If no claim file is present, ownership is not enforced (backward compatible).
7
+ //
8
+ // Claim file location: .gsd/unit-claims.json
9
+ // Unit key format:
10
+ // task: "<milestoneId>/<sliceId>/<taskId>"
11
+ // slice: "<milestoneId>/<sliceId>"
12
+ //
13
+ // Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
14
+
15
+ import { existsSync, readFileSync, mkdirSync } from "node:fs";
16
+ import { join } from "node:path";
17
+ import { atomicWriteSync } from "./atomic-write.js";
18
+
19
+ // ─── Types ───────────────────────────────────────────────────────────────
20
+
21
+ export interface UnitClaim {
22
+ agent: string;
23
+ claimed_at: string;
24
+ }
25
+
26
+ type ClaimsMap = Record<string, UnitClaim>;
27
+
28
+ // ─── Key Builders ────────────────────────────────────────────────────────
29
+
30
+ export function taskUnitKey(milestoneId: string, sliceId: string, taskId: string): string {
31
+ return `${milestoneId}/${sliceId}/${taskId}`;
32
+ }
33
+
34
+ export function sliceUnitKey(milestoneId: string, sliceId: string): string {
35
+ return `${milestoneId}/${sliceId}`;
36
+ }
37
+
38
+ // ─── File Path ───────────────────────────────────────────────────────────
39
+
40
+ function claimsPath(basePath: string): string {
41
+ return join(basePath, ".gsd", "unit-claims.json");
42
+ }
43
+
44
+ // ─── Read Claims ─────────────────────────────────────────────────────────
45
+
46
+ function readClaims(basePath: string): ClaimsMap | null {
47
+ const path = claimsPath(basePath);
48
+ if (!existsSync(path)) return null;
49
+ try {
50
+ return JSON.parse(readFileSync(path, "utf-8")) as ClaimsMap;
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+
56
+ // ─── Public API ──────────────────────────────────────────────────────────
57
+
58
+ /**
59
+ * Claim a unit for an agent.
60
+ * Overwrites any existing claim for this unit (last writer wins).
61
+ */
62
+ export function claimUnit(basePath: string, unitKey: string, agentName: string): void {
63
+ const claims = readClaims(basePath) ?? {};
64
+ claims[unitKey] = { agent: agentName, claimed_at: new Date().toISOString() };
65
+ const dir = join(basePath, ".gsd");
66
+ mkdirSync(dir, { recursive: true });
67
+ atomicWriteSync(claimsPath(basePath), JSON.stringify(claims, null, 2) + "\n");
68
+ }
69
+
70
+ /**
71
+ * Release a unit claim (remove it from the claims map).
72
+ */
73
+ export function releaseUnit(basePath: string, unitKey: string): void {
74
+ const claims = readClaims(basePath);
75
+ if (!claims || !(unitKey in claims)) return;
76
+ delete claims[unitKey];
77
+ atomicWriteSync(claimsPath(basePath), JSON.stringify(claims, null, 2) + "\n");
78
+ }
79
+
80
+ /**
81
+ * Get the current owner of a unit, or null if unclaimed / no claims file.
82
+ */
83
+ export function getOwner(basePath: string, unitKey: string): string | null {
84
+ const claims = readClaims(basePath);
85
+ if (!claims) return null;
86
+ return claims[unitKey]?.agent ?? null;
87
+ }
88
+
89
+ /**
90
+ * Check if an actor is authorized to operate on a unit.
91
+ * Returns null if ownership passes (or is unclaimed / no file).
92
+ * Returns an error string if a different agent owns the unit.
93
+ */
94
+ export function checkOwnership(
95
+ basePath: string,
96
+ unitKey: string,
97
+ actorName: string | undefined,
98
+ ): string | null {
99
+ if (!actorName) return null; // no actor identity provided — opt-in, so allow
100
+ const owner = getOwner(basePath, unitKey);
101
+ if (owner === null) return null; // unit unclaimed or no claims file
102
+ if (owner === actorName) return null; // actor is the owner
103
+ return `Unit ${unitKey} is owned by ${owner}, not ${actorName}`;
104
+ }
@@ -0,0 +1,154 @@
1
+ import { createHash, randomUUID } from "node:crypto";
2
+ import { appendFileSync, readFileSync, existsSync, mkdirSync } from "node:fs";
3
+ import { join } from "node:path";
4
+ import { atomicWriteSync } from "./atomic-write.js";
5
+
6
+ // ─── Session ID ───────────────────────────────────────────────────────────
7
+
8
+ /**
9
+ * Engine-generated session ID — stable for the lifetime of this process.
10
+ * Agents can reference this to correlate all events from one run.
11
+ */
12
+ const ENGINE_SESSION_ID: string = randomUUID();
13
+
14
+ export function getSessionId(): string {
15
+ return ENGINE_SESSION_ID;
16
+ }
17
+
18
+ // ─── Event Types ─────────────────────────────────────────────────────────
19
+
20
+ export interface WorkflowEvent {
21
+ cmd: string; // e.g. "complete_task"
22
+ params: Record<string, unknown>;
23
+ ts: string; // ISO 8601
24
+ hash: string; // content hash (hex, 16 chars)
25
+ actor: "agent" | "system";
26
+ actor_name?: string; // e.g. "executor-agent-01" — caller-provided identity
27
+ trigger_reason?: string; // e.g. "plan-phase complete" — caller-provided causation
28
+ session_id: string; // engine-generated UUID, stable per process lifetime
29
+ }
30
+
31
+ // ─── appendEvent ─────────────────────────────────────────────────────────
32
+
33
+ /**
34
+ * Append one event to .gsd/event-log.jsonl.
35
+ * Computes a content hash from cmd+params (deterministic, independent of ts/actor/session).
36
+ * Creates .gsd directory if needed.
37
+ */
38
+ export function appendEvent(
39
+ basePath: string,
40
+ event: Omit<WorkflowEvent, "hash" | "session_id"> & { actor_name?: string; trigger_reason?: string },
41
+ ): void {
42
+ const hash = createHash("sha256")
43
+ .update(JSON.stringify({ cmd: event.cmd, params: event.params, ts: event.ts }))
44
+ .digest("hex")
45
+ .slice(0, 16);
46
+
47
+ const fullEvent: WorkflowEvent = {
48
+ ...event,
49
+ hash,
50
+ session_id: ENGINE_SESSION_ID,
51
+ };
52
+ const dir = join(basePath, ".gsd");
53
+ mkdirSync(dir, { recursive: true });
54
+ appendFileSync(join(dir, "event-log.jsonl"), JSON.stringify(fullEvent) + "\n", "utf-8");
55
+ }
56
+
57
+ // ─── readEvents ──────────────────────────────────────────────────────────
58
+
59
+ /**
60
+ * Read all events from a JSONL file.
61
+ * Returns empty array if file doesn't exist.
62
+ * Corrupted lines are skipped with stderr warning.
63
+ */
64
+ export function readEvents(logPath: string): WorkflowEvent[] {
65
+ if (!existsSync(logPath)) {
66
+ return [];
67
+ }
68
+
69
+ const content = readFileSync(logPath, "utf-8");
70
+ const lines = content.split("\n").filter((l) => l.length > 0);
71
+ const events: WorkflowEvent[] = [];
72
+
73
+ for (const line of lines) {
74
+ try {
75
+ events.push(JSON.parse(line) as WorkflowEvent);
76
+ } catch {
77
+ process.stderr.write(`workflow-events: skipping corrupted event line: ${line.slice(0, 80)}\n`);
78
+ }
79
+ }
80
+
81
+ return events;
82
+ }
83
+
84
+ // ─── findForkPoint ───────────────────────────────────────────────────────
85
+
86
+ /**
87
+ * Find the index of the last common event between two logs by comparing hashes.
88
+ * Returns -1 if the first events differ (completely diverged).
89
+ * If one log is a prefix of the other, returns length of shorter - 1.
90
+ */
91
+ export function findForkPoint(
92
+ logA: WorkflowEvent[],
93
+ logB: WorkflowEvent[],
94
+ ): number {
95
+ const minLen = Math.min(logA.length, logB.length);
96
+ let lastCommon = -1;
97
+
98
+ for (let i = 0; i < minLen; i++) {
99
+ if (logA[i]!.hash === logB[i]!.hash) {
100
+ lastCommon = i;
101
+ } else {
102
+ break;
103
+ }
104
+ }
105
+
106
+ return lastCommon;
107
+ }
108
+
109
+ // ─── compactMilestoneEvents ─────────────────────────────────────────────────
110
+
111
+ /**
112
+ * Archive a milestone's events from the active log to a separate file.
113
+ * Active log retains only events from other milestones.
114
+ * Archived file is kept on disk for forensics.
115
+ *
116
+ * @param basePath - Project root (parent of .gsd/)
117
+ * @param milestoneId - The milestone whose events should be archived
118
+ * @returns { archived: number } — count of events moved to archive
119
+ */
120
+ export function compactMilestoneEvents(
121
+ basePath: string,
122
+ milestoneId: string,
123
+ ): { archived: number } {
124
+ const logPath = join(basePath, ".gsd", "event-log.jsonl");
125
+ const archivePath = join(basePath, ".gsd", `event-log-${milestoneId}.jsonl.archived`);
126
+
127
+ const allEvents = readEvents(logPath);
128
+ const toArchive = allEvents.filter(
129
+ (e) => (e.params as { milestoneId?: string }).milestoneId === milestoneId,
130
+ );
131
+ const remaining = allEvents.filter(
132
+ (e) => (e.params as { milestoneId?: string }).milestoneId !== milestoneId,
133
+ );
134
+
135
+ if (toArchive.length === 0) {
136
+ return { archived: 0 };
137
+ }
138
+
139
+ // Write archived events to .jsonl.archived file (crash-safe)
140
+ atomicWriteSync(
141
+ archivePath,
142
+ toArchive.map((e) => JSON.stringify(e)).join("\n") + "\n",
143
+ );
144
+
145
+ // Truncate active log to remaining events only
146
+ atomicWriteSync(
147
+ logPath,
148
+ remaining.length > 0
149
+ ? remaining.map((e) => JSON.stringify(e)).join("\n") + "\n"
150
+ : "",
151
+ );
152
+
153
+ return { archived: toArchive.length };
154
+ }