gsd-pi 2.43.0 → 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 (693) 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/bg-shell/overlay.js +3 -0
  5. package/dist/resources/extensions/github-sync/sync.js +2 -1
  6. package/dist/resources/extensions/gsd/auto/loop.js +0 -2
  7. package/dist/resources/extensions/gsd/auto/phases.js +7 -12
  8. package/dist/resources/extensions/gsd/auto-dashboard.js +19 -18
  9. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +34 -19
  10. package/dist/resources/extensions/gsd/auto-dispatch.js +36 -21
  11. package/dist/resources/extensions/gsd/auto-post-unit.js +128 -14
  12. package/dist/resources/extensions/gsd/auto-prompts.js +202 -92
  13. package/dist/resources/extensions/gsd/auto-recovery.js +83 -135
  14. package/dist/resources/extensions/gsd/auto-start.js +10 -0
  15. package/dist/resources/extensions/gsd/auto-supervisor.js +14 -0
  16. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +4 -7
  17. package/dist/resources/extensions/gsd/auto-verification.js +5 -10
  18. package/dist/resources/extensions/gsd/auto-worktree.js +123 -30
  19. package/dist/resources/extensions/gsd/auto.js +1 -4
  20. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +611 -0
  21. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +28 -3
  22. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -0
  23. package/dist/resources/extensions/gsd/commands/catalog.js +3 -1
  24. package/dist/resources/extensions/gsd/commands/handlers/ops.js +15 -1
  25. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  26. package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
  27. package/dist/resources/extensions/gsd/commands-maintenance.js +78 -3
  28. package/dist/resources/extensions/gsd/dashboard-overlay.js +32 -31
  29. package/dist/resources/extensions/gsd/db-writer.js +95 -4
  30. package/dist/resources/extensions/gsd/dispatch-guard.js +35 -30
  31. package/dist/resources/extensions/gsd/doctor-checks.js +28 -11
  32. package/dist/resources/extensions/gsd/doctor-environment.js +28 -0
  33. package/dist/resources/extensions/gsd/doctor-types.js +0 -15
  34. package/dist/resources/extensions/gsd/doctor.js +46 -282
  35. package/dist/resources/extensions/gsd/file-watcher.js +5 -1
  36. package/dist/resources/extensions/gsd/files.js +14 -198
  37. package/dist/resources/extensions/gsd/git-service.js +4 -0
  38. package/dist/resources/extensions/gsd/gitignore.js +4 -0
  39. package/dist/resources/extensions/gsd/gsd-db.js +819 -197
  40. package/dist/resources/extensions/gsd/guided-flow.js +18 -8
  41. package/dist/resources/extensions/gsd/markdown-renderer.js +862 -0
  42. package/dist/resources/extensions/gsd/md-importer.js +182 -4
  43. package/dist/resources/extensions/gsd/native-git-bridge.js +10 -1
  44. package/dist/resources/extensions/gsd/parallel-eligibility.js +14 -19
  45. package/dist/resources/extensions/gsd/parallel-orchestrator.js +38 -0
  46. package/dist/resources/extensions/gsd/parsers-legacy.js +239 -0
  47. package/dist/resources/extensions/gsd/preferences-types.js +1 -0
  48. package/dist/resources/extensions/gsd/preferences-validation.js +9 -0
  49. package/dist/resources/extensions/gsd/preferences.js +1 -0
  50. package/dist/resources/extensions/gsd/prompts/complete-slice.md +22 -9
  51. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -2
  52. package/dist/resources/extensions/gsd/prompts/execute-task.md +15 -5
  53. package/dist/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  54. package/dist/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  55. package/dist/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  56. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +6 -10
  57. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -7
  58. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -3
  59. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -7
  60. package/dist/resources/extensions/gsd/prompts/replan-slice.md +6 -6
  61. package/dist/resources/extensions/gsd/reactive-graph.js +33 -3
  62. package/dist/resources/extensions/gsd/skill-health.js +3 -1
  63. package/dist/resources/extensions/gsd/state.js +484 -30
  64. package/dist/resources/extensions/gsd/tools/complete-milestone.js +128 -0
  65. package/dist/resources/extensions/gsd/tools/complete-slice.js +244 -0
  66. package/dist/resources/extensions/gsd/tools/complete-task.js +204 -0
  67. package/dist/resources/extensions/gsd/tools/plan-milestone.js +205 -0
  68. package/dist/resources/extensions/gsd/tools/plan-slice.js +155 -0
  69. package/dist/resources/extensions/gsd/tools/plan-task.js +94 -0
  70. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +152 -0
  71. package/dist/resources/extensions/gsd/tools/replan-slice.js +146 -0
  72. package/dist/resources/extensions/gsd/triage-resolution.js +17 -1
  73. package/dist/resources/extensions/gsd/undo.js +197 -3
  74. package/dist/resources/extensions/gsd/visualizer-data.js +53 -16
  75. package/dist/resources/extensions/gsd/workspace-index.js +63 -39
  76. package/dist/web/standalone/.next/BUILD_ID +1 -1
  77. package/dist/web/standalone/.next/app-path-routes-manifest.json +18 -17
  78. package/dist/web/standalone/.next/build-manifest.json +4 -4
  79. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  80. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  81. package/dist/web/standalone/.next/required-server-files.json +4 -4
  82. package/dist/web/standalone/.next/routes-manifest.json +6 -0
  83. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  84. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  86. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  91. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  92. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  94. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  96. package/dist/web/standalone/.next/server/app/_not-found.rsc +4 -4
  97. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +4 -4
  98. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  99. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  100. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  103. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  110. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  148. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  154. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -0
  166. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -0
  167. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -0
  168. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  171. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  173. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  175. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/index.html +1 -1
  185. package/dist/web/standalone/.next/server/app/index.rsc +5 -5
  186. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  187. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +5 -5
  188. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  189. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  190. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  191. package/dist/web/standalone/.next/server/app/page.js +2 -2
  192. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app-paths-manifest.json +18 -17
  194. package/dist/web/standalone/.next/server/chunks/229.js +3 -3
  195. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  196. package/dist/web/standalone/.next/server/functions-config-manifest.json +1 -0
  197. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  199. package/dist/web/standalone/.next/server/middleware.js +2 -2
  200. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  201. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  202. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  203. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  204. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  205. package/dist/web/standalone/.next/static/alS4hoANx0TK4UVZY27da/_buildManifest.js +1 -0
  206. package/dist/web/standalone/.next/static/chunks/{4024.c195dc1fdd2adbea.js → 4024.0de81b543b28b9fe.js} +2 -2
  207. package/dist/web/standalone/.next/static/chunks/app/_global-error/{page-d07a2c023f1aef1e.js → page-d83ba70a25a85472.js} +1 -1
  208. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
  209. package/dist/web/standalone/.next/static/chunks/app/api/boot/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
  210. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/input/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
  211. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/resize/{route-d07a2c023f1aef1e.js → route-d83ba70a25a85472.js} +1 -1
  212. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-d83ba70a25a85472.js +1 -0
  213. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-d83ba70a25a85472.js +1 -0
  214. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-d83ba70a25a85472.js +1 -0
  215. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-d83ba70a25a85472.js +1 -0
  216. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-d83ba70a25a85472.js +1 -0
  217. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-d83ba70a25a85472.js +1 -0
  218. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-d83ba70a25a85472.js +1 -0
  219. package/dist/web/standalone/.next/static/chunks/app/api/files/route-d83ba70a25a85472.js +1 -0
  220. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-d83ba70a25a85472.js +1 -0
  221. package/dist/web/standalone/.next/static/chunks/app/api/git/route-d83ba70a25a85472.js +1 -0
  222. package/dist/web/standalone/.next/static/chunks/app/api/history/route-d83ba70a25a85472.js +1 -0
  223. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-d83ba70a25a85472.js +1 -0
  224. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-d83ba70a25a85472.js +1 -0
  225. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-d83ba70a25a85472.js +1 -0
  226. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-d83ba70a25a85472.js +1 -0
  227. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-d83ba70a25a85472.js +1 -0
  228. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-d83ba70a25a85472.js +1 -0
  229. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-d83ba70a25a85472.js +1 -0
  230. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-d83ba70a25a85472.js +1 -0
  231. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-d83ba70a25a85472.js +1 -0
  232. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-d83ba70a25a85472.js +1 -0
  233. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-d83ba70a25a85472.js +1 -0
  234. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-d83ba70a25a85472.js +1 -0
  235. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-d83ba70a25a85472.js +1 -0
  236. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-d83ba70a25a85472.js +1 -0
  237. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-d83ba70a25a85472.js +1 -0
  238. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-d83ba70a25a85472.js +1 -0
  239. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-d83ba70a25a85472.js +1 -0
  240. package/dist/web/standalone/.next/static/chunks/app/api/switch-root/route-d83ba70a25a85472.js +1 -0
  241. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-d83ba70a25a85472.js +1 -0
  242. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-d83ba70a25a85472.js +1 -0
  243. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-d83ba70a25a85472.js +1 -0
  244. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-d83ba70a25a85472.js +1 -0
  245. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-d83ba70a25a85472.js +1 -0
  246. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-d83ba70a25a85472.js +1 -0
  247. package/dist/web/standalone/.next/static/chunks/app/api/update/route-d83ba70a25a85472.js +1 -0
  248. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-d83ba70a25a85472.js +1 -0
  249. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
  250. package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
  251. package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
  252. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d83ba70a25a85472.js +1 -0
  253. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d83ba70a25a85472.js +1 -0
  254. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  255. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d83ba70a25a85472.js +1 -0
  256. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d83ba70a25a85472.js +1 -0
  257. package/dist/web/standalone/.next/static/chunks/{webpack-fa307370fcf9fb2c.js → webpack-9014b5adb127a98a.js} +1 -1
  258. package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +1 -0
  259. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  260. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  261. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  262. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  263. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  264. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  265. package/dist/web/standalone/server.js +1 -1
  266. package/package.json +4 -4
  267. package/packages/pi-ai/dist/models.custom.d.ts +173 -0
  268. package/packages/pi-ai/dist/models.custom.d.ts.map +1 -0
  269. package/packages/pi-ai/dist/models.custom.js +170 -0
  270. package/packages/pi-ai/dist/models.custom.js.map +1 -0
  271. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  272. package/packages/pi-ai/dist/models.js +16 -1
  273. package/packages/pi-ai/dist/models.js.map +1 -1
  274. package/packages/pi-ai/dist/models.test.d.ts +2 -0
  275. package/packages/pi-ai/dist/models.test.d.ts.map +1 -0
  276. package/packages/pi-ai/dist/models.test.js +67 -0
  277. package/packages/pi-ai/dist/models.test.js.map +1 -0
  278. package/packages/pi-ai/src/models.custom.ts +172 -0
  279. package/packages/pi-ai/src/models.test.ts +85 -0
  280. package/packages/pi-ai/src/models.ts +17 -1
  281. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +10 -3
  282. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/agent-session.js +21 -34
  284. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  286. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts +2 -2
  288. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
  290. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +2 -2
  291. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  292. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  293. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +4 -4
  294. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  295. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  296. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  297. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  298. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts +6 -0
  299. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  300. package/packages/pi-coding-agent/dist/core/extensions/loader.js +80 -0
  301. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  302. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js +63 -0
  303. package/packages/pi-coding-agent/dist/core/extensions/loader.test.js.map +1 -1
  304. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  305. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  306. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +37 -0
  307. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  308. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  309. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -1
  310. package/packages/pi-coding-agent/dist/core/fallback-resolver.js +2 -3
  311. package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -1
  312. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +12 -2
  313. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -1
  314. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  315. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  316. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +38 -0
  317. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -0
  318. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +192 -0
  319. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -0
  320. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts +5 -0
  321. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  322. package/packages/pi-coding-agent/dist/core/lsp/client.js +69 -21
  323. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  324. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts +2 -0
  325. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts.map +1 -0
  326. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +255 -0
  327. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -0
  328. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +15 -0
  329. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  330. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  331. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  332. package/packages/pi-coding-agent/dist/core/package-commands.d.ts +25 -0
  333. package/packages/pi-coding-agent/dist/core/package-commands.d.ts.map +1 -0
  334. package/packages/pi-coding-agent/dist/core/package-commands.js +253 -0
  335. package/packages/pi-coding-agent/dist/core/package-commands.js.map +1 -0
  336. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts +2 -0
  337. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts.map +1 -0
  338. package/packages/pi-coding-agent/dist/core/package-commands.test.js +225 -0
  339. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -0
  340. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  341. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  342. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  343. package/packages/pi-coding-agent/dist/core/sdk.js +4 -0
  344. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  345. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  346. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  347. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  348. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  349. package/packages/pi-coding-agent/dist/index.d.ts +3 -1
  350. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  351. package/packages/pi-coding-agent/dist/index.js +1 -0
  352. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  353. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  354. package/packages/pi-coding-agent/dist/main.js +11 -199
  355. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  356. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts +6 -0
  357. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  358. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +21 -0
  359. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  360. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts +1 -1
  361. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  362. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js +8 -15
  363. package/packages/pi-coding-agent/dist/modes/interactive/theme/theme.js.map +1 -1
  364. package/packages/pi-coding-agent/dist/modes/print-mode.d.ts.map +1 -1
  365. package/packages/pi-coding-agent/dist/modes/print-mode.js +45 -34
  366. package/packages/pi-coding-agent/dist/modes/print-mode.js.map +1 -1
  367. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts +1 -0
  368. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  369. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js +7 -2
  370. package/packages/pi-coding-agent/dist/modes/rpc/rpc-client.js.map +1 -1
  371. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  372. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js +2 -1
  373. package/packages/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
  374. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  375. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  376. package/packages/pi-coding-agent/package.json +1 -1
  377. package/packages/pi-coding-agent/src/core/agent-session.ts +26 -37
  378. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  379. package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +2 -2
  380. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +3 -3
  381. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +4 -4
  382. package/packages/pi-coding-agent/src/core/extensions/index.ts +5 -0
  383. package/packages/pi-coding-agent/src/core/extensions/loader.test.ts +96 -0
  384. package/packages/pi-coding-agent/src/core/extensions/loader.ts +89 -0
  385. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  386. package/packages/pi-coding-agent/src/core/extensions/types.ts +44 -0
  387. package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +15 -2
  388. package/packages/pi-coding-agent/src/core/fallback-resolver.ts +2 -3
  389. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  390. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +274 -0
  391. package/packages/pi-coding-agent/src/core/lsp/client.ts +83 -21
  392. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +288 -0
  393. package/packages/pi-coding-agent/src/core/model-registry.ts +39 -3
  394. package/packages/pi-coding-agent/src/core/package-commands.test.ts +240 -0
  395. package/packages/pi-coding-agent/src/core/package-commands.ts +310 -0
  396. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  397. package/packages/pi-coding-agent/src/core/sdk.ts +4 -0
  398. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  399. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  400. package/packages/pi-coding-agent/src/index.ts +7 -0
  401. package/packages/pi-coding-agent/src/main.ts +11 -232
  402. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +20 -0
  403. package/packages/pi-coding-agent/src/modes/interactive/theme/theme.ts +9 -16
  404. package/packages/pi-coding-agent/src/modes/print-mode.ts +42 -32
  405. package/packages/pi-coding-agent/src/modes/rpc/rpc-client.ts +8 -2
  406. package/packages/pi-coding-agent/src/modes/rpc/rpc-mode.ts +2 -1
  407. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  408. package/pkg/dist/modes/interactive/theme/theme.d.ts +1 -1
  409. package/pkg/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  410. package/pkg/dist/modes/interactive/theme/theme.js +8 -15
  411. package/pkg/dist/modes/interactive/theme/theme.js.map +1 -1
  412. package/pkg/package.json +1 -1
  413. package/src/resources/extensions/bg-shell/overlay.ts +4 -0
  414. package/src/resources/extensions/github-sync/sync.ts +2 -1
  415. package/src/resources/extensions/gsd/auto/loop-deps.ts +0 -8
  416. package/src/resources/extensions/gsd/auto/loop.ts +0 -2
  417. package/src/resources/extensions/gsd/auto/phases.ts +7 -20
  418. package/src/resources/extensions/gsd/auto/types.ts +0 -1
  419. package/src/resources/extensions/gsd/auto-dashboard.ts +20 -16
  420. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +34 -19
  421. package/src/resources/extensions/gsd/auto-dispatch.ts +38 -21
  422. package/src/resources/extensions/gsd/auto-post-unit.ts +150 -15
  423. package/src/resources/extensions/gsd/auto-prompts.ts +186 -103
  424. package/src/resources/extensions/gsd/auto-recovery.ts +77 -142
  425. package/src/resources/extensions/gsd/auto-start.ts +14 -0
  426. package/src/resources/extensions/gsd/auto-supervisor.ts +14 -0
  427. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +6 -7
  428. package/src/resources/extensions/gsd/auto-verification.ts +4 -9
  429. package/src/resources/extensions/gsd/auto-worktree.ts +126 -30
  430. package/src/resources/extensions/gsd/auto.ts +0 -9
  431. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +675 -4
  432. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +31 -3
  433. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +7 -0
  434. package/src/resources/extensions/gsd/commands/catalog.ts +3 -1
  435. package/src/resources/extensions/gsd/commands/handlers/ops.ts +15 -1
  436. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  437. package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
  438. package/src/resources/extensions/gsd/commands-maintenance.ts +86 -3
  439. package/src/resources/extensions/gsd/dashboard-overlay.ts +17 -13
  440. package/src/resources/extensions/gsd/db-writer.ts +105 -4
  441. package/src/resources/extensions/gsd/dispatch-guard.ts +32 -30
  442. package/src/resources/extensions/gsd/doctor-checks.ts +25 -11
  443. package/src/resources/extensions/gsd/doctor-environment.ts +31 -0
  444. package/src/resources/extensions/gsd/doctor-types.ts +0 -23
  445. package/src/resources/extensions/gsd/doctor.ts +45 -295
  446. package/src/resources/extensions/gsd/file-watcher.ts +4 -1
  447. package/src/resources/extensions/gsd/files.ts +16 -220
  448. package/src/resources/extensions/gsd/git-service.ts +4 -0
  449. package/src/resources/extensions/gsd/gitignore.ts +4 -0
  450. package/src/resources/extensions/gsd/gsd-db.ts +1157 -370
  451. package/src/resources/extensions/gsd/guided-flow.ts +20 -8
  452. package/src/resources/extensions/gsd/markdown-renderer.ts +1098 -0
  453. package/src/resources/extensions/gsd/md-importer.ts +211 -2
  454. package/src/resources/extensions/gsd/native-git-bridge.ts +12 -1
  455. package/src/resources/extensions/gsd/parallel-eligibility.ts +14 -18
  456. package/src/resources/extensions/gsd/parallel-orchestrator.ts +43 -0
  457. package/src/resources/extensions/gsd/parsers-legacy.ts +271 -0
  458. package/src/resources/extensions/gsd/preferences-types.ts +3 -0
  459. package/src/resources/extensions/gsd/preferences-validation.ts +9 -0
  460. package/src/resources/extensions/gsd/preferences.ts +1 -0
  461. package/src/resources/extensions/gsd/prompts/complete-slice.md +22 -9
  462. package/src/resources/extensions/gsd/prompts/discuss.md +2 -2
  463. package/src/resources/extensions/gsd/prompts/execute-task.md +15 -5
  464. package/src/resources/extensions/gsd/prompts/guided-complete-slice.md +1 -1
  465. package/src/resources/extensions/gsd/prompts/guided-execute-task.md +1 -1
  466. package/src/resources/extensions/gsd/prompts/guided-plan-milestone.md +1 -1
  467. package/src/resources/extensions/gsd/prompts/plan-milestone.md +6 -10
  468. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -7
  469. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -3
  470. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -7
  471. package/src/resources/extensions/gsd/prompts/replan-slice.md +6 -6
  472. package/src/resources/extensions/gsd/reactive-graph.ts +33 -3
  473. package/src/resources/extensions/gsd/skill-health.ts +2 -1
  474. package/src/resources/extensions/gsd/state.ts +547 -29
  475. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  476. package/src/resources/extensions/gsd/tests/atomic-task-closeout.test.ts +8 -120
  477. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  478. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +20 -11
  479. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  480. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  481. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +600 -513
  482. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  483. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  484. package/src/resources/extensions/gsd/tests/auto-stash-merge.test.ts +121 -0
  485. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +540 -668
  486. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  487. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  488. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  489. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  490. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  491. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  492. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  493. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +39 -60
  494. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +375 -0
  495. package/src/resources/extensions/gsd/tests/complete-task.test.ts +387 -0
  496. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  497. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  498. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  499. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  500. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +0 -2
  501. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  502. package/src/resources/extensions/gsd/tests/db-writer.test.ts +390 -420
  503. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  504. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +512 -0
  505. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +644 -84
  506. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  507. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  508. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  509. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  510. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +192 -161
  511. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  512. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  513. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +30 -90
  514. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  515. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +57 -80
  516. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +164 -0
  517. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  518. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +55 -153
  519. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  520. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  521. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +53 -97
  522. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  523. package/src/resources/extensions/gsd/tests/doctor.test.ts +109 -149
  524. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  525. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  526. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  527. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  528. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +278 -0
  529. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +232 -0
  530. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  531. package/src/resources/extensions/gsd/tests/git-service.test.ts +291 -390
  532. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  533. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  534. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  535. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  536. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +440 -0
  537. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  538. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  539. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  540. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -270
  541. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  542. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  543. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  544. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  545. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +643 -0
  546. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +0 -3
  547. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +1161 -0
  548. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  549. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  550. package/src/resources/extensions/gsd/tests/memory-store.test.ts +81 -94
  551. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  552. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +429 -0
  553. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  554. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  555. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  556. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +89 -97
  557. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +127 -164
  558. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  559. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
  560. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  561. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  562. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  563. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  564. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  565. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  566. package/src/resources/extensions/gsd/tests/parsers.test.ts +548 -612
  567. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  568. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +176 -113
  569. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +7 -0
  570. package/src/resources/extensions/gsd/tests/plan-slice.test.ts +179 -0
  571. package/src/resources/extensions/gsd/tests/plan-task.test.ts +145 -0
  572. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +305 -0
  573. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  574. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +139 -0
  575. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  576. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  577. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  578. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  579. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  580. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  581. package/src/resources/extensions/gsd/tests/reassess-handler.test.ts +325 -0
  582. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  583. package/src/resources/extensions/gsd/tests/replan-handler.test.ts +410 -0
  584. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  585. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  586. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  587. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  588. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  589. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +1 -1
  590. package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +296 -0
  591. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  592. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  593. package/src/resources/extensions/gsd/tests/schema-v9-sequence.test.ts +176 -0
  594. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  595. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  596. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +209 -0
  597. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  598. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  599. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  600. package/src/resources/extensions/gsd/tests/token-cost-display.test.ts +118 -0
  601. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  602. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  603. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +19 -13
  604. package/src/resources/extensions/gsd/tests/undo.test.ts +321 -1
  605. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  606. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  607. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +1 -1
  608. package/src/resources/extensions/gsd/tests/verification-evidence.test.ts +0 -142
  609. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  610. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  611. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  612. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  613. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  614. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  615. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  616. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  617. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  618. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  619. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  620. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +12 -5
  621. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  622. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  623. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  624. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  625. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  626. package/src/resources/extensions/gsd/tools/complete-milestone.ts +176 -0
  627. package/src/resources/extensions/gsd/tools/complete-slice.ts +300 -0
  628. package/src/resources/extensions/gsd/tools/complete-task.ts +245 -0
  629. package/src/resources/extensions/gsd/tools/plan-milestone.ts +249 -0
  630. package/src/resources/extensions/gsd/tools/plan-slice.ts +194 -0
  631. package/src/resources/extensions/gsd/tools/plan-task.ts +116 -0
  632. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +203 -0
  633. package/src/resources/extensions/gsd/tools/replan-slice.ts +192 -0
  634. package/src/resources/extensions/gsd/triage-resolution.ts +20 -1
  635. package/src/resources/extensions/gsd/types.ts +50 -0
  636. package/src/resources/extensions/gsd/undo.ts +247 -3
  637. package/src/resources/extensions/gsd/visualizer-data.ts +54 -17
  638. package/src/resources/extensions/gsd/workspace-index.ts +64 -46
  639. package/dist/resources/extensions/gsd/auto-observability.js +0 -56
  640. package/dist/resources/extensions/gsd/observability-validator.js +0 -422
  641. package/dist/resources/extensions/gsd/roadmap-mutations.js +0 -110
  642. package/dist/web/standalone/.next/static/VvclDCW6TAWjEyLU-EYL1/_buildManifest.js +0 -1
  643. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
  644. package/dist/web/standalone/.next/static/chunks/app/api/bridge-terminal/stream/route-d07a2c023f1aef1e.js +0 -1
  645. package/dist/web/standalone/.next/static/chunks/app/api/browse-directories/route-d07a2c023f1aef1e.js +0 -1
  646. package/dist/web/standalone/.next/static/chunks/app/api/captures/route-d07a2c023f1aef1e.js +0 -1
  647. package/dist/web/standalone/.next/static/chunks/app/api/cleanup/route-d07a2c023f1aef1e.js +0 -1
  648. package/dist/web/standalone/.next/static/chunks/app/api/dev-mode/route-d07a2c023f1aef1e.js +0 -1
  649. package/dist/web/standalone/.next/static/chunks/app/api/doctor/route-d07a2c023f1aef1e.js +0 -1
  650. package/dist/web/standalone/.next/static/chunks/app/api/export-data/route-d07a2c023f1aef1e.js +0 -1
  651. package/dist/web/standalone/.next/static/chunks/app/api/files/route-d07a2c023f1aef1e.js +0 -1
  652. package/dist/web/standalone/.next/static/chunks/app/api/forensics/route-d07a2c023f1aef1e.js +0 -1
  653. package/dist/web/standalone/.next/static/chunks/app/api/git/route-d07a2c023f1aef1e.js +0 -1
  654. package/dist/web/standalone/.next/static/chunks/app/api/history/route-d07a2c023f1aef1e.js +0 -1
  655. package/dist/web/standalone/.next/static/chunks/app/api/hooks/route-d07a2c023f1aef1e.js +0 -1
  656. package/dist/web/standalone/.next/static/chunks/app/api/inspect/route-d07a2c023f1aef1e.js +0 -1
  657. package/dist/web/standalone/.next/static/chunks/app/api/knowledge/route-d07a2c023f1aef1e.js +0 -1
  658. package/dist/web/standalone/.next/static/chunks/app/api/live-state/route-d07a2c023f1aef1e.js +0 -1
  659. package/dist/web/standalone/.next/static/chunks/app/api/onboarding/route-d07a2c023f1aef1e.js +0 -1
  660. package/dist/web/standalone/.next/static/chunks/app/api/preferences/route-d07a2c023f1aef1e.js +0 -1
  661. package/dist/web/standalone/.next/static/chunks/app/api/projects/route-d07a2c023f1aef1e.js +0 -1
  662. package/dist/web/standalone/.next/static/chunks/app/api/recovery/route-d07a2c023f1aef1e.js +0 -1
  663. package/dist/web/standalone/.next/static/chunks/app/api/remote-questions/route-d07a2c023f1aef1e.js +0 -1
  664. package/dist/web/standalone/.next/static/chunks/app/api/session/browser/route-d07a2c023f1aef1e.js +0 -1
  665. package/dist/web/standalone/.next/static/chunks/app/api/session/command/route-d07a2c023f1aef1e.js +0 -1
  666. package/dist/web/standalone/.next/static/chunks/app/api/session/events/route-d07a2c023f1aef1e.js +0 -1
  667. package/dist/web/standalone/.next/static/chunks/app/api/session/manage/route-d07a2c023f1aef1e.js +0 -1
  668. package/dist/web/standalone/.next/static/chunks/app/api/settings-data/route-d07a2c023f1aef1e.js +0 -1
  669. package/dist/web/standalone/.next/static/chunks/app/api/shutdown/route-d07a2c023f1aef1e.js +0 -1
  670. package/dist/web/standalone/.next/static/chunks/app/api/skill-health/route-d07a2c023f1aef1e.js +0 -1
  671. package/dist/web/standalone/.next/static/chunks/app/api/steer/route-d07a2c023f1aef1e.js +0 -1
  672. package/dist/web/standalone/.next/static/chunks/app/api/terminal/input/route-d07a2c023f1aef1e.js +0 -1
  673. package/dist/web/standalone/.next/static/chunks/app/api/terminal/resize/route-d07a2c023f1aef1e.js +0 -1
  674. package/dist/web/standalone/.next/static/chunks/app/api/terminal/sessions/route-d07a2c023f1aef1e.js +0 -1
  675. package/dist/web/standalone/.next/static/chunks/app/api/terminal/stream/route-d07a2c023f1aef1e.js +0 -1
  676. package/dist/web/standalone/.next/static/chunks/app/api/terminal/upload/route-d07a2c023f1aef1e.js +0 -1
  677. package/dist/web/standalone/.next/static/chunks/app/api/undo/route-d07a2c023f1aef1e.js +0 -1
  678. package/dist/web/standalone/.next/static/chunks/app/api/update/route-d07a2c023f1aef1e.js +0 -1
  679. package/dist/web/standalone/.next/static/chunks/app/api/visualizer/route-d07a2c023f1aef1e.js +0 -1
  680. package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
  681. package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
  682. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-d07a2c023f1aef1e.js +0 -1
  683. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-d07a2c023f1aef1e.js +0 -1
  684. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
  685. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-d07a2c023f1aef1e.js +0 -1
  686. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-d07a2c023f1aef1e.js +0 -1
  687. package/dist/web/standalone/.next/static/css/123c0bb039697968.css +0 -1
  688. package/src/resources/extensions/gsd/auto-observability.ts +0 -74
  689. package/src/resources/extensions/gsd/observability-validator.ts +0 -456
  690. package/src/resources/extensions/gsd/roadmap-mutations.ts +0 -134
  691. package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +0 -174
  692. package/src/resources/extensions/gsd/tests/plan-quality-validator.test.ts +0 -474
  693. /package/dist/web/standalone/.next/static/{VvclDCW6TAWjEyLU-EYL1 → alS4hoANx0TK4UVZY27da}/_ssgManifest.js +0 -0
@@ -1,3 +1,5 @@
1
+ import { describe, test } from 'node:test';
2
+ import assert from 'node:assert/strict';
1
3
  import { mkdtempSync, mkdirSync, writeFileSync, rmSync, existsSync, symlinkSync } from "node:fs";
2
4
  import { join, dirname } from "node:path";
3
5
  import { tmpdir } from "node:os";
@@ -20,174 +22,170 @@ import {
20
22
  type TaskCommitContext,
21
23
  } from "../git-service.ts";
22
24
  import { nativeAddAllWithExclusions } from "../native-git-bridge.ts";
23
- import { createTestContext } from './test-helpers.ts';
24
-
25
- const { assertEq, assertTrue, report } = createTestContext();
26
25
  function run(command: string, cwd: string): string {
27
26
  return execSync(command, { cwd, stdio: ["ignore", "pipe", "pipe"], encoding: "utf-8" }).trim();
28
27
  }
29
28
 
30
- async function main(): Promise<void> {
29
+ describe('git-service', async () => {
31
30
  // ─── inferCommitType ───────────────────────────────────────────────────
32
31
 
33
- console.log("\n=== inferCommitType ===");
34
32
 
35
- assertEq(
33
+ assert.deepStrictEqual(
36
34
  inferCommitType("Implement user authentication"),
37
35
  "feat",
38
36
  "generic feature title → feat"
39
37
  );
40
38
 
41
- assertEq(
39
+ assert.deepStrictEqual(
42
40
  inferCommitType("Add dashboard page"),
43
41
  "feat",
44
42
  "add-style title → feat"
45
43
  );
46
44
 
47
- assertEq(
45
+ assert.deepStrictEqual(
48
46
  inferCommitType("Fix login redirect bug"),
49
47
  "fix",
50
48
  "title with 'fix' → fix"
51
49
  );
52
50
 
53
- assertEq(
51
+ assert.deepStrictEqual(
54
52
  inferCommitType("Bug in session handling"),
55
53
  "fix",
56
54
  "title with 'bug' → fix"
57
55
  );
58
56
 
59
- assertEq(
57
+ assert.deepStrictEqual(
60
58
  inferCommitType("Hotfix for production crash"),
61
59
  "fix",
62
60
  "title with 'hotfix' → fix"
63
61
  );
64
62
 
65
- assertEq(
63
+ assert.deepStrictEqual(
66
64
  inferCommitType("Patch memory leak"),
67
65
  "fix",
68
66
  "title with 'patch' → fix"
69
67
  );
70
68
 
71
- assertEq(
69
+ assert.deepStrictEqual(
72
70
  inferCommitType("Refactor state management"),
73
71
  "refactor",
74
72
  "title with 'refactor' → refactor"
75
73
  );
76
74
 
77
- assertEq(
75
+ assert.deepStrictEqual(
78
76
  inferCommitType("Restructure project layout"),
79
77
  "refactor",
80
78
  "title with 'restructure' → refactor"
81
79
  );
82
80
 
83
- assertEq(
81
+ assert.deepStrictEqual(
84
82
  inferCommitType("Reorganize module imports"),
85
83
  "refactor",
86
84
  "title with 'reorganize' → refactor"
87
85
  );
88
86
 
89
- assertEq(
87
+ assert.deepStrictEqual(
90
88
  inferCommitType("Update API documentation"),
91
89
  "docs",
92
90
  "title with 'documentation' → docs"
93
91
  );
94
92
 
95
- assertEq(
93
+ assert.deepStrictEqual(
96
94
  inferCommitType("Add doc for setup guide"),
97
95
  "docs",
98
96
  "title with 'doc' → docs"
99
97
  );
100
98
 
101
- assertEq(
99
+ assert.deepStrictEqual(
102
100
  inferCommitType("Add unit tests for auth"),
103
101
  "test",
104
102
  "title with 'tests' → test"
105
103
  );
106
104
 
107
- assertEq(
105
+ assert.deepStrictEqual(
108
106
  inferCommitType("Testing infrastructure setup"),
109
107
  "test",
110
108
  "title with 'testing' → test"
111
109
  );
112
110
 
113
- assertEq(
111
+ assert.deepStrictEqual(
114
112
  inferCommitType("Chore: update dependencies"),
115
113
  "chore",
116
114
  "title with 'chore' → chore"
117
115
  );
118
116
 
119
- assertEq(
117
+ assert.deepStrictEqual(
120
118
  inferCommitType("Cleanup unused imports"),
121
119
  "chore",
122
120
  "title with 'cleanup' → chore"
123
121
  );
124
122
 
125
- assertEq(
123
+ assert.deepStrictEqual(
126
124
  inferCommitType("Clean up stale branches"),
127
125
  "chore",
128
126
  "title with 'clean up' → chore"
129
127
  );
130
128
 
131
- assertEq(
129
+ assert.deepStrictEqual(
132
130
  inferCommitType("Archive old milestones"),
133
131
  "chore",
134
132
  "title with 'archive' → chore"
135
133
  );
136
134
 
137
- assertEq(
135
+ assert.deepStrictEqual(
138
136
  inferCommitType("Remove deprecated endpoints"),
139
137
  "chore",
140
138
  "title with 'remove' → chore"
141
139
  );
142
140
 
143
- assertEq(
141
+ assert.deepStrictEqual(
144
142
  inferCommitType("Delete temp files"),
145
143
  "chore",
146
144
  "title with 'delete' → chore"
147
145
  );
148
146
 
149
147
  // Mixed keywords — first match wins
150
- assertEq(
148
+ assert.deepStrictEqual(
151
149
  inferCommitType("Fix and refactor the login module"),
152
150
  "fix",
153
151
  "mixed keywords → first match wins (fix before refactor)"
154
152
  );
155
153
 
156
- assertEq(
154
+ assert.deepStrictEqual(
157
155
  inferCommitType("Refactor test utilities"),
158
156
  "refactor",
159
157
  "mixed keywords → first match wins (refactor before test)"
160
158
  );
161
159
 
162
160
  // Unknown / unrecognized title → feat
163
- assertEq(
161
+ assert.deepStrictEqual(
164
162
  inferCommitType("Build the new pipeline"),
165
163
  "feat",
166
164
  "unrecognized title → feat"
167
165
  );
168
166
 
169
- assertEq(
167
+ assert.deepStrictEqual(
170
168
  inferCommitType(""),
171
169
  "feat",
172
170
  "empty title → feat"
173
171
  );
174
172
 
175
173
  // Word boundary: "testify" should NOT match "test"
176
- assertEq(
174
+ assert.deepStrictEqual(
177
175
  inferCommitType("Testify integration"),
178
176
  "feat",
179
177
  "'testify' does not match 'test' — word boundary prevents partial match"
180
178
  );
181
179
 
182
180
  // "documentary" should NOT match "doc" (word boundary)
183
- assertEq(
181
+ assert.deepStrictEqual(
184
182
  inferCommitType("Documentary style UI"),
185
183
  "feat",
186
184
  "'documentary' does not match 'doc' — word boundary prevents partial match"
187
185
  );
188
186
 
189
187
  // "prefix" should NOT match "fix" (word boundary)
190
- assertEq(
188
+ assert.deepStrictEqual(
191
189
  inferCommitType("Add prefix to all IDs"),
192
190
  "feat",
193
191
  "'prefix' does not match 'fix' — word boundary prevents partial match"
@@ -195,15 +193,14 @@ async function main(): Promise<void> {
195
193
 
196
194
  // ─── inferCommitType with oneLiner ──────────────────────────────────────
197
195
 
198
- console.log("\n=== inferCommitType with oneLiner ===");
199
196
 
200
- assertEq(
197
+ assert.deepStrictEqual(
201
198
  inferCommitType("implement dashboard", "Fixed rendering bug in sidebar"),
202
199
  "fix",
203
200
  "one-liner with 'fixed' overrides generic title → fix"
204
201
  );
205
202
 
206
- assertEq(
203
+ assert.deepStrictEqual(
207
204
  inferCommitType("add search", "Optimized query performance with caching"),
208
205
  "perf",
209
206
  "one-liner with 'performance' and 'caching' → perf"
@@ -211,29 +208,27 @@ async function main(): Promise<void> {
211
208
 
212
209
  // ─── buildTaskCommitMessage ─────────────────────────────────────────────
213
210
 
214
- console.log("\n=== buildTaskCommitMessage ===");
215
-
216
- {
211
+ test('buildTaskCommitMessage', () => {
217
212
  const msg = buildTaskCommitMessage({
218
213
  taskId: "S01/T02",
219
214
  taskTitle: "implement user authentication",
220
215
  oneLiner: "Added JWT-based auth with refresh token rotation",
221
216
  keyFiles: ["src/auth.ts", "src/middleware/jwt.ts"],
222
217
  });
223
- assertTrue(msg.startsWith("feat(S01/T02):"), "message starts with type(scope)");
224
- assertTrue(msg.includes("JWT-based auth"), "message includes one-liner content");
225
- assertTrue(msg.includes("- src/auth.ts"), "message body includes key files");
226
- assertTrue(msg.includes("- src/middleware/jwt.ts"), "message body includes second key file");
227
- }
218
+ assert.ok(msg.startsWith("feat(S01/T02):"), "message starts with type(scope)");
219
+ assert.ok(msg.includes("JWT-based auth"), "message includes one-liner content");
220
+ assert.ok(msg.includes("- src/auth.ts"), "message body includes key files");
221
+ assert.ok(msg.includes("- src/middleware/jwt.ts"), "message body includes second key file");
222
+ });
228
223
 
229
224
  {
230
225
  const msg = buildTaskCommitMessage({
231
226
  taskId: "S02/T01",
232
227
  taskTitle: "fix login redirect bug",
233
228
  });
234
- assertTrue(msg.startsWith("fix(S02/T01):"), "infers fix type from title");
235
- assertTrue(msg.includes("fix login redirect bug"), "uses task title when no one-liner");
236
- assertTrue(!msg.includes("\n"), "no body when no key files");
229
+ assert.ok(msg.startsWith("fix(S02/T01):"), "infers fix type from title");
230
+ assert.ok(msg.includes("fix login redirect bug"), "uses task title when no one-liner");
231
+ assert.ok(!msg.includes("\n"), "no body when no key files");
237
232
  }
238
233
 
239
234
  {
@@ -242,17 +237,16 @@ async function main(): Promise<void> {
242
237
  taskTitle: "add tests",
243
238
  oneLiner: "Unit tests for auth module with coverage",
244
239
  });
245
- assertTrue(msg.startsWith("test(S01/T03):"), "infers test type");
240
+ assert.ok(msg.startsWith("test(S01/T03):"), "infers test type");
246
241
  }
247
242
 
248
243
  // ─── RUNTIME_EXCLUSION_PATHS ───────────────────────────────────────────
249
244
 
250
- console.log("\n=== RUNTIME_EXCLUSION_PATHS ===");
251
245
 
252
- assertEq(
246
+ assert.deepStrictEqual(
253
247
  RUNTIME_EXCLUSION_PATHS.length,
254
- 9,
255
- "exactly 9 runtime exclusion paths"
248
+ 13,
249
+ "exactly 13 runtime exclusion paths"
256
250
  );
257
251
 
258
252
  const expectedPaths = [
@@ -264,27 +258,30 @@ async function main(): Promise<void> {
264
258
  ".gsd/completed-units.json",
265
259
  ".gsd/STATE.md",
266
260
  ".gsd/gsd.db",
261
+ ".gsd/gsd.db-shm",
262
+ ".gsd/gsd.db-wal",
263
+ ".gsd/journal/",
264
+ ".gsd/doctor-history.jsonl",
267
265
  ".gsd/DISCUSSION-MANIFEST.json",
268
266
  ];
269
267
 
270
- assertEq(
268
+ assert.deepStrictEqual(
271
269
  [...RUNTIME_EXCLUSION_PATHS],
272
270
  expectedPaths,
273
271
  "paths match expected set in order"
274
272
  );
275
273
 
276
- assertTrue(
274
+ assert.ok(
277
275
  RUNTIME_EXCLUSION_PATHS.includes(".gsd/activity/"),
278
276
  "includes .gsd/activity/"
279
277
  );
280
- assertTrue(
278
+ assert.ok(
281
279
  RUNTIME_EXCLUSION_PATHS.includes(".gsd/STATE.md"),
282
280
  "includes .gsd/STATE.md"
283
281
  );
284
282
 
285
283
  // ─── runGit ────────────────────────────────────────────────────────────
286
284
 
287
- console.log("\n=== runGit ===");
288
285
 
289
286
  const tempDir = mkdtempSync(join(tmpdir(), "gsd-git-service-test-"));
290
287
  run("git init -b main", tempDir);
@@ -293,11 +290,11 @@ async function main(): Promise<void> {
293
290
 
294
291
  // runGit should work on a valid repo
295
292
  const branch = runGit(tempDir, ["branch", "--show-current"]);
296
- assertEq(branch, "main", "runGit returns current branch");
293
+ assert.deepStrictEqual(branch, "main", "runGit returns current branch");
297
294
 
298
295
  // runGit allowFailure returns empty string on failure
299
296
  const result = runGit(tempDir, ["log", "--oneline"], { allowFailure: true });
300
- assertEq(result, "", "runGit allowFailure returns empty on error (no commits yet)");
297
+ assert.deepStrictEqual(result, "", "runGit allowFailure returns empty on error (no commits yet)");
301
298
 
302
299
  // runGit throws on failure without allowFailure
303
300
  let threw = false;
@@ -305,22 +302,21 @@ async function main(): Promise<void> {
305
302
  runGit(tempDir, ["log", "--oneline"]);
306
303
  } catch (e) {
307
304
  threw = true;
308
- assertTrue(
305
+ assert.ok(
309
306
  (e as Error).message.includes("git log --oneline failed"),
310
307
  "error message includes command and path"
311
308
  );
312
309
  }
313
- assertTrue(threw, "runGit throws without allowFailure on error");
310
+ assert.ok(threw, "runGit throws without allowFailure on error");
314
311
 
315
312
  // ─── Type exports compile check ────────────────────────────────────────
316
313
 
317
- console.log("\n=== Type exports ===");
318
314
 
319
315
  // These are compile-time checks — if we got here, the types import fine
320
316
  const _prefs: GitPreferences = { auto_push: true, remote: "origin" };
321
317
  const _opts: CommitOptions = { message: "test" };
322
- assertTrue(true, "GitPreferences type exported and usable");
323
- assertTrue(true, "CommitOptions type exported and usable");
318
+ assert.ok(true, "GitPreferences type exported and usable");
319
+ assert.ok(true, "CommitOptions type exported and usable");
324
320
 
325
321
  // Cleanup T01 temp dir
326
322
  rmSync(tempDir, { recursive: true, force: true });
@@ -347,9 +343,7 @@ async function main(): Promise<void> {
347
343
 
348
344
  // ─── GitServiceImpl: smart staging ─────────────────────────────────────
349
345
 
350
- console.log("\n=== GitServiceImpl: smart staging ===");
351
-
352
- {
346
+ test('GitServiceImpl: smart staging', () => {
353
347
  const repo = initTempRepo();
354
348
  const svc = new GitServiceImpl(repo);
355
349
 
@@ -366,34 +360,32 @@ async function main(): Promise<void> {
366
360
 
367
361
  const result = svc.commit({ message: "test: smart staging" });
368
362
 
369
- assertEq(result, "test: smart staging", "commit returns the commit message");
363
+ assert.deepStrictEqual(result, "test: smart staging", "commit returns the commit message");
370
364
 
371
365
  // Verify only src/code.ts is in the commit
372
366
  const showStat = run("git show --stat --format= HEAD", repo);
373
- assertTrue(showStat.includes("src/code.ts"), "src/code.ts is in the commit");
374
- assertTrue(!showStat.includes(".gsd/activity"), ".gsd/activity/ excluded from commit");
375
- assertTrue(!showStat.includes(".gsd/runtime"), ".gsd/runtime/ excluded from commit");
376
- assertTrue(!showStat.includes("STATE.md"), ".gsd/STATE.md excluded from commit");
377
- assertTrue(!showStat.includes("auto.lock"), ".gsd/auto.lock excluded from commit");
378
- assertTrue(!showStat.includes("metrics.json"), ".gsd/metrics.json excluded from commit");
379
- assertTrue(!showStat.includes(".gsd/worktrees"), ".gsd/worktrees/ excluded from commit");
367
+ assert.ok(showStat.includes("src/code.ts"), "src/code.ts is in the commit");
368
+ assert.ok(!showStat.includes(".gsd/activity"), ".gsd/activity/ excluded from commit");
369
+ assert.ok(!showStat.includes(".gsd/runtime"), ".gsd/runtime/ excluded from commit");
370
+ assert.ok(!showStat.includes("STATE.md"), ".gsd/STATE.md excluded from commit");
371
+ assert.ok(!showStat.includes("auto.lock"), ".gsd/auto.lock excluded from commit");
372
+ assert.ok(!showStat.includes("metrics.json"), ".gsd/metrics.json excluded from commit");
373
+ assert.ok(!showStat.includes(".gsd/worktrees"), ".gsd/worktrees/ excluded from commit");
380
374
 
381
375
  // Verify runtime files are still untracked
382
376
  // git status --short may collapse to "?? .gsd/" or show individual files
383
377
  // Use --untracked-files=all to force individual listing
384
378
  const statusOut = run("git status --short --untracked-files=all", repo);
385
- assertTrue(statusOut.includes(".gsd/activity/"), "activity still untracked after commit");
386
- assertTrue(statusOut.includes(".gsd/runtime/"), "runtime still untracked after commit");
387
- assertTrue(statusOut.includes(".gsd/STATE.md"), "STATE.md still untracked after commit");
379
+ assert.ok(statusOut.includes(".gsd/activity/"), "activity still untracked after commit");
380
+ assert.ok(statusOut.includes(".gsd/runtime/"), "runtime still untracked after commit");
381
+ assert.ok(statusOut.includes(".gsd/STATE.md"), "STATE.md still untracked after commit");
388
382
 
389
383
  rmSync(repo, { recursive: true, force: true });
390
- }
384
+ });
391
385
 
392
386
  // ─── GitServiceImpl: smart staging excludes tracked runtime files ──────
393
387
 
394
- console.log("\n=== GitServiceImpl: smart staging excludes tracked runtime files ===");
395
-
396
- {
388
+ test('GitServiceImpl: smart staging excludes tracked runtime files', () => {
397
389
  // Reproduces the real bug: .gsd/ runtime files that are already tracked
398
390
  // (in the git index) must be excluded from staging even when .gsd/ is
399
391
  // in .gitignore. The old pathspec-exclude approach failed silently in
@@ -423,9 +415,9 @@ async function main(): Promise<void> {
423
415
 
424
416
  // Verify runtime files are tracked (precondition)
425
417
  const tracked = run("git ls-files .gsd/", repo);
426
- assertTrue(tracked.includes("metrics.json"), "precondition: metrics.json tracked");
427
- assertTrue(tracked.includes("completed-units.json"), "precondition: completed-units.json tracked");
428
- assertTrue(tracked.includes("activity/log.jsonl"), "precondition: activity log tracked");
418
+ assert.ok(tracked.includes("metrics.json"), "precondition: metrics.json tracked");
419
+ assert.ok(tracked.includes("completed-units.json"), "precondition: completed-units.json tracked");
420
+ assert.ok(tracked.includes("activity/log.jsonl"), "precondition: activity log tracked");
429
421
 
430
422
  // Now modify both runtime and real files
431
423
  createFile(repo, ".gsd/metrics.json", '{"version":2}');
@@ -436,15 +428,15 @@ async function main(): Promise<void> {
436
428
  // autoCommit should commit real.ts. The first call also runs auto-cleanup
437
429
  // which removes runtime files from the index via a dedicated commit.
438
430
  const msg = svc.autoCommit("execute-task", "M001/S01/T01");
439
- assertTrue(msg !== null, "autoCommit produces a commit");
431
+ assert.ok(msg !== null, "autoCommit produces a commit");
440
432
 
441
433
  const show = run("git show --stat HEAD", repo);
442
- assertTrue(show.includes("src/real.ts"), "real files are committed");
434
+ assert.ok(show.includes("src/real.ts"), "real files are committed");
443
435
 
444
436
  // After the commit, runtime files must no longer be in the git index.
445
437
  // They remain on disk but are untracked (protected by .gitignore).
446
438
  const trackedAfter = run("git ls-files .gsd/", repo);
447
- assertEq(trackedAfter, "", "no .gsd/ runtime files remain in the index");
439
+ assert.deepStrictEqual(trackedAfter, "", "no .gsd/ runtime files remain in the index");
448
440
 
449
441
  // Verify a second autoCommit with changed runtime files does NOT stage them
450
442
  createFile(repo, ".gsd/metrics.json", '{"version":3}');
@@ -452,37 +444,33 @@ async function main(): Promise<void> {
452
444
  createFile(repo, "src/real.ts", "third version");
453
445
 
454
446
  const msg2 = svc.autoCommit("execute-task", "M001/S01/T02");
455
- assertTrue(msg2 !== null, "second autoCommit produces a commit");
447
+ assert.ok(msg2 !== null, "second autoCommit produces a commit");
456
448
 
457
449
  const show2 = run("git show --stat HEAD", repo);
458
- assertTrue(show2.includes("src/real.ts"), "real files committed in second commit");
459
- assertTrue(!show2.includes("metrics"), "metrics.json not in second commit");
460
- assertTrue(!show2.includes("completed-units"), "completed-units.json not in second commit");
461
- assertTrue(!show2.includes("activity"), "activity not in second commit");
450
+ assert.ok(show2.includes("src/real.ts"), "real files committed in second commit");
451
+ assert.ok(!show2.includes("metrics"), "metrics.json not in second commit");
452
+ assert.ok(!show2.includes("completed-units"), "completed-units.json not in second commit");
453
+ assert.ok(!show2.includes("activity"), "activity not in second commit");
462
454
 
463
455
  rmSync(repo, { recursive: true, force: true });
464
- }
456
+ });
465
457
 
466
458
  // ─── GitServiceImpl: autoCommit on clean repo ──────────────────────────
467
459
 
468
- console.log("\n=== GitServiceImpl: autoCommit ===");
469
-
470
- {
460
+ test('GitServiceImpl: autoCommit', () => {
471
461
  const repo = initTempRepo();
472
462
  const svc = new GitServiceImpl(repo);
473
463
 
474
464
  // Clean repo — autoCommit should return null
475
465
  const cleanResult = svc.autoCommit("task", "T01");
476
- assertEq(cleanResult, null, "autoCommit on clean repo returns null");
466
+ assert.deepStrictEqual(cleanResult, null, "autoCommit on clean repo returns null");
477
467
 
478
468
  rmSync(repo, { recursive: true, force: true });
479
- }
469
+ });
480
470
 
481
471
  // ─── GitServiceImpl: autoCommit on dirty repo ──────────────────────────
482
472
 
483
- console.log("\n=== GitServiceImpl: autoCommit on dirty repo ===");
484
-
485
- {
473
+ test('GitServiceImpl: autoCommit on dirty repo', () => {
486
474
  const repo = initTempRepo();
487
475
  const svc = new GitServiceImpl(repo);
488
476
 
@@ -490,10 +478,10 @@ async function main(): Promise<void> {
490
478
 
491
479
  // Without task context, autoCommit uses generic chore message
492
480
  const msg = svc.autoCommit("task", "T01");
493
- assertEq(msg, "chore(T01): auto-commit after task", "autoCommit returns generic format without task context");
481
+ assert.deepStrictEqual(msg, "chore(T01): auto-commit after task", "autoCommit returns generic format without task context");
494
482
 
495
483
  const log = run("git log --oneline -1", repo);
496
- assertTrue(log.includes("chore(T01): auto-commit after task"), "generic commit message is in git log");
484
+ assert.ok(log.includes("chore(T01): auto-commit after task"), "generic commit message is in git log");
497
485
 
498
486
  // With task context, autoCommit uses meaningful message
499
487
  createFile(repo, "src/auth.ts", "export function login() {}");
@@ -503,18 +491,16 @@ async function main(): Promise<void> {
503
491
  oneLiner: "Added JWT-based auth with refresh token rotation",
504
492
  keyFiles: ["src/auth.ts"],
505
493
  });
506
- assertTrue(msg2 !== null, "autoCommit with task context returns a message");
507
- assertTrue(msg2!.startsWith("feat(S01/T02):"), "meaningful commit uses feat type and scope");
508
- assertTrue(msg2!.includes("JWT-based auth"), "meaningful commit includes one-liner content");
494
+ assert.ok(msg2 !== null, "autoCommit with task context returns a message");
495
+ assert.ok(msg2!.startsWith("feat(S01/T02):"), "meaningful commit uses feat type and scope");
496
+ assert.ok(msg2!.includes("JWT-based auth"), "meaningful commit includes one-liner content");
509
497
 
510
498
  rmSync(repo, { recursive: true, force: true });
511
- }
499
+ });
512
500
 
513
501
  // ─── GitServiceImpl: empty-after-staging guard ─────────────────────────
514
502
 
515
- console.log("\n=== GitServiceImpl: empty-after-staging guard ===");
516
-
517
- {
503
+ test('GitServiceImpl: empty-after-staging guard', () => {
518
504
  const repo = initTempRepo();
519
505
  const svc = new GitServiceImpl(repo);
520
506
 
@@ -522,20 +508,18 @@ async function main(): Promise<void> {
522
508
  createFile(repo, ".gsd/activity/x.jsonl", "data");
523
509
 
524
510
  const result = svc.autoCommit("task", "T02");
525
- assertEq(result, null, "autoCommit returns null when only runtime files are dirty");
511
+ assert.deepStrictEqual(result, null, "autoCommit returns null when only runtime files are dirty");
526
512
 
527
513
  // Verify no new commit was created (should still be at init commit)
528
514
  const logCount = run("git rev-list --count HEAD", repo);
529
- assertEq(logCount, "1", "no new commit created when only runtime files changed");
515
+ assert.deepStrictEqual(logCount, "1", "no new commit created when only runtime files changed");
530
516
 
531
517
  rmSync(repo, { recursive: true, force: true });
532
- }
518
+ });
533
519
 
534
520
  // ─── GitServiceImpl: autoCommit with extraExclusions ───────────────────
535
521
 
536
- console.log("\n=== GitServiceImpl: autoCommit with extraExclusions ===");
537
-
538
- {
522
+ test('GitServiceImpl: autoCommit with extraExclusions', () => {
539
523
  const repo = initTempRepo();
540
524
  const svc = new GitServiceImpl(repo);
541
525
 
@@ -545,21 +529,19 @@ async function main(): Promise<void> {
545
529
 
546
530
  // Auto-commit with .gsd/ excluded (simulates pre-switch)
547
531
  const msg = svc.autoCommit("pre-switch", "main", [".gsd/"]);
548
- assertEq(msg, "chore(main): auto-commit after pre-switch", "pre-switch autoCommit with .gsd/ exclusion commits");
532
+ assert.deepStrictEqual(msg, "chore(main): auto-commit after pre-switch", "pre-switch autoCommit with .gsd/ exclusion commits");
549
533
 
550
534
  // Verify .gsd/ file was NOT committed
551
535
  const show = run("git show --stat HEAD", repo);
552
- assertTrue(!show.includes("ROADMAP"), ".gsd/ files excluded from pre-switch auto-commit");
553
- assertTrue(show.includes("feature.ts"), "non-.gsd/ files included in pre-switch auto-commit");
536
+ assert.ok(!show.includes("ROADMAP"), ".gsd/ files excluded from pre-switch auto-commit");
537
+ assert.ok(show.includes("feature.ts"), "non-.gsd/ files included in pre-switch auto-commit");
554
538
 
555
539
  rmSync(repo, { recursive: true, force: true });
556
- }
540
+ });
557
541
 
558
542
  // ─── GitServiceImpl: autoCommit extraExclusions — only .gsd/ dirty ────
559
543
 
560
- console.log("\n=== GitServiceImpl: autoCommit extraExclusions — only .gsd/ dirty ===");
561
-
562
- {
544
+ test('GitServiceImpl: autoCommit extraExclusions — only .gsd/ dirty', () => {
563
545
  const repo = initTempRepo();
564
546
  const svc = new GitServiceImpl(repo);
565
547
 
@@ -569,25 +551,23 @@ async function main(): Promise<void> {
569
551
 
570
552
  // Auto-commit with .gsd/ excluded — nothing else to commit
571
553
  const result = svc.autoCommit("pre-switch", "main", [".gsd/"]);
572
- assertEq(result, null, "autoCommit returns null when only .gsd/ files are dirty and excluded");
554
+ assert.deepStrictEqual(result, null, "autoCommit returns null when only .gsd/ files are dirty and excluded");
573
555
 
574
556
  rmSync(repo, { recursive: true, force: true });
575
- }
557
+ });
576
558
 
577
559
  // ─── GitServiceImpl: commit returns null when nothing staged ───────────
578
560
 
579
- console.log("\n=== GitServiceImpl: commit empty ===");
580
-
581
- {
561
+ test('GitServiceImpl: commit empty', () => {
582
562
  const repo = initTempRepo();
583
563
  const svc = new GitServiceImpl(repo);
584
564
 
585
565
  // Nothing dirty, commit should return null
586
566
  const result = svc.commit({ message: "should not commit" });
587
- assertEq(result, null, "commit returns null when nothing to stage");
567
+ assert.deepStrictEqual(result, null, "commit returns null when nothing to stage");
588
568
 
589
569
  rmSync(repo, { recursive: true, force: true });
590
- }
570
+ });
591
571
 
592
572
  // ─── Helper: create repo for branch tests ────────────────────────────
593
573
 
@@ -604,36 +584,32 @@ async function main(): Promise<void> {
604
584
 
605
585
  // ─── getCurrentBranch ────────────────────────────────────────────────
606
586
 
607
- console.log("\n=== Branch queries ===");
608
-
609
- {
587
+ test('Branch queries', () => {
610
588
  const repo = initBranchTestRepo();
611
589
  const svc = new GitServiceImpl(repo);
612
590
 
613
- assertEq(svc.getCurrentBranch(), "main", "getCurrentBranch returns main on main branch");
591
+ assert.deepStrictEqual(svc.getCurrentBranch(), "main", "getCurrentBranch returns main on main branch");
614
592
 
615
593
  run("git checkout -b gsd/M001/S01", repo);
616
- assertEq(svc.getCurrentBranch(), "gsd/M001/S01", "getCurrentBranch returns slice branch name");
594
+ assert.deepStrictEqual(svc.getCurrentBranch(), "gsd/M001/S01", "getCurrentBranch returns slice branch name");
617
595
 
618
596
  run("git checkout -b feature/foo", repo);
619
- assertEq(svc.getCurrentBranch(), "feature/foo", "getCurrentBranch returns feature branch name");
597
+ assert.deepStrictEqual(svc.getCurrentBranch(), "feature/foo", "getCurrentBranch returns feature branch name");
620
598
 
621
599
  rmSync(repo, { recursive: true, force: true });
622
- }
600
+ });
623
601
 
624
602
  // ─── getMainBranch ────────────────────────────────────────────────────
625
603
 
626
- console.log("\n=== getMainBranch ===");
627
-
628
- {
604
+ test('getMainBranch', () => {
629
605
  const repo = initBranchTestRepo();
630
606
  const svc = new GitServiceImpl(repo);
631
607
 
632
608
  // Basic case: repo has "main" branch
633
- assertEq(svc.getMainBranch(), "main", "getMainBranch returns main when main exists");
609
+ assert.deepStrictEqual(svc.getMainBranch(), "main", "getMainBranch returns main when main exists");
634
610
 
635
611
  rmSync(repo, { recursive: true, force: true });
636
- }
612
+ });
637
613
 
638
614
  {
639
615
  // master-only repo
@@ -646,7 +622,7 @@ async function main(): Promise<void> {
646
622
  run('git commit -m "init"', repo);
647
623
 
648
624
  const svc = new GitServiceImpl(repo);
649
- assertEq(svc.getMainBranch(), "master", "getMainBranch returns master when only master exists");
625
+ assert.deepStrictEqual(svc.getMainBranch(), "master", "getMainBranch returns master when only master exists");
650
626
 
651
627
  rmSync(repo, { recursive: true, force: true });
652
628
  }
@@ -657,9 +633,7 @@ async function main(): Promise<void> {
657
633
 
658
634
  // ─── createSnapshot: prefs enabled ─────────────────────────────────────
659
635
 
660
- console.log("\n=== createSnapshot: enabled ===");
661
-
662
- {
636
+ test('createSnapshot: enabled', () => {
663
637
  const repo = initBranchTestRepo();
664
638
  const svc = new GitServiceImpl(repo, { snapshots: true });
665
639
 
@@ -673,16 +647,14 @@ async function main(): Promise<void> {
673
647
 
674
648
  // Verify ref exists under refs/gsd/snapshots/
675
649
  const refs = run("git for-each-ref refs/gsd/snapshots/", repo);
676
- assertTrue(refs.includes("refs/gsd/snapshots/gsd/M001/S01/"), "snapshot ref created under refs/gsd/snapshots/");
650
+ assert.ok(refs.includes("refs/gsd/snapshots/gsd/M001/S01/"), "snapshot ref created under refs/gsd/snapshots/");
677
651
 
678
652
  rmSync(repo, { recursive: true, force: true });
679
- }
653
+ });
680
654
 
681
655
  // ─── createSnapshot: prefs disabled ────────────────────────────────────
682
656
 
683
- console.log("\n=== createSnapshot: disabled ===");
684
-
685
- {
657
+ test('createSnapshot: disabled', () => {
686
658
  const repo = initBranchTestRepo();
687
659
  const svc = new GitServiceImpl(repo, { snapshots: false });
688
660
 
@@ -694,16 +666,14 @@ async function main(): Promise<void> {
694
666
  svc.createSnapshot("gsd/M001/S01");
695
667
 
696
668
  const refs = run("git for-each-ref refs/gsd/snapshots/", repo);
697
- assertEq(refs, "", "no snapshot ref created when prefs.snapshots is false");
669
+ assert.deepStrictEqual(refs, "", "no snapshot ref created when prefs.snapshots is false");
698
670
 
699
671
  rmSync(repo, { recursive: true, force: true });
700
- }
672
+ });
701
673
 
702
674
  // ─── runPreMergeCheck: pass ────────────────────────────────────────────
703
675
 
704
- console.log("\n=== runPreMergeCheck: pass ===");
705
-
706
- {
676
+ test('runPreMergeCheck: pass', () => {
707
677
  const repo = initBranchTestRepo();
708
678
  // Create package.json with passing test script
709
679
  createFile(repo, "package.json", JSON.stringify({
@@ -716,17 +686,15 @@ async function main(): Promise<void> {
716
686
  const svc = new GitServiceImpl(repo, { pre_merge_check: true });
717
687
  const result: PreMergeCheckResult = svc.runPreMergeCheck();
718
688
 
719
- assertEq(result.passed, true, "runPreMergeCheck returns passed:true when tests pass");
720
- assertTrue(!result.skipped, "runPreMergeCheck is not skipped when enabled");
689
+ assert.deepStrictEqual(result.passed, true, "runPreMergeCheck returns passed:true when tests pass");
690
+ assert.ok(!result.skipped, "runPreMergeCheck is not skipped when enabled");
721
691
 
722
692
  rmSync(repo, { recursive: true, force: true });
723
- }
693
+ });
724
694
 
725
695
  // ─── runPreMergeCheck: fail ────────────────────────────────────────────
726
696
 
727
- console.log("\n=== runPreMergeCheck: fail ===");
728
-
729
- {
697
+ test('runPreMergeCheck: fail', () => {
730
698
  const repo = initBranchTestRepo();
731
699
  // Create package.json with failing test script
732
700
  createFile(repo, "package.json", JSON.stringify({
@@ -739,17 +707,15 @@ async function main(): Promise<void> {
739
707
  const svc = new GitServiceImpl(repo, { pre_merge_check: true });
740
708
  const result: PreMergeCheckResult = svc.runPreMergeCheck();
741
709
 
742
- assertEq(result.passed, false, "runPreMergeCheck returns passed:false when tests fail");
743
- assertTrue(!result.skipped, "runPreMergeCheck is not skipped when enabled");
710
+ assert.deepStrictEqual(result.passed, false, "runPreMergeCheck returns passed:false when tests fail");
711
+ assert.ok(!result.skipped, "runPreMergeCheck is not skipped when enabled");
744
712
 
745
713
  rmSync(repo, { recursive: true, force: true });
746
- }
714
+ });
747
715
 
748
716
  // ─── runPreMergeCheck: disabled ────────────────────────────────────────
749
717
 
750
- console.log("\n=== runPreMergeCheck: disabled ===");
751
-
752
- {
718
+ test('runPreMergeCheck: disabled', () => {
753
719
  const repo = initBranchTestRepo();
754
720
  createFile(repo, "package.json", JSON.stringify({
755
721
  name: "test-disabled",
@@ -761,98 +727,86 @@ async function main(): Promise<void> {
761
727
  const svc = new GitServiceImpl(repo, { pre_merge_check: false });
762
728
  const result: PreMergeCheckResult = svc.runPreMergeCheck();
763
729
 
764
- assertEq(result.skipped, true, "runPreMergeCheck skipped when pre_merge_check is false");
765
- assertEq(result.passed, true, "runPreMergeCheck returns passed:true when skipped (no block)");
730
+ assert.deepStrictEqual(result.skipped, true, "runPreMergeCheck skipped when pre_merge_check is false");
731
+ assert.deepStrictEqual(result.passed, true, "runPreMergeCheck returns passed:true when skipped (no block)");
766
732
 
767
733
  rmSync(repo, { recursive: true, force: true });
768
- }
734
+ });
769
735
 
770
736
  // ─── runPreMergeCheck: custom command ──────────────────────────────────
771
737
 
772
- console.log("\n=== runPreMergeCheck: custom command ===");
773
-
774
- {
738
+ test('runPreMergeCheck: custom command', () => {
775
739
  const repo = initBranchTestRepo();
776
740
  // Custom command string overrides auto-detection
777
741
  const svc = new GitServiceImpl(repo, { pre_merge_check: 'node -e "process.exit(0)"' });
778
742
  const result: PreMergeCheckResult = svc.runPreMergeCheck();
779
743
 
780
- assertEq(result.passed, true, "runPreMergeCheck passes with custom command that exits 0");
781
- assertTrue(!result.skipped, "custom command is not skipped");
744
+ assert.deepStrictEqual(result.passed, true, "runPreMergeCheck passes with custom command that exits 0");
745
+ assert.ok(!result.skipped, "custom command is not skipped");
782
746
 
783
747
  rmSync(repo, { recursive: true, force: true });
784
- }
748
+ });
785
749
 
786
750
  // ─── VALID_BRANCH_NAME regex ──────────────────────────────────────────
787
751
 
788
- console.log("\n=== VALID_BRANCH_NAME regex ===");
789
-
790
- {
752
+ test('VALID_BRANCH_NAME regex', () => {
791
753
  // Valid branch names
792
- assertTrue(VALID_BRANCH_NAME.test("main"), "VALID_BRANCH_NAME accepts 'main'");
793
- assertTrue(VALID_BRANCH_NAME.test("master"), "VALID_BRANCH_NAME accepts 'master'");
794
- assertTrue(VALID_BRANCH_NAME.test("develop"), "VALID_BRANCH_NAME accepts 'develop'");
795
- assertTrue(VALID_BRANCH_NAME.test("feature/foo"), "VALID_BRANCH_NAME accepts 'feature/foo'");
796
- assertTrue(VALID_BRANCH_NAME.test("release-1.0"), "VALID_BRANCH_NAME accepts 'release-1.0'");
797
- assertTrue(VALID_BRANCH_NAME.test("my_branch"), "VALID_BRANCH_NAME accepts 'my_branch'");
798
- assertTrue(VALID_BRANCH_NAME.test("v2.0.1"), "VALID_BRANCH_NAME accepts 'v2.0.1'");
754
+ assert.ok(VALID_BRANCH_NAME.test("main"), "VALID_BRANCH_NAME accepts 'main'");
755
+ assert.ok(VALID_BRANCH_NAME.test("master"), "VALID_BRANCH_NAME accepts 'master'");
756
+ assert.ok(VALID_BRANCH_NAME.test("develop"), "VALID_BRANCH_NAME accepts 'develop'");
757
+ assert.ok(VALID_BRANCH_NAME.test("feature/foo"), "VALID_BRANCH_NAME accepts 'feature/foo'");
758
+ assert.ok(VALID_BRANCH_NAME.test("release-1.0"), "VALID_BRANCH_NAME accepts 'release-1.0'");
759
+ assert.ok(VALID_BRANCH_NAME.test("my_branch"), "VALID_BRANCH_NAME accepts 'my_branch'");
760
+ assert.ok(VALID_BRANCH_NAME.test("v2.0.1"), "VALID_BRANCH_NAME accepts 'v2.0.1'");
799
761
 
800
762
  // Invalid / injection attempts
801
- assertTrue(!VALID_BRANCH_NAME.test("main; rm -rf /"), "VALID_BRANCH_NAME rejects shell injection");
802
- assertTrue(!VALID_BRANCH_NAME.test("main && echo pwned"), "VALID_BRANCH_NAME rejects && injection");
803
- assertTrue(!VALID_BRANCH_NAME.test(""), "VALID_BRANCH_NAME rejects empty string");
804
- assertTrue(!VALID_BRANCH_NAME.test("branch name"), "VALID_BRANCH_NAME rejects spaces");
805
- assertTrue(!VALID_BRANCH_NAME.test("branch`cmd`"), "VALID_BRANCH_NAME rejects backticks");
806
- assertTrue(!VALID_BRANCH_NAME.test("branch$(cmd)"), "VALID_BRANCH_NAME rejects $() subshell");
807
- }
763
+ assert.ok(!VALID_BRANCH_NAME.test("main; rm -rf /"), "VALID_BRANCH_NAME rejects shell injection");
764
+ assert.ok(!VALID_BRANCH_NAME.test("main && echo pwned"), "VALID_BRANCH_NAME rejects && injection");
765
+ assert.ok(!VALID_BRANCH_NAME.test(""), "VALID_BRANCH_NAME rejects empty string");
766
+ assert.ok(!VALID_BRANCH_NAME.test("branch name"), "VALID_BRANCH_NAME rejects spaces");
767
+ assert.ok(!VALID_BRANCH_NAME.test("branch`cmd`"), "VALID_BRANCH_NAME rejects backticks");
768
+ assert.ok(!VALID_BRANCH_NAME.test("branch$(cmd)"), "VALID_BRANCH_NAME rejects $() subshell");
769
+ });
808
770
 
809
771
  // ─── getMainBranch: configured main_branch preference ──────────────────
810
772
 
811
- console.log("\n=== getMainBranch: configured main_branch ===");
812
-
813
- {
773
+ test('getMainBranch: configured main_branch', () => {
814
774
  const repo = initBranchTestRepo();
815
775
  const svc = new GitServiceImpl(repo, { main_branch: "trunk" });
816
776
 
817
- assertEq(svc.getMainBranch(), "trunk", "getMainBranch returns configured main_branch preference");
777
+ assert.deepStrictEqual(svc.getMainBranch(), "trunk", "getMainBranch returns configured main_branch preference");
818
778
 
819
779
  rmSync(repo, { recursive: true, force: true });
820
- }
780
+ });
821
781
 
822
782
  // ─── getMainBranch: falls back to auto-detection when not set ──────────
823
783
 
824
- console.log("\n=== getMainBranch: fallback to auto-detection ===");
825
-
826
- {
784
+ test('getMainBranch: fallback to auto-detection', () => {
827
785
  const repo = initBranchTestRepo();
828
786
  const svc = new GitServiceImpl(repo, {});
829
787
 
830
- assertEq(svc.getMainBranch(), "main", "getMainBranch falls back to auto-detection when main_branch not set");
788
+ assert.deepStrictEqual(svc.getMainBranch(), "main", "getMainBranch falls back to auto-detection when main_branch not set");
831
789
 
832
790
  rmSync(repo, { recursive: true, force: true });
833
- }
791
+ });
834
792
 
835
793
  // ─── getMainBranch: ignores invalid branch names ───────────────────────
836
794
 
837
- console.log("\n=== getMainBranch: ignores invalid branch name ===");
838
-
839
- {
795
+ test('getMainBranch: ignores invalid branch name', () => {
840
796
  const repo = initBranchTestRepo();
841
797
  const svc = new GitServiceImpl(repo, { main_branch: "main; rm -rf /" });
842
798
 
843
- assertEq(svc.getMainBranch(), "main", "getMainBranch ignores invalid branch name and falls back to auto-detection");
799
+ assert.deepStrictEqual(svc.getMainBranch(), "main", "getMainBranch ignores invalid branch name and falls back to auto-detection");
844
800
 
845
801
  rmSync(repo, { recursive: true, force: true });
846
- }
802
+ });
847
803
 
848
804
  // ─── PreMergeCheckResult type export compile check ─────────────────────
849
805
 
850
- console.log("\n=== PreMergeCheckResult type export ===");
851
-
852
- {
806
+ test('PreMergeCheckResult type export', () => {
853
807
  const _checkResult: PreMergeCheckResult = { passed: true, skipped: false };
854
- assertTrue(true, "PreMergeCheckResult type exported and usable");
855
- }
808
+ assert.ok(true, "PreMergeCheckResult type exported and usable");
809
+ });
856
810
 
857
811
  // ═══════════════════════════════════════════════════════════════════════
858
812
  // Integration branch — feature-branch workflow support
@@ -860,82 +814,70 @@ async function main(): Promise<void> {
860
814
 
861
815
  // ─── writeIntegrationBranch / readIntegrationBranch: round-trip ────────
862
816
 
863
- console.log("\n=== Integration branch: write and read ===");
864
-
865
- {
817
+ test('Integration branch: write and read', () => {
866
818
  const repo = initBranchTestRepo();
867
819
 
868
820
  // Initially no integration branch
869
- assertEq(readIntegrationBranch(repo, "M001"), null, "readIntegrationBranch returns null when no metadata");
821
+ assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), null, "readIntegrationBranch returns null when no metadata");
870
822
 
871
823
  // Write integration branch
872
824
  writeIntegrationBranch(repo, "M001", "f-123-new-thing");
873
- assertEq(readIntegrationBranch(repo, "M001"), "f-123-new-thing", "readIntegrationBranch returns written branch");
825
+ assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), "f-123-new-thing", "readIntegrationBranch returns written branch");
874
826
 
875
827
  rmSync(repo, { recursive: true, force: true });
876
- }
828
+ });
877
829
 
878
830
  // ─── writeIntegrationBranch: updates when branch changes (#300) ──────
879
831
 
880
- console.log("\n=== Integration branch: updates on branch change ===");
881
-
882
- {
832
+ test('Integration branch: updates on branch change', () => {
883
833
  const repo = initBranchTestRepo();
884
834
 
885
835
  writeIntegrationBranch(repo, "M001", "f-123-first");
886
836
  writeIntegrationBranch(repo, "M001", "f-456-second"); // updates to new branch (#300)
887
837
 
888
- assertEq(readIntegrationBranch(repo, "M001"), "f-456-second", "second write updates integration branch to new value");
838
+ assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), "f-456-second", "second write updates integration branch to new value");
889
839
 
890
840
  rmSync(repo, { recursive: true, force: true });
891
- }
841
+ });
892
842
 
893
843
  // ─── writeIntegrationBranch: same branch is idempotent ─────────────────
894
844
 
895
- console.log("\n=== Integration branch: same branch is idempotent ===");
896
-
897
- {
845
+ test('Integration branch: same branch is idempotent', () => {
898
846
  const repo = initBranchTestRepo();
899
847
 
900
848
  writeIntegrationBranch(repo, "M001", "f-123-first");
901
849
  writeIntegrationBranch(repo, "M001", "f-123-first"); // same branch — no-op
902
850
 
903
- assertEq(readIntegrationBranch(repo, "M001"), "f-123-first", "same branch write is idempotent");
851
+ assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), "f-123-first", "same branch write is idempotent");
904
852
 
905
853
  rmSync(repo, { recursive: true, force: true });
906
- }
854
+ });
907
855
 
908
856
  // ─── writeIntegrationBranch: rejects slice branches ───────────────────
909
857
 
910
- console.log("\n=== Integration branch: rejects slice branches ===");
911
-
912
- {
858
+ test('Integration branch: rejects slice branches', () => {
913
859
  const repo = initBranchTestRepo();
914
860
 
915
861
  writeIntegrationBranch(repo, "M001", "gsd/M001/S01");
916
- assertEq(readIntegrationBranch(repo, "M001"), null, "slice branches are not recorded as integration branch");
862
+ assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), null, "slice branches are not recorded as integration branch");
917
863
 
918
864
  rmSync(repo, { recursive: true, force: true });
919
- }
865
+ });
920
866
 
921
867
  // ─── writeIntegrationBranch: rejects invalid branch names ─────────────
922
868
 
923
- console.log("\n=== Integration branch: rejects invalid names ===");
924
-
925
- {
869
+ test('Integration branch: rejects invalid names', () => {
926
870
  const repo = initBranchTestRepo();
927
871
 
928
872
  writeIntegrationBranch(repo, "M001", "bad; rm -rf /");
929
- assertEq(readIntegrationBranch(repo, "M001"), null, "invalid branch name is not recorded");
873
+ assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), null, "invalid branch name is not recorded");
930
874
 
931
875
  rmSync(repo, { recursive: true, force: true });
932
- }
876
+ });
933
877
 
934
878
  // ─── getMainBranch: uses integration branch when milestone set ────────
935
879
 
936
- console.log("\n=== getMainBranch: integration branch from milestone metadata ===");
937
-
938
- {
880
+ test('getMainBranch: integration branch from milestone metadata', () => {
939
881
  const repo = initBranchTestRepo();
940
882
 
941
883
  // Create a feature branch
@@ -947,20 +889,18 @@ async function main(): Promise<void> {
947
889
 
948
890
  // Without milestone set, getMainBranch returns "main"
949
891
  const svc = new GitServiceImpl(repo);
950
- assertEq(svc.getMainBranch(), "main", "getMainBranch returns main when no milestone set");
892
+ assert.deepStrictEqual(svc.getMainBranch(), "main", "getMainBranch returns main when no milestone set");
951
893
 
952
894
  // With milestone set, getMainBranch returns the integration branch
953
895
  svc.setMilestoneId("M001");
954
- assertEq(svc.getMainBranch(), "f-123-feature", "getMainBranch returns integration branch when milestone set");
896
+ assert.deepStrictEqual(svc.getMainBranch(), "f-123-feature", "getMainBranch returns integration branch when milestone set");
955
897
 
956
898
  rmSync(repo, { recursive: true, force: true });
957
- }
899
+ });
958
900
 
959
901
  // ─── getMainBranch: main_branch pref still takes priority ─────────────
960
902
 
961
- console.log("\n=== getMainBranch: main_branch pref overrides integration branch ===");
962
-
963
- {
903
+ test('getMainBranch: main_branch pref overrides integration branch', () => {
964
904
  const repo = initBranchTestRepo();
965
905
 
966
906
  run("git checkout -b f-123-feature", repo);
@@ -972,16 +912,14 @@ async function main(): Promise<void> {
972
912
  // Explicit preference still wins
973
913
  const svc = new GitServiceImpl(repo, { main_branch: "trunk" });
974
914
  svc.setMilestoneId("M001");
975
- assertEq(svc.getMainBranch(), "trunk", "main_branch preference overrides integration branch");
915
+ assert.deepStrictEqual(svc.getMainBranch(), "trunk", "main_branch preference overrides integration branch");
976
916
 
977
917
  rmSync(repo, { recursive: true, force: true });
978
- }
918
+ });
979
919
 
980
920
  // ─── getMainBranch: falls back when integration branch deleted ────────
981
921
 
982
- console.log("\n=== getMainBranch: fallback when integration branch deleted ===");
983
-
984
- {
922
+ test('getMainBranch: fallback when integration branch deleted', () => {
985
923
  const repo = initBranchTestRepo();
986
924
 
987
925
  // Write metadata pointing to a branch that doesn't exist
@@ -989,75 +927,67 @@ async function main(): Promise<void> {
989
927
 
990
928
  const svc = new GitServiceImpl(repo);
991
929
  svc.setMilestoneId("M001");
992
- assertEq(svc.getMainBranch(), "main", "getMainBranch falls back to main when integration branch no longer exists");
930
+ assert.deepStrictEqual(svc.getMainBranch(), "main", "getMainBranch falls back to main when integration branch no longer exists");
993
931
 
994
932
  rmSync(repo, { recursive: true, force: true });
995
- }
933
+ });
996
934
 
997
935
  // ─── resolveMilestoneIntegrationBranch: recorded branch wins when it exists ───
998
936
 
999
- console.log("\n=== Integration branch: resolver prefers recorded branch ===");
1000
-
1001
- {
937
+ test('Integration branch: resolver prefers recorded branch', () => {
1002
938
  const repo = initBranchTestRepo();
1003
939
  run("git checkout -b feature/live", repo);
1004
940
  run("git checkout main", repo);
1005
941
  writeIntegrationBranch(repo, "M001", "feature/live");
1006
942
 
1007
943
  const resolved = resolveMilestoneIntegrationBranch(repo, "M001");
1008
- assertEq(resolved.status, "recorded", "resolver reports recorded branch when metadata branch exists");
1009
- assertEq(resolved.recordedBranch, "feature/live", "resolver includes recorded branch");
1010
- assertEq(resolved.effectiveBranch, "feature/live", "resolver uses recorded branch as effective branch");
944
+ assert.deepStrictEqual(resolved.status, "recorded", "resolver reports recorded branch when metadata branch exists");
945
+ assert.deepStrictEqual(resolved.recordedBranch, "feature/live", "resolver includes recorded branch");
946
+ assert.deepStrictEqual(resolved.effectiveBranch, "feature/live", "resolver uses recorded branch as effective branch");
1011
947
 
1012
948
  rmSync(repo, { recursive: true, force: true });
1013
- }
949
+ });
1014
950
 
1015
951
  // ─── resolveMilestoneIntegrationBranch: falls back to detected default ────────
1016
952
 
1017
- console.log("\n=== Integration branch: resolver falls back to detected default ===");
1018
-
1019
- {
953
+ test('Integration branch: resolver falls back to detected default', () => {
1020
954
  const repo = initBranchTestRepo();
1021
955
  writeIntegrationBranch(repo, "M001", "deleted-branch");
1022
956
 
1023
957
  const resolved = resolveMilestoneIntegrationBranch(repo, "M001");
1024
- assertEq(resolved.status, "fallback", "resolver reports fallback when recorded branch is stale");
1025
- assertEq(resolved.recordedBranch, "deleted-branch", "resolver preserves stale recorded branch for diagnostics");
1026
- assertEq(resolved.effectiveBranch, "main", "resolver falls back to detected default branch");
1027
- assertTrue(
958
+ assert.deepStrictEqual(resolved.status, "fallback", "resolver reports fallback when recorded branch is stale");
959
+ assert.deepStrictEqual(resolved.recordedBranch, "deleted-branch", "resolver preserves stale recorded branch for diagnostics");
960
+ assert.deepStrictEqual(resolved.effectiveBranch, "main", "resolver falls back to detected default branch");
961
+ assert.ok(
1028
962
  resolved.reason.includes("deleted-branch") && resolved.reason.includes("main"),
1029
963
  "resolver reason mentions stale recorded branch and fallback branch",
1030
964
  );
1031
965
 
1032
966
  rmSync(repo, { recursive: true, force: true });
1033
- }
967
+ });
1034
968
 
1035
969
  // ─── resolveMilestoneIntegrationBranch: configured main_branch is fallback ─────
1036
970
 
1037
- console.log("\n=== Integration branch: resolver uses configured fallback branch ===");
1038
-
1039
- {
971
+ test('Integration branch: resolver uses configured fallback branch', () => {
1040
972
  const repo = initBranchTestRepo();
1041
973
  run("git checkout -b trunk", repo);
1042
974
  run("git checkout main", repo);
1043
975
  writeIntegrationBranch(repo, "M001", "deleted-branch");
1044
976
 
1045
977
  const resolved = resolveMilestoneIntegrationBranch(repo, "M001", { main_branch: "trunk" });
1046
- assertEq(resolved.status, "fallback", "resolver reports fallback when using configured main_branch");
1047
- assertEq(resolved.effectiveBranch, "trunk", "resolver prefers configured main_branch as fallback");
1048
- assertTrue(
978
+ assert.deepStrictEqual(resolved.status, "fallback", "resolver reports fallback when using configured main_branch");
979
+ assert.deepStrictEqual(resolved.effectiveBranch, "trunk", "resolver prefers configured main_branch as fallback");
980
+ assert.ok(
1049
981
  resolved.reason.includes("deleted-branch") && resolved.reason.includes("trunk"),
1050
982
  "configured fallback reason mentions stale branch and configured branch",
1051
983
  );
1052
984
 
1053
985
  rmSync(repo, { recursive: true, force: true });
1054
- }
986
+ });
1055
987
 
1056
988
  // ─── Per-milestone isolation: different milestones, different targets ──
1057
989
 
1058
- console.log("\n=== Integration branch: per-milestone isolation ===");
1059
-
1060
- {
990
+ test('Integration branch: per-milestone isolation', () => {
1061
991
  const repo = initBranchTestRepo();
1062
992
 
1063
993
  run("git checkout -b feature-a", repo);
@@ -1070,37 +1000,33 @@ async function main(): Promise<void> {
1070
1000
  const svc = new GitServiceImpl(repo);
1071
1001
 
1072
1002
  svc.setMilestoneId("M001");
1073
- assertEq(svc.getMainBranch(), "feature-a", "M001 integration branch is feature-a");
1003
+ assert.deepStrictEqual(svc.getMainBranch(), "feature-a", "M001 integration branch is feature-a");
1074
1004
 
1075
1005
  svc.setMilestoneId("M002");
1076
- assertEq(svc.getMainBranch(), "feature-b", "M002 integration branch is feature-b");
1006
+ assert.deepStrictEqual(svc.getMainBranch(), "feature-b", "M002 integration branch is feature-b");
1077
1007
 
1078
1008
  svc.setMilestoneId(null);
1079
- assertEq(svc.getMainBranch(), "main", "no milestone set → falls back to main");
1009
+ assert.deepStrictEqual(svc.getMainBranch(), "main", "no milestone set → falls back to main");
1080
1010
 
1081
1011
  rmSync(repo, { recursive: true, force: true });
1082
- }
1012
+ });
1083
1013
 
1084
1014
  // ─── Backward compatibility: no metadata → existing behavior ──────────
1085
1015
 
1086
- console.log("\n=== Integration branch: backward compat ===");
1087
-
1088
- {
1016
+ test('Integration branch: backward compat', () => {
1089
1017
  const repo = initBranchTestRepo();
1090
1018
  const svc = new GitServiceImpl(repo);
1091
1019
 
1092
1020
  // Set milestone but no metadata file exists
1093
1021
  svc.setMilestoneId("M001");
1094
- assertEq(svc.getMainBranch(), "main", "backward compat: no metadata file → falls back to main");
1022
+ assert.deepStrictEqual(svc.getMainBranch(), "main", "backward compat: no metadata file → falls back to main");
1095
1023
 
1096
1024
  rmSync(repo, { recursive: true, force: true });
1097
- }
1025
+ });
1098
1026
 
1099
1027
  // ─── untrackRuntimeFiles: removes tracked runtime files from index ───
1100
1028
 
1101
- console.log("\n=== untrackRuntimeFiles ===");
1102
-
1103
- {
1029
+ test('untrackRuntimeFiles', async () => {
1104
1030
  const { untrackRuntimeFiles } = await import("../gitignore.ts");
1105
1031
  const repo = mkdtempSync(join(tmpdir(), "gsd-untrack-"));
1106
1032
  run("git init -b main", repo);
@@ -1121,38 +1047,36 @@ async function main(): Promise<void> {
1121
1047
 
1122
1048
  // Precondition: runtime files are tracked
1123
1049
  const trackedBefore = run("git ls-files .gsd/", repo);
1124
- assertTrue(trackedBefore.includes("completed-units.json"), "untrack: precondition — completed-units tracked");
1125
- assertTrue(trackedBefore.includes("metrics.json"), "untrack: precondition — metrics tracked");
1050
+ assert.ok(trackedBefore.includes("completed-units.json"), "untrack: precondition — completed-units tracked");
1051
+ assert.ok(trackedBefore.includes("metrics.json"), "untrack: precondition — metrics tracked");
1126
1052
 
1127
1053
  // Run untrackRuntimeFiles
1128
1054
  untrackRuntimeFiles(repo);
1129
1055
 
1130
1056
  // Runtime files should be removed from the index
1131
1057
  const trackedAfter = run("git ls-files .gsd/", repo);
1132
- assertEq(trackedAfter, "", "untrack: all runtime files removed from index");
1058
+ assert.deepStrictEqual(trackedAfter, "", "untrack: all runtime files removed from index");
1133
1059
 
1134
1060
  // Non-runtime files remain tracked
1135
1061
  const srcTracked = run("git ls-files src.ts", repo);
1136
- assertTrue(srcTracked.includes("src.ts"), "untrack: non-runtime files remain tracked");
1062
+ assert.ok(srcTracked.includes("src.ts"), "untrack: non-runtime files remain tracked");
1137
1063
 
1138
1064
  // Files still exist on disk
1139
- assertTrue(existsSync(join(repo, ".gsd", "completed-units.json")),
1065
+ assert.ok(existsSync(join(repo, ".gsd", "completed-units.json")),
1140
1066
  "untrack: completed-units.json still on disk");
1141
- assertTrue(existsSync(join(repo, ".gsd", "metrics.json")),
1067
+ assert.ok(existsSync(join(repo, ".gsd", "metrics.json")),
1142
1068
  "untrack: metrics.json still on disk");
1143
1069
 
1144
1070
  // Idempotent — running again doesn't error
1145
1071
  untrackRuntimeFiles(repo);
1146
- assertTrue(true, "untrack: second call is idempotent (no error)");
1072
+ assert.ok(true, "untrack: second call is idempotent (no error)");
1147
1073
 
1148
1074
  rmSync(repo, { recursive: true, force: true });
1149
- }
1075
+ });
1150
1076
 
1151
1077
  // ─── smartStage excludes runtime files but allows milestone artifacts ──
1152
1078
 
1153
- console.log("\n=== smartStage excludes runtime files, allows milestone artifacts ===");
1154
-
1155
- {
1079
+ test('smartStage excludes runtime files, allows milestone artifacts', () => {
1156
1080
  const repo = mkdtempSync(join(tmpdir(), "gsd-smart-stage-excludes-"));
1157
1081
  run("git init -b main", repo);
1158
1082
  run("git config user.email test@test.com", repo);
@@ -1174,71 +1098,65 @@ async function main(): Promise<void> {
1174
1098
  // smartStage excludes only runtime paths, not all of .gsd/ (#1326)
1175
1099
  const svc = new GitServiceImpl(repo);
1176
1100
  const msg = svc.commit({ message: "test commit" });
1177
- assertTrue(msg !== null, "smartStage: commit succeeds");
1101
+ assert.ok(msg !== null, "smartStage: commit succeeds");
1178
1102
 
1179
1103
  const committed = run("git show --name-only HEAD", repo);
1180
- assertTrue(committed.includes("src.ts"), "smartStage: source files ARE in commit");
1104
+ assert.ok(committed.includes("src.ts"), "smartStage: source files ARE in commit");
1181
1105
  // Runtime files should NOT be committed
1182
- assertTrue(!committed.includes(".gsd/STATE.md"), "smartStage: STATE.md excluded (runtime)");
1183
- assertTrue(!committed.includes(".gsd/runtime/"), "smartStage: runtime/ excluded");
1184
- assertTrue(!committed.includes(".gsd/activity/"), "smartStage: activity/ excluded");
1106
+ assert.ok(!committed.includes(".gsd/STATE.md"), "smartStage: STATE.md excluded (runtime)");
1107
+ assert.ok(!committed.includes(".gsd/runtime/"), "smartStage: runtime/ excluded");
1108
+ assert.ok(!committed.includes(".gsd/activity/"), "smartStage: activity/ excluded");
1185
1109
  // Milestone artifacts SHOULD be committed when not gitignored (#1326)
1186
- assertTrue(committed.includes(".gsd/milestones/"), "smartStage: milestone artifacts ARE committed");
1110
+ assert.ok(committed.includes(".gsd/milestones/"), "smartStage: milestone artifacts ARE committed");
1187
1111
 
1188
1112
  rmSync(repo, { recursive: true, force: true });
1189
- }
1113
+ });
1190
1114
 
1191
1115
  // ─── writeIntegrationBranch: no commit (metadata in external storage) ──
1192
1116
 
1193
- console.log("\n=== writeIntegrationBranch: no commit ===");
1194
-
1195
- {
1117
+ test('writeIntegrationBranch: no commit', () => {
1196
1118
  const repo = initBranchTestRepo();
1197
1119
  const commitsBefore = run("git rev-list --count HEAD", repo);
1198
1120
 
1199
1121
  writeIntegrationBranch(repo, "M001", "f-123-new-thing");
1200
1122
 
1201
1123
  // File should still be written to disk
1202
- assertEq(readIntegrationBranch(repo, "M001"), "f-123-new-thing",
1124
+ assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), "f-123-new-thing",
1203
1125
  "writeIntegrationBranch: metadata file exists on disk");
1204
1126
 
1205
1127
  // No commit — .gsd/ is managed externally
1206
1128
  const commitsAfter = run("git rev-list --count HEAD", repo);
1207
- assertEq(commitsBefore, commitsAfter,
1129
+ assert.deepStrictEqual(commitsBefore, commitsAfter,
1208
1130
  "writeIntegrationBranch: no git commit created for integration branch");
1209
1131
 
1210
1132
  rmSync(repo, { recursive: true, force: true });
1211
- }
1133
+ });
1212
1134
 
1213
1135
  // ─── ensureGitignore: always adds .gsd to gitignore ──────────────────
1214
1136
 
1215
- console.log("\n=== ensureGitignore: adds .gsd entry ===");
1216
-
1217
- {
1137
+ test('ensureGitignore: adds .gsd entry', async () => {
1218
1138
  const { ensureGitignore } = await import("../gitignore.ts");
1219
1139
  const repo = mkdtempSync(join(tmpdir(), "gsd-gitignore-external-state-"));
1220
1140
 
1221
1141
  // Should add .gsd to gitignore (external state dir is a symlink)
1222
1142
  const modified = ensureGitignore(repo);
1223
- assertTrue(modified, "ensureGitignore: gitignore was modified");
1143
+ assert.ok(modified, "ensureGitignore: gitignore was modified");
1224
1144
 
1225
1145
  const { readFileSync } = await import("node:fs");
1226
1146
  const content = readFileSync(join(repo, ".gitignore"), "utf-8");
1227
1147
  const lines = content.split("\n").map(l => l.trim()).filter(l => l && !l.startsWith("#"));
1228
- assertTrue(lines.includes(".gsd"), "ensureGitignore: .gitignore contains .gsd");
1148
+ assert.ok(lines.includes(".gsd"), "ensureGitignore: .gitignore contains .gsd");
1229
1149
 
1230
1150
  // Idempotent — calling again doesn't add duplicates
1231
1151
  const modified2 = ensureGitignore(repo);
1232
- assertTrue(!modified2, "ensureGitignore: second call is idempotent");
1152
+ assert.ok(!modified2, "ensureGitignore: second call is idempotent");
1233
1153
 
1234
1154
  rmSync(repo, { recursive: true, force: true });
1235
- }
1155
+ });
1236
1156
 
1237
1157
  // ─── nativeAddAllWithExclusions: symlinked .gsd fallback ───────────────
1238
1158
 
1239
- console.log("\n=== nativeAddAllWithExclusions: symlinked .gsd fallback ===");
1240
-
1241
- {
1159
+ test('nativeAddAllWithExclusions: symlinked .gsd fallback', () => {
1242
1160
  // When .gsd is a symlink, git rejects `:!.gsd/...` pathspecs with
1243
1161
  // "fatal: pathspec '...' is beyond a symbolic link". The fix falls
1244
1162
  // back to plain `git add -A`, which respects .gitignore.
@@ -1267,22 +1185,20 @@ async function main(): Promise<void> {
1267
1185
  threw = true;
1268
1186
  console.error(" unexpected error:", e);
1269
1187
  }
1270
- assertTrue(!threw, "nativeAddAllWithExclusions does not throw with symlinked .gsd");
1188
+ assert.ok(!threw, "nativeAddAllWithExclusions does not throw with symlinked .gsd");
1271
1189
 
1272
1190
  // Verify the real file was staged
1273
1191
  const staged = run("git diff --cached --name-only", repo);
1274
- assertTrue(staged.includes("src/app.ts"), "real file staged despite symlinked .gsd");
1275
- assertTrue(!staged.includes(".gsd"), ".gsd content not staged");
1192
+ assert.ok(staged.includes("src/app.ts"), "real file staged despite symlinked .gsd");
1193
+ assert.ok(!staged.includes(".gsd"), ".gsd content not staged");
1276
1194
 
1277
1195
  rmSync(repo, { recursive: true, force: true });
1278
1196
  rmSync(externalGsd, { recursive: true, force: true });
1279
- }
1197
+ });
1280
1198
 
1281
1199
  // ─── nativeAddAllWithExclusions: non-symlinked .gsd still works ───────
1282
1200
 
1283
- console.log("\n=== nativeAddAllWithExclusions: non-symlinked .gsd still works ===");
1284
-
1285
- {
1201
+ test('nativeAddAllWithExclusions: non-symlinked .gsd still works', () => {
1286
1202
  // Verify the normal (non-symlink) case still works with pathspec exclusions
1287
1203
  const repo = initTempRepo();
1288
1204
 
@@ -1296,96 +1212,91 @@ async function main(): Promise<void> {
1296
1212
  } catch {
1297
1213
  threw = true;
1298
1214
  }
1299
- assertTrue(!threw, "nativeAddAllWithExclusions works with normal .gsd directory");
1215
+ assert.ok(!threw, "nativeAddAllWithExclusions works with normal .gsd directory");
1300
1216
 
1301
1217
  const staged = run("git diff --cached --name-only", repo);
1302
- assertTrue(staged.includes("src/code.ts"), "real file staged with normal .gsd");
1218
+ assert.ok(staged.includes("src/code.ts"), "real file staged with normal .gsd");
1303
1219
 
1304
1220
  rmSync(repo, { recursive: true, force: true });
1305
- }
1221
+ });
1306
1222
 
1307
1223
  // ─── MergeConflictError: constructor fields ───────────────────────────────
1308
1224
 
1309
- console.log("\n=== MergeConflictError: constructor fields ===");
1310
- {
1225
+ test('MergeConflictError: constructor fields', () => {
1311
1226
  const err = new MergeConflictError(
1312
1227
  ["src/foo.ts", "src/bar.ts"],
1313
1228
  "squash",
1314
1229
  "gsd/M001/S01",
1315
1230
  "main",
1316
1231
  );
1317
- assertEq(err.conflictedFiles, ["src/foo.ts", "src/bar.ts"], "MergeConflictError.conflictedFiles populated");
1318
- assertEq(err.strategy, "squash", "MergeConflictError.strategy set");
1319
- assertEq(err.branch, "gsd/M001/S01", "MergeConflictError.branch set");
1320
- assertEq(err.mainBranch, "main", "MergeConflictError.mainBranch set");
1321
- assertEq(err.name, "MergeConflictError", "MergeConflictError.name is MergeConflictError");
1322
- assertTrue(err.message.includes("src/foo.ts"), "MergeConflictError message lists conflicted files");
1323
- assertTrue(err.message.toLowerCase().includes("squash"), "MergeConflictError message mentions strategy");
1324
- assertTrue(err instanceof MergeConflictError, "MergeConflictError is an instanceof MergeConflictError");
1325
- assertTrue(err instanceof Error, "MergeConflictError is an Error instance");
1326
- }
1232
+ assert.deepStrictEqual(err.conflictedFiles, ["src/foo.ts", "src/bar.ts"], "MergeConflictError.conflictedFiles populated");
1233
+ assert.deepStrictEqual(err.strategy, "squash", "MergeConflictError.strategy set");
1234
+ assert.deepStrictEqual(err.branch, "gsd/M001/S01", "MergeConflictError.branch set");
1235
+ assert.deepStrictEqual(err.mainBranch, "main", "MergeConflictError.mainBranch set");
1236
+ assert.deepStrictEqual(err.name, "MergeConflictError", "MergeConflictError.name is MergeConflictError");
1237
+ assert.ok(err.message.includes("src/foo.ts"), "MergeConflictError message lists conflicted files");
1238
+ assert.ok(err.message.toLowerCase().includes("squash"), "MergeConflictError message mentions strategy");
1239
+ assert.ok(err instanceof MergeConflictError, "MergeConflictError is an instanceof MergeConflictError");
1240
+ assert.ok(err instanceof Error, "MergeConflictError is an Error instance");
1241
+ });
1327
1242
 
1328
1243
  // ─── Integration branch: rejects gsd/quick/* branches ────────────────────
1329
1244
 
1330
- console.log("\n=== Integration branch: rejects gsd/quick/* branches ===");
1331
- {
1245
+ test('Integration branch: rejects gsd/quick/* branches', () => {
1332
1246
  const repo = initBranchTestRepo();
1333
1247
 
1334
1248
  writeIntegrationBranch(repo, "M001", "gsd/quick/1234-some-task");
1335
- assertEq(readIntegrationBranch(repo, "M001"), null, "gsd/quick/* branches are not recorded as integration branch");
1249
+ assert.deepStrictEqual(readIntegrationBranch(repo, "M001"), null, "gsd/quick/* branches are not recorded as integration branch");
1336
1250
 
1337
1251
  rmSync(repo, { recursive: true, force: true });
1338
- }
1252
+ });
1339
1253
 
1340
1254
  // ─── Integration branch: resolver returns missing when no metadata ────────
1341
1255
 
1342
- console.log("\n=== Integration branch: resolver returns missing when no metadata ===");
1343
- {
1256
+ test('Integration branch: resolver returns missing when no metadata', () => {
1344
1257
  const repo = initBranchTestRepo();
1345
1258
 
1346
1259
  // No writeIntegrationBranch call — no metadata file exists
1347
1260
  const resolved = resolveMilestoneIntegrationBranch(repo, "M999");
1348
- assertEq(resolved.status, "missing", "resolver reports missing when no metadata file");
1349
- assertEq(resolved.recordedBranch, null, "resolver recordedBranch is null when no metadata");
1350
- assertEq(resolved.effectiveBranch, null, "resolver effectiveBranch is null when no metadata");
1351
- assertTrue(resolved.reason.includes("M999"), "resolver reason mentions the milestone ID");
1261
+ assert.deepStrictEqual(resolved.status, "missing", "resolver reports missing when no metadata file");
1262
+ assert.deepStrictEqual(resolved.recordedBranch, null, "resolver recordedBranch is null when no metadata");
1263
+ assert.deepStrictEqual(resolved.effectiveBranch, null, "resolver effectiveBranch is null when no metadata");
1264
+ assert.ok(resolved.reason.includes("M999"), "resolver reason mentions the milestone ID");
1352
1265
 
1353
1266
  rmSync(repo, { recursive: true, force: true });
1354
- }
1267
+ });
1355
1268
 
1356
1269
  // ─── Integration branch: resolver missing when both recorded and configured branches gone ───
1357
1270
 
1358
- console.log("\n=== Integration branch: resolver missing when both recorded and configured branches gone ===");
1359
- {
1271
+ test('Integration branch: resolver missing when both recorded and configured branches gone', () => {
1360
1272
  const repo = initBranchTestRepo();
1361
1273
 
1362
1274
  // Record a branch that doesn't exist
1363
1275
  writeIntegrationBranch(repo, "M001", "deleted-feature");
1364
1276
  // configured main_branch also doesn't exist
1365
1277
  const resolved = resolveMilestoneIntegrationBranch(repo, "M001", { main_branch: "nonexistent-branch" });
1366
- assertEq(resolved.status, "missing", "resolver reports missing when recorded branch and configured main_branch both absent");
1367
- assertEq(resolved.recordedBranch, "deleted-feature", "resolver preserves stale recorded branch");
1368
- assertEq(resolved.effectiveBranch, null, "resolver effectiveBranch is null when no safe fallback");
1369
- assertTrue(
1278
+ assert.deepStrictEqual(resolved.status, "missing", "resolver reports missing when recorded branch and configured main_branch both absent");
1279
+ assert.deepStrictEqual(resolved.recordedBranch, "deleted-feature", "resolver preserves stale recorded branch");
1280
+ assert.deepStrictEqual(resolved.effectiveBranch, null, "resolver effectiveBranch is null when no safe fallback");
1281
+ assert.ok(
1370
1282
  resolved.reason.includes("deleted-feature") && resolved.reason.includes("nonexistent-branch"),
1371
1283
  "reason mentions both stale branch and unavailable configured branch",
1372
1284
  );
1373
1285
 
1374
1286
  rmSync(repo, { recursive: true, force: true });
1375
- }
1287
+ });
1376
1288
 
1377
1289
  // ─── buildTaskCommitMessage: issueNumber appends Resolves trailer ─────────
1378
1290
 
1379
- console.log("\n=== buildTaskCommitMessage: issueNumber appends Resolves trailer ===");
1380
- {
1291
+ test('buildTaskCommitMessage: issueNumber appends Resolves trailer', () => {
1381
1292
  const msg = buildTaskCommitMessage({
1382
1293
  taskId: "S01/T03",
1383
1294
  taskTitle: "fix login redirect",
1384
1295
  issueNumber: 42,
1385
1296
  });
1386
- assertTrue(msg.includes("Resolves #42"), "buildTaskCommitMessage includes Resolves #N trailer when issueNumber is set");
1387
- assertTrue(msg.startsWith("fix(S01/T03):"), "buildTaskCommitMessage infers fix type");
1388
- }
1297
+ assert.ok(msg.includes("Resolves #42"), "buildTaskCommitMessage includes Resolves #N trailer when issueNumber is set");
1298
+ assert.ok(msg.startsWith("fix(S01/T03):"), "buildTaskCommitMessage infers fix type");
1299
+ });
1389
1300
 
1390
1301
  {
1391
1302
  // No issueNumber — no Resolves trailer
@@ -1393,29 +1304,26 @@ async function main(): Promise<void> {
1393
1304
  taskId: "S01/T04",
1394
1305
  taskTitle: "add dashboard widget",
1395
1306
  });
1396
- assertTrue(!msg.includes("Resolves"), "buildTaskCommitMessage omits Resolves trailer when issueNumber is absent");
1307
+ assert.ok(!msg.includes("Resolves"), "buildTaskCommitMessage omits Resolves trailer when issueNumber is absent");
1397
1308
  }
1398
1309
 
1399
1310
  // ─── runPreMergeCheck: skips when no package.json ────────────────────────
1400
1311
 
1401
- console.log("\n=== runPreMergeCheck: skips when no package.json ===");
1402
- {
1312
+ test('runPreMergeCheck: skips when no package.json', () => {
1403
1313
  const repo = initBranchTestRepo();
1404
1314
  // No package.json created — auto-detect should skip gracefully
1405
1315
  const svc = new GitServiceImpl(repo, { pre_merge_check: true });
1406
1316
  const result: PreMergeCheckResult = svc.runPreMergeCheck();
1407
1317
 
1408
- assertEq(result.passed, true, "runPreMergeCheck passes when no package.json (skip)");
1409
- assertEq(result.skipped, true, "runPreMergeCheck skips when no package.json found");
1318
+ assert.deepStrictEqual(result.passed, true, "runPreMergeCheck passes when no package.json (skip)");
1319
+ assert.deepStrictEqual(result.skipped, true, "runPreMergeCheck skips when no package.json found");
1410
1320
 
1411
1321
  rmSync(repo, { recursive: true, force: true });
1412
- }
1322
+ });
1413
1323
 
1414
1324
  // ─── autoCommit: symlinked .gsd does NOT stage milestone artifacts (#2247) ──
1415
1325
 
1416
- console.log("\n=== autoCommit: symlinked .gsd does NOT stage milestone artifacts (#2247) ===");
1417
-
1418
- {
1326
+ test('autoCommit: symlinked .gsd does NOT stage milestone artifacts (#2247)', () => {
1419
1327
  // When .gsd is a symlink (external state project), .gsd/ files live outside
1420
1328
  // the repo by design. smartStage() must NOT force-stage them into git — the
1421
1329
  // .gitignore exclusion is correct and intentional.
@@ -1444,21 +1352,14 @@ async function main(): Promise<void> {
1444
1352
 
1445
1353
  const svc = new GitServiceImpl(repo);
1446
1354
  const msg = svc.autoCommit("complete-milestone", "M009");
1447
- assertTrue(msg !== null, "symlink autoCommit: commit succeeds");
1355
+ assert.ok(msg !== null, "symlink autoCommit: commit succeeds");
1448
1356
 
1449
1357
  const committed = run("git show --name-only HEAD", repo);
1450
- assertTrue(committed.includes("src/feature.ts"), "symlink autoCommit: source file committed");
1451
- assertTrue(!committed.includes(".gsd/milestones/"),
1358
+ assert.ok(committed.includes("src/feature.ts"), "symlink autoCommit: source file committed");
1359
+ assert.ok(!committed.includes(".gsd/milestones/"),
1452
1360
  "symlink autoCommit: .gsd/milestones/ files are NOT staged (external state stays external)");
1453
1361
 
1454
1362
  try { rmSync(repo, { recursive: true, force: true }); } catch {}
1455
1363
  try { rmSync(externalGsd, { recursive: true, force: true }); } catch {}
1456
- }
1457
-
1458
- report();
1459
- }
1460
-
1461
- main().catch((error) => {
1462
- console.error(error);
1463
- process.exit(1);
1364
+ });
1464
1365
  });