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
@@ -1,5 +1,4 @@
1
- import { describe, test, afterEach } from "node:test";
2
- import assert from "node:assert/strict";
1
+ import { createTestContext } from './test-helpers.ts';
3
2
  import * as fs from 'node:fs';
4
3
  import * as path from 'node:path';
5
4
  import * as os from 'node:os';
@@ -18,6 +17,8 @@ import {
18
17
  import { handleCompleteSlice } from '../tools/complete-slice.ts';
19
18
  import type { CompleteSliceParams } from '../types.ts';
20
19
 
20
+ const { assertEq, assertTrue, assertMatch, report } = createTestContext();
21
+
21
22
  // ═══════════════════════════════════════════════════════════════════════════
22
23
  // Helpers
23
24
  // ═══════════════════════════════════════════════════════════════════════════
@@ -114,262 +115,297 @@ Run the test suite and verify all assertions pass.
114
115
  }
115
116
 
116
117
  // ═══════════════════════════════════════════════════════════════════════════
117
- // Tests
118
+ // complete-slice: Schema v6 migration
118
119
  // ═══════════════════════════════════════════════════════════════════════════
119
120
 
120
- describe("complete-slice: schema v6 migration", () => {
121
- test("schema version and columns exist", () => {
122
- const dbPath = tempDbPath();
123
- openDatabase(dbPath);
124
-
125
- const adapter = _getAdapter()!;
126
-
127
- // Verify schema version is current (v10 after M001 planning migrations)
128
- const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
129
- assert.strictEqual(versionRow?.['v'], 10, 'schema version should be 10');
130
-
131
- // Verify slices table has full_summary_md and full_uat_md columns
132
- const cols = adapter.prepare("PRAGMA table_info(slices)").all();
133
- const colNames = cols.map(c => c['name'] as string);
134
- assert.ok(colNames.includes('full_summary_md'), 'slices table should have full_summary_md column');
135
- assert.ok(colNames.includes('full_uat_md'), 'slices table should have full_uat_md column');
136
-
137
- cleanup(dbPath);
138
- });
139
- });
140
-
141
- describe("complete-slice: getSlice/updateSliceStatus accessors", () => {
142
- test("getSlice and updateSliceStatus work correctly", () => {
143
- const dbPath = tempDbPath();
144
- openDatabase(dbPath);
145
-
146
- // Insert milestone and slice
147
- insertMilestone({ id: 'M001' });
148
- insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice', risk: 'high' });
149
-
150
- // getSlice returns correct row
151
- const slice = getSlice('M001', 'S01');
152
- assert.ok(slice !== null, 'getSlice should return non-null for existing slice');
153
- assert.strictEqual(slice!.id, 'S01', 'slice id');
154
- assert.strictEqual(slice!.milestone_id, 'M001', 'slice milestone_id');
155
- assert.strictEqual(slice!.title, 'Test Slice', 'slice title');
156
- assert.strictEqual(slice!.risk, 'high', 'slice risk');
157
- assert.strictEqual(slice!.status, 'pending', 'slice default status should be pending');
158
- assert.strictEqual(slice!.completed_at, null, 'slice completed_at should be null initially');
159
- assert.strictEqual(slice!.full_summary_md, '', 'slice full_summary_md should be empty initially');
160
- assert.strictEqual(slice!.full_uat_md, '', 'slice full_uat_md should be empty initially');
161
-
162
- // getSlice returns null for non-existent
163
- const noSlice = getSlice('M001', 'S99');
164
- assert.strictEqual(noSlice, null, 'non-existent slice should return null');
165
-
166
- // updateSliceStatus changes status and completed_at
167
- const now = new Date().toISOString();
168
- updateSliceStatus('M001', 'S01', 'complete', now);
169
- const updated = getSlice('M001', 'S01');
170
- assert.strictEqual(updated!.status, 'complete', 'slice status should be updated to complete');
171
- assert.strictEqual(updated!.completed_at, now, 'slice completed_at should be set');
172
-
173
- cleanup(dbPath);
174
- });
175
- });
176
-
177
- describe("complete-slice: handler", () => {
178
- test("happy path", async () => {
179
- const dbPath = tempDbPath();
180
- openDatabase(dbPath);
181
-
182
- const { basePath, roadmapPath } = createTempProject();
183
-
184
- // Set up DB state: milestone, slice, 2 complete tasks
185
- insertMilestone({ id: 'M001' });
186
- insertSlice({ id: 'S01', milestoneId: 'M001' });
187
- insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
188
- insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 2' });
189
-
190
- const params = makeValidSliceParams();
191
- const result = await handleCompleteSlice(params, basePath);
192
-
193
- assert.ok(!('error' in result), 'handler should succeed without error');
194
- if (!('error' in result)) {
195
- assert.strictEqual(result.sliceId, 'S01', 'result sliceId');
196
- assert.strictEqual(result.milestoneId, 'M001', 'result milestoneId');
197
- assert.ok(result.summaryPath.endsWith('S01-SUMMARY.md'), 'summaryPath should end with S01-SUMMARY.md');
198
- assert.ok(result.uatPath.endsWith('S01-UAT.md'), 'uatPath should end with S01-UAT.md');
199
-
200
- // (a) Verify SUMMARY.md exists on disk with correct YAML frontmatter
201
- assert.ok(fs.existsSync(result.summaryPath), 'summary file should exist on disk');
202
- const summaryContent = fs.readFileSync(result.summaryPath, 'utf-8');
203
- assert.match(summaryContent, /^---\n/, 'summary should start with YAML frontmatter');
204
- assert.match(summaryContent, /id: S01/, 'summary should contain id: S01');
205
- assert.match(summaryContent, /parent: M001/, 'summary should contain parent: M001');
206
- assert.match(summaryContent, /milestone: M001/, 'summary should contain milestone: M001');
207
- assert.match(summaryContent, /blocker_discovered: false/, 'summary should contain blocker_discovered');
208
- assert.match(summaryContent, /verification_result: passed/, 'summary should contain verification_result');
209
- assert.match(summaryContent, /key_files:/, 'summary should contain key_files');
210
- assert.match(summaryContent, /patterns_established:/, 'summary should contain patterns_established');
211
- assert.match(summaryContent, /observability_surfaces:/, 'summary should contain observability_surfaces');
212
- assert.match(summaryContent, /provides:/, 'summary should contain provides');
213
- assert.match(summaryContent, /# S01: Test Slice/, 'summary should have H1 with slice ID and title');
214
- assert.match(summaryContent, /\*\*Implemented test slice with full coverage\*\*/, 'summary should have one-liner in bold');
215
- assert.match(summaryContent, /## What Happened/, 'summary should have What Happened section');
216
- assert.match(summaryContent, /## Verification/, 'summary should have Verification section');
217
- assert.match(summaryContent, /## Requirements Advanced/, 'summary should have Requirements Advanced section');
218
-
219
- // (b) Verify UAT.md exists on disk
220
- assert.ok(fs.existsSync(result.uatPath), 'UAT file should exist on disk');
221
- const uatContent = fs.readFileSync(result.uatPath, 'utf-8');
222
- assert.match(uatContent, /# S01: Test Slice — UAT/, 'UAT should have correct title');
223
- assert.match(uatContent, /Milestone:\*\* M001/, 'UAT should reference milestone');
224
- assert.match(uatContent, /Smoke Test/, 'UAT should contain smoke test from params');
225
-
226
- // (c) Verify roadmap checkbox toggled to [x]
227
- const roadmapContent = fs.readFileSync(roadmapPath, 'utf-8');
228
- assert.match(roadmapContent, /\[x\]\s+\*\*S01:/, 'S01 should be checked in roadmap');
229
- assert.match(roadmapContent, /\[ \]\s+\*\*S02:/, 'S02 should still be unchecked in roadmap');
230
-
231
- // (d) Verify full_summary_md and full_uat_md stored in DB for D004 recovery
232
- const sliceAfter = getSlice('M001', 'S01');
233
- assert.ok(sliceAfter !== null, 'slice should exist in DB after handler');
234
- assert.ok(sliceAfter!.full_summary_md.length > 0, 'full_summary_md should be non-empty in DB');
235
- assert.match(sliceAfter!.full_summary_md, /id: S01/, 'full_summary_md should contain frontmatter');
236
- assert.ok(sliceAfter!.full_uat_md.length > 0, 'full_uat_md should be non-empty in DB');
237
- assert.match(sliceAfter!.full_uat_md, /S01: Test Slice — UAT/, 'full_uat_md should contain UAT title');
238
-
239
- // (e) Verify slice status is complete in DB
240
- assert.strictEqual(sliceAfter!.status, 'complete', 'slice status should be complete in DB');
241
- assert.ok(sliceAfter!.completed_at !== null, 'completed_at should be set in DB');
242
- }
121
+ console.log('\n=== complete-slice: schema v6 migration ===');
122
+ {
123
+ const dbPath = tempDbPath();
124
+ openDatabase(dbPath);
243
125
 
244
- cleanupDir(basePath);
245
- cleanup(dbPath);
246
- });
126
+ const adapter = _getAdapter()!;
247
127
 
248
- test("rejects incomplete tasks", async () => {
249
- const dbPath = tempDbPath();
250
- openDatabase(dbPath);
128
+ // Verify schema version is current (v10 after M001 planning migrations)
129
+ const versionRow = adapter.prepare('SELECT MAX(version) as v FROM schema_version').get();
130
+ assertEq(versionRow?.['v'], 11, 'schema version should be 11');
251
131
 
252
- // Insert milestone, slice, 2 tasks one complete, one pending
253
- insertMilestone({ id: 'M001' });
254
- insertSlice({ id: 'S01', milestoneId: 'M001' });
255
- insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
256
- insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'pending', title: 'Task 2' });
132
+ // Verify slices table has full_summary_md and full_uat_md columns
133
+ const cols = adapter.prepare("PRAGMA table_info(slices)").all();
134
+ const colNames = cols.map(c => c['name'] as string);
135
+ assertTrue(colNames.includes('full_summary_md'), 'slices table should have full_summary_md column');
136
+ assertTrue(colNames.includes('full_uat_md'), 'slices table should have full_uat_md column');
257
137
 
258
- const params = makeValidSliceParams();
259
- const result = await handleCompleteSlice(params, '/tmp/fake');
138
+ cleanup(dbPath);
139
+ }
260
140
 
261
- assert.ok('error' in result, 'should return error when tasks are incomplete');
262
- if ('error' in result) {
263
- assert.match(result.error, /incomplete tasks/, 'error should mention incomplete tasks');
264
- assert.match(result.error, /T02/, 'error should mention the specific incomplete task ID');
265
- }
141
+ // ═══════════════════════════════════════════════════════════════════════════
142
+ // complete-slice: getSlice/updateSliceStatus accessors
143
+ // ═══════════════════════════════════════════════════════════════════════════
266
144
 
267
- cleanup(dbPath);
268
- });
145
+ console.log('\n=== complete-slice: getSlice/updateSliceStatus accessors ===');
146
+ {
147
+ const dbPath = tempDbPath();
148
+ openDatabase(dbPath);
149
+
150
+ // Insert milestone and slice
151
+ insertMilestone({ id: 'M001' });
152
+ insertSlice({ id: 'S01', milestoneId: 'M001', title: 'Test Slice', risk: 'high' });
153
+
154
+ // getSlice returns correct row
155
+ const slice = getSlice('M001', 'S01');
156
+ assertTrue(slice !== null, 'getSlice should return non-null for existing slice');
157
+ assertEq(slice!.id, 'S01', 'slice id');
158
+ assertEq(slice!.milestone_id, 'M001', 'slice milestone_id');
159
+ assertEq(slice!.title, 'Test Slice', 'slice title');
160
+ assertEq(slice!.risk, 'high', 'slice risk');
161
+ assertEq(slice!.status, 'pending', 'slice default status should be pending');
162
+ assertEq(slice!.completed_at, null, 'slice completed_at should be null initially');
163
+ assertEq(slice!.full_summary_md, '', 'slice full_summary_md should be empty initially');
164
+ assertEq(slice!.full_uat_md, '', 'slice full_uat_md should be empty initially');
165
+
166
+ // getSlice returns null for non-existent
167
+ const noSlice = getSlice('M001', 'S99');
168
+ assertEq(noSlice, null, 'non-existent slice should return null');
169
+
170
+ // updateSliceStatus changes status and completed_at
171
+ const now = new Date().toISOString();
172
+ updateSliceStatus('M001', 'S01', 'complete', now);
173
+ const updated = getSlice('M001', 'S01');
174
+ assertEq(updated!.status, 'complete', 'slice status should be updated to complete');
175
+ assertEq(updated!.completed_at, now, 'slice completed_at should be set');
176
+
177
+ cleanup(dbPath);
178
+ }
269
179
 
270
- test("rejects no tasks", async () => {
271
- const dbPath = tempDbPath();
272
- openDatabase(dbPath);
180
+ // ═══════════════════════════════════════════════════════════════════════════
181
+ // complete-slice: Handler happy path
182
+ // ═══════════════════════════════════════════════════════════════════════════
273
183
 
274
- // Insert milestone and slice but NO tasks
275
- insertMilestone({ id: 'M001' });
276
- insertSlice({ id: 'S01', milestoneId: 'M001' });
184
+ console.log('\n=== complete-slice: handler happy path ===');
185
+ {
186
+ const dbPath = tempDbPath();
187
+ openDatabase(dbPath);
188
+
189
+ const { basePath, roadmapPath } = createTempProject();
190
+
191
+ // Set up DB state: milestone, slices (S01 + S02), 2 complete tasks
192
+ insertMilestone({ id: 'M001' });
193
+ insertSlice({ id: 'S01', milestoneId: 'M001' });
194
+ insertSlice({ id: 'S02', milestoneId: 'M001', title: 'Second Slice' });
195
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
196
+ insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 2' });
197
+
198
+ const params = makeValidSliceParams();
199
+ const result = await handleCompleteSlice(params, basePath);
200
+
201
+ assertTrue(!('error' in result), 'handler should succeed without error');
202
+ if (!('error' in result)) {
203
+ assertEq(result.sliceId, 'S01', 'result sliceId');
204
+ assertEq(result.milestoneId, 'M001', 'result milestoneId');
205
+ assertTrue(result.summaryPath.endsWith('S01-SUMMARY.md'), 'summaryPath should end with S01-SUMMARY.md');
206
+ assertTrue(result.uatPath.endsWith('S01-UAT.md'), 'uatPath should end with S01-UAT.md');
207
+
208
+ // (a) Verify SUMMARY.md exists on disk with correct YAML frontmatter
209
+ assertTrue(fs.existsSync(result.summaryPath), 'summary file should exist on disk');
210
+ const summaryContent = fs.readFileSync(result.summaryPath, 'utf-8');
211
+ assertMatch(summaryContent, /^---\n/, 'summary should start with YAML frontmatter');
212
+ assertMatch(summaryContent, /id: S01/, 'summary should contain id: S01');
213
+ assertMatch(summaryContent, /parent: M001/, 'summary should contain parent: M001');
214
+ assertMatch(summaryContent, /milestone: M001/, 'summary should contain milestone: M001');
215
+ assertMatch(summaryContent, /blocker_discovered: false/, 'summary should contain blocker_discovered');
216
+ assertMatch(summaryContent, /verification_result: passed/, 'summary should contain verification_result');
217
+ assertMatch(summaryContent, /key_files:/, 'summary should contain key_files');
218
+ assertMatch(summaryContent, /patterns_established:/, 'summary should contain patterns_established');
219
+ assertMatch(summaryContent, /observability_surfaces:/, 'summary should contain observability_surfaces');
220
+ assertMatch(summaryContent, /provides:/, 'summary should contain provides');
221
+ assertMatch(summaryContent, /# S01: Test Slice/, 'summary should have H1 with slice ID and title');
222
+ assertMatch(summaryContent, /\*\*Implemented test slice with full coverage\*\*/, 'summary should have one-liner in bold');
223
+ assertMatch(summaryContent, /## What Happened/, 'summary should have What Happened section');
224
+ assertMatch(summaryContent, /## Verification/, 'summary should have Verification section');
225
+ assertMatch(summaryContent, /## Requirements Advanced/, 'summary should have Requirements Advanced section');
226
+
227
+ // (b) Verify UAT.md exists on disk
228
+ assertTrue(fs.existsSync(result.uatPath), 'UAT file should exist on disk');
229
+ const uatContent = fs.readFileSync(result.uatPath, 'utf-8');
230
+ assertMatch(uatContent, /# S01: Test Slice — UAT/, 'UAT should have correct title');
231
+ assertMatch(uatContent, /Milestone:\*\* M001/, 'UAT should reference milestone');
232
+ assertMatch(uatContent, /Smoke Test/, 'UAT should contain smoke test from params');
233
+
234
+ // (c) Verify roadmap shows S01 complete (✅) and S02 pending (⬜) in table format
235
+ // Projection renders roadmap as a Slice Overview table, not checkbox list
236
+ const roadmapContent = fs.readFileSync(roadmapPath, 'utf-8');
237
+ assertMatch(roadmapContent, /\| S01 \|/, 'S01 should appear in roadmap table');
238
+ assertTrue(roadmapContent.includes('✅'), 'completed S01 should show ✅ in roadmap table');
239
+ assertMatch(roadmapContent, /\| S02 \|/, 'S02 should appear in roadmap table');
240
+ assertTrue(roadmapContent.includes('⬜'), 'pending S02 should show ⬜ in roadmap table');
241
+
242
+ // (d) Verify full_summary_md and full_uat_md stored in DB for D004 recovery
243
+ const sliceAfter = getSlice('M001', 'S01');
244
+ assertTrue(sliceAfter !== null, 'slice should exist in DB after handler');
245
+ assertTrue(sliceAfter!.full_summary_md.length > 0, 'full_summary_md should be non-empty in DB');
246
+ assertMatch(sliceAfter!.full_summary_md, /id: S01/, 'full_summary_md should contain frontmatter');
247
+ assertTrue(sliceAfter!.full_uat_md.length > 0, 'full_uat_md should be non-empty in DB');
248
+ assertMatch(sliceAfter!.full_uat_md, /S01: Test Slice — UAT/, 'full_uat_md should contain UAT title');
249
+
250
+ // (e) Verify slice status is complete in DB
251
+ assertEq(sliceAfter!.status, 'complete', 'slice status should be complete in DB');
252
+ assertTrue(sliceAfter!.completed_at !== null, 'completed_at should be set in DB');
253
+ }
277
254
 
278
- const params = makeValidSliceParams();
279
- const result = await handleCompleteSlice(params, '/tmp/fake');
255
+ cleanupDir(basePath);
256
+ cleanup(dbPath);
257
+ }
280
258
 
281
- assert.ok('error' in result, 'should return error when no tasks exist');
282
- if ('error' in result) {
283
- assert.match(result.error, /no tasks found/, 'error should say no tasks found');
284
- }
259
+ // ═══════════════════════════════════════════════════════════════════════════
260
+ // complete-slice: Handler rejects incomplete tasks
261
+ // ═══════════════════════════════════════════════════════════════════════════
285
262
 
286
- cleanup(dbPath);
287
- });
263
+ console.log('\n=== complete-slice: handler rejects incomplete tasks ===');
264
+ {
265
+ const dbPath = tempDbPath();
266
+ openDatabase(dbPath);
288
267
 
289
- test("validation errors", async () => {
290
- const dbPath = tempDbPath();
291
- openDatabase(dbPath);
268
+ // Insert milestone, slice, 2 tasks — one complete, one pending
269
+ insertMilestone({ id: 'M001' });
270
+ insertSlice({ id: 'S01', milestoneId: 'M001' });
271
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
272
+ insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'pending', title: 'Task 2' });
292
273
 
293
- const params = makeValidSliceParams();
274
+ const params = makeValidSliceParams();
275
+ const result = await handleCompleteSlice(params, '/tmp/fake');
294
276
 
295
- // Empty sliceId
296
- const r1 = await handleCompleteSlice({ ...params, sliceId: '' }, '/tmp/fake');
297
- assert.ok('error' in r1, 'should return error for empty sliceId');
298
- if ('error' in r1) {
299
- assert.match(r1.error, /sliceId/, 'error should mention sliceId');
300
- }
277
+ assertTrue('error' in result, 'should return error when tasks are incomplete');
278
+ if ('error' in result) {
279
+ assertMatch(result.error, /incomplete tasks/, 'error should mention incomplete tasks');
280
+ assertMatch(result.error, /T02/, 'error should mention the specific incomplete task ID');
281
+ }
301
282
 
302
- // Empty milestoneId
303
- const r2 = await handleCompleteSlice({ ...params, milestoneId: '' }, '/tmp/fake');
304
- assert.ok('error' in r2, 'should return error for empty milestoneId');
305
- if ('error' in r2) {
306
- assert.match(r2.error, /milestoneId/, 'error should mention milestoneId');
307
- }
283
+ cleanup(dbPath);
284
+ }
308
285
 
309
- cleanup(dbPath);
310
- });
286
+ // ═══════════════════════════════════════════════════════════════════════════
287
+ // complete-slice: Handler rejects no tasks
288
+ // ═══════════════════════════════════════════════════════════════════════════
311
289
 
312
- test("idempotency", async () => {
313
- const dbPath = tempDbPath();
314
- openDatabase(dbPath);
290
+ console.log('\n=== complete-slice: handler rejects no tasks ===');
291
+ {
292
+ const dbPath = tempDbPath();
293
+ openDatabase(dbPath);
315
294
 
316
- const { basePath, roadmapPath } = createTempProject();
295
+ // Insert milestone and slice but NO tasks
296
+ insertMilestone({ id: 'M001' });
297
+ insertSlice({ id: 'S01', milestoneId: 'M001' });
317
298
 
318
- // Set up DB state
319
- insertMilestone({ id: 'M001' });
320
- insertSlice({ id: 'S01', milestoneId: 'M001' });
321
- insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
299
+ const params = makeValidSliceParams();
300
+ const result = await handleCompleteSlice(params, '/tmp/fake');
322
301
 
323
- const params = makeValidSliceParams();
302
+ assertTrue('error' in result, 'should return error when no tasks exist');
303
+ if ('error' in result) {
304
+ assertMatch(result.error, /no tasks found/, 'error should say no tasks found');
305
+ }
324
306
 
325
- // First call
326
- const r1 = await handleCompleteSlice(params, basePath);
327
- assert.ok(!('error' in r1), 'first call should succeed');
307
+ cleanup(dbPath);
308
+ }
328
309
 
329
- // Second call with same params — should not crash
330
- const r2 = await handleCompleteSlice(params, basePath);
331
- assert.ok(!('error' in r2), 'second call should succeed (idempotent)');
310
+ // ═══════════════════════════════════════════════════════════════════════════
311
+ // complete-slice: Handler validation errors
312
+ // ═══════════════════════════════════════════════════════════════════════════
332
313
 
333
- // Verify only 1 slice row (not duplicated)
334
- const adapter = _getAdapter()!;
335
- const sliceRows = adapter.prepare("SELECT * FROM slices WHERE milestone_id = 'M001' AND id = 'S01'").all();
336
- assert.strictEqual(sliceRows.length, 1, 'should have exactly 1 slice row after 2 calls');
314
+ console.log('\n=== complete-slice: handler validation errors ===');
315
+ {
316
+ const dbPath = tempDbPath();
317
+ openDatabase(dbPath);
337
318
 
338
- // Files should still exist
339
- if (!('error' in r2)) {
340
- assert.ok(fs.existsSync(r2.summaryPath), 'summary should still exist after second call');
341
- assert.ok(fs.existsSync(r2.uatPath), 'UAT should still exist after second call');
342
- }
319
+ const params = makeValidSliceParams();
343
320
 
344
- cleanupDir(basePath);
345
- cleanup(dbPath);
346
- });
321
+ // Empty sliceId
322
+ const r1 = await handleCompleteSlice({ ...params, sliceId: '' }, '/tmp/fake');
323
+ assertTrue('error' in r1, 'should return error for empty sliceId');
324
+ if ('error' in r1) {
325
+ assertMatch(r1.error, /sliceId/, 'error should mention sliceId');
326
+ }
347
327
 
348
- test("missing roadmap (graceful)", async () => {
349
- const dbPath = tempDbPath();
350
- openDatabase(dbPath);
328
+ // Empty milestoneId
329
+ const r2 = await handleCompleteSlice({ ...params, milestoneId: '' }, '/tmp/fake');
330
+ assertTrue('error' in r2, 'should return error for empty milestoneId');
331
+ if ('error' in r2) {
332
+ assertMatch(r2.error, /milestoneId/, 'error should mention milestoneId');
333
+ }
351
334
 
352
- // Create a temp dir WITHOUT a roadmap file
353
- const basePath = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-no-roadmap-'));
354
- const sliceDir = path.join(basePath, '.gsd', 'milestones', 'M001', 'slices', 'S01');
355
- fs.mkdirSync(sliceDir, { recursive: true });
335
+ cleanup(dbPath);
336
+ }
356
337
 
357
- // Set up DB state
358
- insertMilestone({ id: 'M001' });
359
- insertSlice({ id: 'S01', milestoneId: 'M001' });
360
- insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
338
+ // ═══════════════════════════════════════════════════════════════════════════
339
+ // complete-slice: Handler idempotency
340
+ // ═══════════════════════════════════════════════════════════════════════════
361
341
 
362
- const params = makeValidSliceParams();
363
- const result = await handleCompleteSlice(params, basePath);
342
+ console.log('\n=== complete-slice: handler idempotency ===');
343
+ {
344
+ const dbPath = tempDbPath();
345
+ openDatabase(dbPath);
364
346
 
365
- // Should succeed even without roadmap file — just skip checkbox toggle
366
- assert.ok(!('error' in result), 'handler should succeed without roadmap file');
367
- if (!('error' in result)) {
368
- assert.ok(fs.existsSync(result.summaryPath), 'summary should be written even without roadmap');
369
- assert.ok(fs.existsSync(result.uatPath), 'UAT should be written even without roadmap');
370
- }
347
+ const { basePath, roadmapPath } = createTempProject();
348
+
349
+ // Set up DB state
350
+ insertMilestone({ id: 'M001' });
351
+ insertSlice({ id: 'S01', milestoneId: 'M001' });
352
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
353
+
354
+ const params = makeValidSliceParams();
355
+
356
+ // First call
357
+ const r1 = await handleCompleteSlice(params, basePath);
358
+ assertTrue(!('error' in r1), 'first call should succeed');
359
+
360
+ // Second call — state machine guard rejects (slice is already complete)
361
+ const r2 = await handleCompleteSlice(params, basePath);
362
+ assertTrue('error' in r2, 'second call should return error (slice already complete)');
363
+ if ('error' in r2) {
364
+ assertMatch(r2.error, /already complete/, 'error should mention already complete');
365
+ }
366
+
367
+ // Verify only 1 slice row (not duplicated)
368
+ const adapter = _getAdapter()!;
369
+ const sliceRows = adapter.prepare("SELECT * FROM slices WHERE milestone_id = 'M001' AND id = 'S01'").all();
370
+ assertEq(sliceRows.length, 1, 'should have exactly 1 slice row after calls');
371
+
372
+ cleanupDir(basePath);
373
+ cleanup(dbPath);
374
+ }
375
+
376
+ // ═══════════════════════════════════════════════════════════════════════════
377
+ // complete-slice: Handler with missing roadmap (graceful)
378
+ // ═══════════════════════════════════════════════════════════════════════════
379
+
380
+ console.log('\n=== complete-slice: handler with missing roadmap ===');
381
+ {
382
+ const dbPath = tempDbPath();
383
+ openDatabase(dbPath);
384
+
385
+ // Create a temp dir WITHOUT a roadmap file
386
+ const basePath = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-no-roadmap-'));
387
+ const sliceDir = path.join(basePath, '.gsd', 'milestones', 'M001', 'slices', 'S01');
388
+ fs.mkdirSync(sliceDir, { recursive: true });
389
+
390
+ // Set up DB state
391
+ insertMilestone({ id: 'M001' });
392
+ insertSlice({ id: 'S01', milestoneId: 'M001' });
393
+ insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
394
+
395
+ const params = makeValidSliceParams();
396
+ const result = await handleCompleteSlice(params, basePath);
397
+
398
+ // Should succeed even without roadmap file — just skip checkbox toggle
399
+ assertTrue(!('error' in result), 'handler should succeed without roadmap file');
400
+ if (!('error' in result)) {
401
+ assertTrue(fs.existsSync(result.summaryPath), 'summary should be written even without roadmap');
402
+ assertTrue(fs.existsSync(result.uatPath), 'UAT should be written even without roadmap');
403
+ }
404
+
405
+ cleanupDir(basePath);
406
+ cleanup(dbPath);
407
+ }
408
+
409
+ // ═══════════════════════════════════════════════════════════════════════════
371
410
 
372
- cleanupDir(basePath);
373
- cleanup(dbPath);
374
- });
375
- });
411
+ report();