gsd-pi 2.43.0-next.8 → 2.44.0-dev.0b97ffd

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 (399) hide show
  1. package/README.md +30 -12
  2. package/dist/cli.js +13 -1
  3. package/dist/help-text.js +24 -0
  4. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +21 -8
  5. package/dist/resources/extensions/gsd/auto-prompts.js +130 -51
  6. package/dist/resources/extensions/gsd/auto-start.js +10 -0
  7. package/dist/resources/extensions/gsd/auto-worktree.js +16 -2
  8. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  9. package/dist/resources/extensions/gsd/dispatch-guard.js +34 -10
  10. package/dist/resources/extensions/gsd/markdown-renderer.js +7 -5
  11. package/dist/resources/extensions/gsd/reactive-graph.js +13 -2
  12. package/dist/resources/extensions/gsd/skill-health.js +3 -1
  13. package/dist/resources/extensions/gsd/tools/plan-milestone.js +2 -11
  14. package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -10
  15. package/dist/resources/extensions/gsd/visualizer-data.js +45 -13
  16. package/dist/resources/extensions/gsd/workspace-index.js +46 -15
  17. package/dist/web/standalone/.next/BUILD_ID +1 -1
  18. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -18
  19. package/dist/web/standalone/.next/build-manifest.json +3 -3
  20. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  21. package/dist/web/standalone/.next/required-server-files.json +4 -4
  22. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  23. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  24. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  25. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  30. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  31. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  32. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  33. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  34. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  35. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  36. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  37. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  39. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  41. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  43. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  44. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  45. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  46. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  47. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  48. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  49. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  87. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  93. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  109. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  111. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  113. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/index.html +1 -1
  123. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  124. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  125. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  126. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  128. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/page.js +2 -2
  130. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -18
  132. package/dist/web/standalone/.next/server/chunks/229.js +1 -1
  133. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  134. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/middleware.js +2 -2
  136. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  138. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  139. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  140. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  141. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
  142. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
  143. package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
  144. package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
  145. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  146. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  147. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  148. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  149. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  150. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  151. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  152. package/dist/web/standalone/server.js +1 -1
  153. package/package.json +4 -4
  154. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +3 -3
  155. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  156. package/packages/pi-coding-agent/dist/core/agent-session.js +11 -34
  157. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  158. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  159. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts +2 -2
  161. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  162. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
  163. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +2 -2
  164. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  165. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +4 -4
  167. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  168. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  169. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  170. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  171. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/extensions/loader.js +18 -0
  173. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  175. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  176. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +37 -0
  177. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  178. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  179. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -1
  180. package/packages/pi-coding-agent/dist/core/fallback-resolver.js +2 -3
  181. package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -1
  182. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +12 -2
  183. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  185. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +38 -0
  187. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -0
  188. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +192 -0
  189. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -0
  190. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts +2 -0
  191. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts.map +1 -0
  192. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +255 -0
  193. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -0
  194. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +15 -0
  195. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  196. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  197. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/package-commands.d.ts +25 -0
  199. package/packages/pi-coding-agent/dist/core/package-commands.d.ts.map +1 -0
  200. package/packages/pi-coding-agent/dist/core/package-commands.js +253 -0
  201. package/packages/pi-coding-agent/dist/core/package-commands.js.map +1 -0
  202. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts +2 -0
  203. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts.map +1 -0
  204. package/packages/pi-coding-agent/dist/core/package-commands.test.js +225 -0
  205. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -0
  206. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  207. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  208. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  209. package/packages/pi-coding-agent/dist/core/sdk.js +4 -0
  210. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  211. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  212. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  213. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  214. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  215. package/packages/pi-coding-agent/dist/index.d.ts +3 -1
  216. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  217. package/packages/pi-coding-agent/dist/index.js +1 -0
  218. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  219. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  220. package/packages/pi-coding-agent/dist/main.js +11 -199
  221. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  222. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  223. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  224. package/packages/pi-coding-agent/package.json +1 -1
  225. package/packages/pi-coding-agent/src/core/agent-session.ts +13 -37
  226. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  227. package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +2 -2
  228. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +3 -3
  229. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +4 -4
  230. package/packages/pi-coding-agent/src/core/extensions/index.ts +5 -0
  231. package/packages/pi-coding-agent/src/core/extensions/loader.ts +23 -0
  232. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  233. package/packages/pi-coding-agent/src/core/extensions/types.ts +44 -0
  234. package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +15 -2
  235. package/packages/pi-coding-agent/src/core/fallback-resolver.ts +2 -3
  236. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  237. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +274 -0
  238. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +288 -0
  239. package/packages/pi-coding-agent/src/core/model-registry.ts +39 -3
  240. package/packages/pi-coding-agent/src/core/package-commands.test.ts +240 -0
  241. package/packages/pi-coding-agent/src/core/package-commands.ts +310 -0
  242. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  243. package/packages/pi-coding-agent/src/core/sdk.ts +4 -0
  244. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  245. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  246. package/packages/pi-coding-agent/src/index.ts +7 -0
  247. package/packages/pi-coding-agent/src/main.ts +11 -232
  248. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  249. package/pkg/package.json +1 -1
  250. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +22 -7
  251. package/src/resources/extensions/gsd/auto-prompts.ts +109 -42
  252. package/src/resources/extensions/gsd/auto-start.ts +14 -0
  253. package/src/resources/extensions/gsd/auto-worktree.ts +16 -3
  254. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  255. package/src/resources/extensions/gsd/dispatch-guard.ts +28 -10
  256. package/src/resources/extensions/gsd/markdown-renderer.ts +7 -5
  257. package/src/resources/extensions/gsd/reactive-graph.ts +12 -2
  258. package/src/resources/extensions/gsd/skill-health.ts +2 -1
  259. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  260. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  261. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  262. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  263. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
  264. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  265. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  266. package/src/resources/extensions/gsd/tests/auto-stash-merge.test.ts +3 -3
  267. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
  268. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  269. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  270. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  271. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  272. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  273. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  274. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  275. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
  276. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
  277. package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
  278. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  279. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  280. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  281. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  282. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  283. package/src/resources/extensions/gsd/tests/db-writer.test.ts +390 -420
  284. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  285. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
  286. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +152 -183
  287. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  288. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  289. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  290. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  291. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
  292. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  293. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  294. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
  295. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  296. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
  297. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
  298. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  299. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
  300. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  301. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  302. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
  303. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  304. package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
  305. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  306. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  307. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  308. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  309. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
  310. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
  311. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  312. package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
  313. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  314. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  315. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  316. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  317. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
  318. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  319. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  320. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  321. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
  322. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  323. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  324. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  325. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  326. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
  327. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
  328. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  329. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  330. package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
  331. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  332. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
  333. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  334. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  335. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  336. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
  337. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
  338. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  339. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
  340. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  341. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  342. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  343. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  344. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  345. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  346. package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
  347. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  348. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  349. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  350. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  351. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  352. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  353. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  354. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  355. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  356. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  357. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  358. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  359. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  360. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  361. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  362. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  363. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  364. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  365. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
  366. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  367. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  368. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  369. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  370. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  371. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +9 -11
  372. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  373. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  374. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  375. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  376. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  377. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  378. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  379. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  380. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  381. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  382. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  383. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  384. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  385. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  386. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  387. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  388. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  389. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  390. package/src/resources/extensions/gsd/tools/plan-milestone.ts +1 -18
  391. package/src/resources/extensions/gsd/tools/plan-slice.ts +1 -15
  392. package/src/resources/extensions/gsd/visualizer-data.ts +46 -14
  393. package/src/resources/extensions/gsd/workspace-index.ts +49 -18
  394. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
  395. package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
  396. package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
  397. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
  398. /package/dist/web/standalone/.next/static/{drUWS0zys9uepCfCwecJv → alS4hoANx0TK4UVZY27da}/_buildManifest.js +0 -0
  399. /package/dist/web/standalone/.next/static/{drUWS0zys9uepCfCwecJv → alS4hoANx0TK4UVZY27da}/_ssgManifest.js +0 -0
@@ -1,4 +1,5 @@
1
- import { createTestContext } from './test-helpers.ts';
1
+ import { describe, test, afterEach } from "node:test";
2
+ import assert from "node:assert/strict";
2
3
  import * as fs from 'node:fs';
3
4
  import * as path from 'node:path';
4
5
  import * as os from 'node:os';
@@ -17,8 +18,6 @@ import {
17
18
  import { handleCompleteSlice } from '../tools/complete-slice.ts';
18
19
  import type { CompleteSliceParams } from '../types.ts';
19
20
 
20
- const { assertEq, assertTrue, assertMatch, report } = createTestContext();
21
-
22
21
  // ═══════════════════════════════════════════════════════════════════════════
23
22
  // Helpers
24
23
  // ═══════════════════════════════════════════════════════════════════════════
@@ -115,296 +114,262 @@ Run the test suite and verify all assertions pass.
115
114
  }
116
115
 
117
116
  // ═══════════════════════════════════════════════════════════════════════════
118
- // complete-slice: Schema v6 migration
119
- // ═══════════════════════════════════════════════════════════════════════════
120
-
121
- console.log('\n=== complete-slice: schema v6 migration ===');
122
- {
123
- const dbPath = tempDbPath();
124
- openDatabase(dbPath);
125
-
126
- const adapter = _getAdapter()!;
127
-
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'], 10, 'schema version should be 10');
131
-
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');
137
-
138
- cleanup(dbPath);
139
- }
140
-
141
- // ═══════════════════════════════════════════════════════════════════════════
142
- // complete-slice: getSlice/updateSliceStatus accessors
143
- // ═══════════════════════════════════════════════════════════════════════════
144
-
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
- }
179
-
117
+ // Tests
180
118
  // ═══════════════════════════════════════════════════════════════════════════
181
- // complete-slice: Handler happy path
182
- // ═══════════════════════════════════════════════════════════════════════════
183
-
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, slice, 2 complete tasks
192
- insertMilestone({ id: 'M001' });
193
- insertSlice({ id: 'S01', milestoneId: 'M001' });
194
- insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
195
- insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 2' });
196
-
197
- const params = makeValidSliceParams();
198
- const result = await handleCompleteSlice(params, basePath);
199
-
200
- assertTrue(!('error' in result), 'handler should succeed without error');
201
- if (!('error' in result)) {
202
- assertEq(result.sliceId, 'S01', 'result sliceId');
203
- assertEq(result.milestoneId, 'M001', 'result milestoneId');
204
- assertTrue(result.summaryPath.endsWith('S01-SUMMARY.md'), 'summaryPath should end with S01-SUMMARY.md');
205
- assertTrue(result.uatPath.endsWith('S01-UAT.md'), 'uatPath should end with S01-UAT.md');
206
-
207
- // (a) Verify SUMMARY.md exists on disk with correct YAML frontmatter
208
- assertTrue(fs.existsSync(result.summaryPath), 'summary file should exist on disk');
209
- const summaryContent = fs.readFileSync(result.summaryPath, 'utf-8');
210
- assertMatch(summaryContent, /^---\n/, 'summary should start with YAML frontmatter');
211
- assertMatch(summaryContent, /id: S01/, 'summary should contain id: S01');
212
- assertMatch(summaryContent, /parent: M001/, 'summary should contain parent: M001');
213
- assertMatch(summaryContent, /milestone: M001/, 'summary should contain milestone: M001');
214
- assertMatch(summaryContent, /blocker_discovered: false/, 'summary should contain blocker_discovered');
215
- assertMatch(summaryContent, /verification_result: passed/, 'summary should contain verification_result');
216
- assertMatch(summaryContent, /key_files:/, 'summary should contain key_files');
217
- assertMatch(summaryContent, /patterns_established:/, 'summary should contain patterns_established');
218
- assertMatch(summaryContent, /observability_surfaces:/, 'summary should contain observability_surfaces');
219
- assertMatch(summaryContent, /provides:/, 'summary should contain provides');
220
- assertMatch(summaryContent, /# S01: Test Slice/, 'summary should have H1 with slice ID and title');
221
- assertMatch(summaryContent, /\*\*Implemented test slice with full coverage\*\*/, 'summary should have one-liner in bold');
222
- assertMatch(summaryContent, /## What Happened/, 'summary should have What Happened section');
223
- assertMatch(summaryContent, /## Verification/, 'summary should have Verification section');
224
- assertMatch(summaryContent, /## Requirements Advanced/, 'summary should have Requirements Advanced section');
225
-
226
- // (b) Verify UAT.md exists on disk
227
- assertTrue(fs.existsSync(result.uatPath), 'UAT file should exist on disk');
228
- const uatContent = fs.readFileSync(result.uatPath, 'utf-8');
229
- assertMatch(uatContent, /# S01: Test Slice — UAT/, 'UAT should have correct title');
230
- assertMatch(uatContent, /Milestone:\*\* M001/, 'UAT should reference milestone');
231
- assertMatch(uatContent, /Smoke Test/, 'UAT should contain smoke test from params');
232
-
233
- // (c) Verify roadmap checkbox toggled to [x]
234
- const roadmapContent = fs.readFileSync(roadmapPath, 'utf-8');
235
- assertMatch(roadmapContent, /\[x\]\s+\*\*S01:/, 'S01 should be checked in roadmap');
236
- assertMatch(roadmapContent, /\[ \]\s+\*\*S02:/, 'S02 should still be unchecked in roadmap');
237
-
238
- // (d) Verify full_summary_md and full_uat_md stored in DB for D004 recovery
239
- const sliceAfter = getSlice('M001', 'S01');
240
- assertTrue(sliceAfter !== null, 'slice should exist in DB after handler');
241
- assertTrue(sliceAfter!.full_summary_md.length > 0, 'full_summary_md should be non-empty in DB');
242
- assertMatch(sliceAfter!.full_summary_md, /id: S01/, 'full_summary_md should contain frontmatter');
243
- assertTrue(sliceAfter!.full_uat_md.length > 0, 'full_uat_md should be non-empty in DB');
244
- assertMatch(sliceAfter!.full_uat_md, /S01: Test Slice — UAT/, 'full_uat_md should contain UAT title');
245
-
246
- // (e) Verify slice status is complete in DB
247
- assertEq(sliceAfter!.status, 'complete', 'slice status should be complete in DB');
248
- assertTrue(sliceAfter!.completed_at !== null, 'completed_at should be set in DB');
249
- }
250
-
251
- cleanupDir(basePath);
252
- cleanup(dbPath);
253
- }
254
-
255
- // ═══════════════════════════════════════════════════════════════════════════
256
- // complete-slice: Handler rejects incomplete tasks
257
- // ═══════════════════════════════════════════════════════════════════════════
258
-
259
- console.log('\n=== complete-slice: handler rejects incomplete tasks ===');
260
- {
261
- const dbPath = tempDbPath();
262
- openDatabase(dbPath);
263
-
264
- // Insert milestone, slice, 2 tasks — one complete, one pending
265
- insertMilestone({ id: 'M001' });
266
- insertSlice({ id: 'S01', milestoneId: 'M001' });
267
- insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
268
- insertTask({ id: 'T02', sliceId: 'S01', milestoneId: 'M001', status: 'pending', title: 'Task 2' });
269
-
270
- const params = makeValidSliceParams();
271
- const result = await handleCompleteSlice(params, '/tmp/fake');
272
-
273
- assertTrue('error' in result, 'should return error when tasks are incomplete');
274
- if ('error' in result) {
275
- assertMatch(result.error, /incomplete tasks/, 'error should mention incomplete tasks');
276
- assertMatch(result.error, /T02/, 'error should mention the specific incomplete task ID');
277
- }
278
119
 
279
- cleanup(dbPath);
280
- }
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
+ }
281
243
 
282
- // ═══════════════════════════════════════════════════════════════════════════
283
- // complete-slice: Handler rejects no tasks
284
- // ═══════════════════════════════════════════════════════════════════════════
244
+ cleanupDir(basePath);
245
+ cleanup(dbPath);
246
+ });
285
247
 
286
- console.log('\n=== complete-slice: handler rejects no tasks ===');
287
- {
288
- const dbPath = tempDbPath();
289
- openDatabase(dbPath);
248
+ test("rejects incomplete tasks", async () => {
249
+ const dbPath = tempDbPath();
250
+ openDatabase(dbPath);
290
251
 
291
- // Insert milestone and slice but NO tasks
292
- insertMilestone({ id: 'M001' });
293
- insertSlice({ id: 'S01', milestoneId: 'M001' });
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' });
294
257
 
295
- const params = makeValidSliceParams();
296
- const result = await handleCompleteSlice(params, '/tmp/fake');
258
+ const params = makeValidSliceParams();
259
+ const result = await handleCompleteSlice(params, '/tmp/fake');
297
260
 
298
- assertTrue('error' in result, 'should return error when no tasks exist');
299
- if ('error' in result) {
300
- assertMatch(result.error, /no tasks found/, 'error should say no tasks found');
301
- }
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
+ }
302
266
 
303
- cleanup(dbPath);
304
- }
267
+ cleanup(dbPath);
268
+ });
305
269
 
306
- // ═══════════════════════════════════════════════════════════════════════════
307
- // complete-slice: Handler validation errors
308
- // ═══════════════════════════════════════════════════════════════════════════
270
+ test("rejects no tasks", async () => {
271
+ const dbPath = tempDbPath();
272
+ openDatabase(dbPath);
309
273
 
310
- console.log('\n=== complete-slice: handler validation errors ===');
311
- {
312
- const dbPath = tempDbPath();
313
- openDatabase(dbPath);
274
+ // Insert milestone and slice but NO tasks
275
+ insertMilestone({ id: 'M001' });
276
+ insertSlice({ id: 'S01', milestoneId: 'M001' });
314
277
 
315
- const params = makeValidSliceParams();
278
+ const params = makeValidSliceParams();
279
+ const result = await handleCompleteSlice(params, '/tmp/fake');
316
280
 
317
- // Empty sliceId
318
- const r1 = await handleCompleteSlice({ ...params, sliceId: '' }, '/tmp/fake');
319
- assertTrue('error' in r1, 'should return error for empty sliceId');
320
- if ('error' in r1) {
321
- assertMatch(r1.error, /sliceId/, 'error should mention sliceId');
322
- }
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
+ }
323
285
 
324
- // Empty milestoneId
325
- const r2 = await handleCompleteSlice({ ...params, milestoneId: '' }, '/tmp/fake');
326
- assertTrue('error' in r2, 'should return error for empty milestoneId');
327
- if ('error' in r2) {
328
- assertMatch(r2.error, /milestoneId/, 'error should mention milestoneId');
329
- }
286
+ cleanup(dbPath);
287
+ });
330
288
 
331
- cleanup(dbPath);
332
- }
289
+ test("validation errors", async () => {
290
+ const dbPath = tempDbPath();
291
+ openDatabase(dbPath);
333
292
 
334
- // ═══════════════════════════════════════════════════════════════════════════
335
- // complete-slice: Handler idempotency
336
- // ═══════════════════════════════════════════════════════════════════════════
293
+ const params = makeValidSliceParams();
337
294
 
338
- console.log('\n=== complete-slice: handler idempotency ===');
339
- {
340
- const dbPath = tempDbPath();
341
- openDatabase(dbPath);
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
+ }
342
301
 
343
- const { basePath, roadmapPath } = createTempProject();
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
+ }
344
308
 
345
- // Set up DB state
346
- insertMilestone({ id: 'M001' });
347
- insertSlice({ id: 'S01', milestoneId: 'M001' });
348
- insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
309
+ cleanup(dbPath);
310
+ });
349
311
 
350
- const params = makeValidSliceParams();
312
+ test("idempotency", async () => {
313
+ const dbPath = tempDbPath();
314
+ openDatabase(dbPath);
351
315
 
352
- // First call
353
- const r1 = await handleCompleteSlice(params, basePath);
354
- assertTrue(!('error' in r1), 'first call should succeed');
316
+ const { basePath, roadmapPath } = createTempProject();
355
317
 
356
- // Second call with same params — should not crash
357
- const r2 = await handleCompleteSlice(params, basePath);
358
- assertTrue(!('error' in r2), 'second call should succeed (idempotent)');
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' });
359
322
 
360
- // Verify only 1 slice row (not duplicated)
361
- const adapter = _getAdapter()!;
362
- const sliceRows = adapter.prepare("SELECT * FROM slices WHERE milestone_id = 'M001' AND id = 'S01'").all();
363
- assertEq(sliceRows.length, 1, 'should have exactly 1 slice row after 2 calls');
323
+ const params = makeValidSliceParams();
364
324
 
365
- // Files should still exist
366
- if (!('error' in r2)) {
367
- assertTrue(fs.existsSync(r2.summaryPath), 'summary should still exist after second call');
368
- assertTrue(fs.existsSync(r2.uatPath), 'UAT should still exist after second call');
369
- }
325
+ // First call
326
+ const r1 = await handleCompleteSlice(params, basePath);
327
+ assert.ok(!('error' in r1), 'first call should succeed');
370
328
 
371
- cleanupDir(basePath);
372
- cleanup(dbPath);
373
- }
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)');
374
332
 
375
- // ═══════════════════════════════════════════════════════════════════════════
376
- // complete-slice: Handler with missing roadmap (graceful)
377
- // ═══════════════════════════════════════════════════════════════════════════
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');
378
337
 
379
- console.log('\n=== complete-slice: handler with missing roadmap ===');
380
- {
381
- const dbPath = tempDbPath();
382
- openDatabase(dbPath);
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
+ }
383
343
 
384
- // Create a temp dir WITHOUT a roadmap file
385
- const basePath = fs.mkdtempSync(path.join(os.tmpdir(), 'gsd-no-roadmap-'));
386
- const sliceDir = path.join(basePath, '.gsd', 'milestones', 'M001', 'slices', 'S01');
387
- fs.mkdirSync(sliceDir, { recursive: true });
344
+ cleanupDir(basePath);
345
+ cleanup(dbPath);
346
+ });
388
347
 
389
- // Set up DB state
390
- insertMilestone({ id: 'M001' });
391
- insertSlice({ id: 'S01', milestoneId: 'M001' });
392
- insertTask({ id: 'T01', sliceId: 'S01', milestoneId: 'M001', status: 'complete', title: 'Task 1' });
348
+ test("missing roadmap (graceful)", async () => {
349
+ const dbPath = tempDbPath();
350
+ openDatabase(dbPath);
393
351
 
394
- const params = makeValidSliceParams();
395
- const result = await handleCompleteSlice(params, basePath);
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 });
396
356
 
397
- // Should succeed even without roadmap file — just skip checkbox toggle
398
- assertTrue(!('error' in result), 'handler should succeed without roadmap file');
399
- if (!('error' in result)) {
400
- assertTrue(fs.existsSync(result.summaryPath), 'summary should be written even without roadmap');
401
- assertTrue(fs.existsSync(result.uatPath), 'UAT should be written even without roadmap');
402
- }
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' });
403
361
 
404
- cleanupDir(basePath);
405
- cleanup(dbPath);
406
- }
362
+ const params = makeValidSliceParams();
363
+ const result = await handleCompleteSlice(params, basePath);
407
364
 
408
- // ═══════════════════════════════════════════════════════════════════════════
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
+ }
409
371
 
410
- report();
372
+ cleanupDir(basePath);
373
+ cleanup(dbPath);
374
+ });
375
+ });