gsd-pi 2.44.0-dev.62b5d6c → 2.44.0-dev.73f2fd5

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 (326) hide show
  1. package/README.md +30 -12
  2. package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
  3. package/dist/resources/extensions/gsd/auto/phases.js +36 -36
  4. package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
  5. package/dist/resources/extensions/gsd/auto-start.js +10 -0
  6. package/dist/resources/extensions/gsd/auto-timers.js +57 -3
  7. package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
  8. package/dist/resources/extensions/gsd/auto-worktree.js +9 -6
  9. package/dist/resources/extensions/gsd/auto.js +30 -3
  10. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +156 -0
  11. package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
  12. package/dist/resources/extensions/gsd/commands/catalog.js +6 -1
  13. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
  14. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  15. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  16. package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
  17. package/dist/resources/extensions/gsd/db-writer.js +34 -16
  18. package/dist/resources/extensions/gsd/doctor.js +8 -0
  19. package/dist/resources/extensions/gsd/git-service.js +8 -3
  20. package/dist/resources/extensions/gsd/gsd-db.js +12 -1
  21. package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
  22. package/dist/resources/extensions/gsd/preferences.js +9 -1
  23. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
  24. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  25. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  26. package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  27. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  28. package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
  29. package/dist/resources/extensions/gsd/state.js +19 -2
  30. package/dist/resources/extensions/gsd/tools/plan-slice.js +1 -0
  31. package/dist/resources/extensions/gsd/tools/plan-task.js +1 -0
  32. package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -0
  33. package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
  34. package/dist/resources/extensions/gsd/worktree-resolver.js +6 -0
  35. package/dist/resources/extensions/mcp-client/index.js +14 -0
  36. package/dist/web/standalone/.next/BUILD_ID +1 -1
  37. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  38. package/dist/web/standalone/.next/build-manifest.json +2 -2
  39. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  40. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  41. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  49. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/index.html +1 -1
  57. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  64. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  65. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  66. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  67. package/package.json +1 -1
  68. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
  69. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  70. package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
  71. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  72. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  73. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  74. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  75. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  76. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  77. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  78. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
  79. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
  80. package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
  81. package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
  82. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +11 -0
  83. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  84. package/packages/pi-coding-agent/dist/core/model-registry.js +20 -1
  85. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  86. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  87. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  88. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  89. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  90. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  91. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  92. package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
  93. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  94. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  95. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  96. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  97. package/packages/pi-coding-agent/dist/main.js +17 -0
  98. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  99. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
  100. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
  101. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
  102. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
  103. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  104. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  105. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
  106. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  107. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  108. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  109. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
  110. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  111. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
  112. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
  113. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
  114. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
  115. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  116. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
  117. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  118. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
  119. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  120. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
  121. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  122. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  123. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
  124. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  125. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  126. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
  127. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  128. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  129. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  130. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  131. package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
  132. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  133. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  134. package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
  135. package/packages/pi-coding-agent/src/core/model-registry.ts +21 -1
  136. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  137. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  138. package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
  139. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  140. package/packages/pi-coding-agent/src/main.ts +19 -0
  141. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
  142. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
  143. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  144. package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
  145. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
  146. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
  147. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
  148. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
  149. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  150. package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
  151. package/src/resources/extensions/gsd/auto/phases.ts +45 -48
  152. package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
  153. package/src/resources/extensions/gsd/auto-start.ts +14 -0
  154. package/src/resources/extensions/gsd/auto-timers.ts +64 -3
  155. package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
  156. package/src/resources/extensions/gsd/auto-worktree.ts +9 -6
  157. package/src/resources/extensions/gsd/auto.ts +37 -3
  158. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +148 -0
  159. package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
  160. package/src/resources/extensions/gsd/commands/catalog.ts +6 -1
  161. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
  162. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  163. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  164. package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
  165. package/src/resources/extensions/gsd/db-writer.ts +39 -17
  166. package/src/resources/extensions/gsd/doctor.ts +7 -1
  167. package/src/resources/extensions/gsd/git-service.ts +6 -2
  168. package/src/resources/extensions/gsd/gsd-db.ts +16 -1
  169. package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
  170. package/src/resources/extensions/gsd/preferences.ts +11 -1
  171. package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
  172. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  173. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  174. package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  175. package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  176. package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
  177. package/src/resources/extensions/gsd/state.ts +19 -1
  178. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  179. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  180. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  181. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
  182. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  183. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
  184. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  185. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  186. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
  187. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  188. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  189. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  190. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  191. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  192. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  193. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  194. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
  195. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
  196. package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
  197. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
  198. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  199. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  200. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  201. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  202. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  203. package/src/resources/extensions/gsd/tests/db-writer.test.ts +465 -416
  204. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  205. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
  206. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +210 -181
  207. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  208. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  209. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  210. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  211. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
  212. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  213. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  214. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
  215. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  216. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
  217. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
  218. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  219. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
  220. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  221. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  222. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
  223. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  224. package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
  225. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  226. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
  227. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  228. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  229. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  230. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
  231. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
  232. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  233. package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
  234. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  235. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  236. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  237. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  238. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
  239. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  240. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  241. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  242. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
  243. package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
  244. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  245. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  246. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  247. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  248. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
  249. package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
  250. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
  251. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
  252. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  253. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  254. package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
  255. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
  256. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  257. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
  258. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  259. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  260. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  261. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
  262. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
  263. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  264. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +35 -36
  265. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  266. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  267. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  268. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  269. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  270. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  271. package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
  272. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  273. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  274. package/src/resources/extensions/gsd/tests/preferences.test.ts +27 -0
  275. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +11 -7
  276. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  277. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  278. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  279. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  280. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  281. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  282. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  283. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  284. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  285. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  286. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  287. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  288. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  289. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  290. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  291. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  292. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
  293. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  294. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  295. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
  296. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  297. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
  298. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  299. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  300. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +10 -11
  301. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  302. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  303. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  304. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  305. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  306. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  307. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  308. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  309. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  310. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  311. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  312. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  313. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  314. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  315. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  316. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  317. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  318. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  319. package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
  320. package/src/resources/extensions/gsd/tools/plan-task.ts +2 -0
  321. package/src/resources/extensions/gsd/tools/replan-slice.ts +3 -0
  322. package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
  323. package/src/resources/extensions/gsd/worktree-resolver.ts +7 -0
  324. package/src/resources/extensions/mcp-client/index.ts +20 -0
  325. /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → kxxAA66bah_yhPYqLBHE2}/_buildManifest.js +0 -0
  326. /package/dist/web/standalone/.next/static/{fOnWQBjWXMKUs4bqTg530 → kxxAA66bah_yhPYqLBHE2}/_ssgManifest.js +0 -0
@@ -39,61 +39,55 @@ function activeData(overrides: Partial<HealthWidgetData> = {}): HealthWidgetData
39
39
  };
40
40
  }
41
41
 
42
- test("detectHealthWidgetProjectState: no .gsd returns none", () => {
42
+ test("detectHealthWidgetProjectState: no .gsd returns none", (t) => {
43
43
  const dir = makeTempDir("none");
44
- try {
45
- assert.equal(detectHealthWidgetProjectState(dir), "none");
46
- } finally {
47
- cleanup(dir);
48
- }
44
+ t.after(() => { cleanup(dir); });
45
+
46
+ assert.equal(detectHealthWidgetProjectState(dir), "none");
49
47
  });
50
48
 
51
- test("detectHealthWidgetProjectState: bootstrapped .gsd without milestones returns initialized", () => {
49
+ test("detectHealthWidgetProjectState: bootstrapped .gsd without milestones returns initialized", (t) => {
52
50
  const dir = makeTempDir("initialized");
53
- try {
54
- mkdirSync(join(dir, ".gsd"), { recursive: true });
55
- assert.equal(detectHealthWidgetProjectState(dir), "initialized");
56
- } finally {
57
- cleanup(dir);
58
- }
51
+ t.after(() => { cleanup(dir); });
52
+
53
+ mkdirSync(join(dir, ".gsd"), { recursive: true });
54
+ assert.equal(detectHealthWidgetProjectState(dir), "initialized");
59
55
  });
60
56
 
61
- test("detectHealthWidgetProjectState: milestone without metrics returns active", () => {
57
+ test("detectHealthWidgetProjectState: milestone without metrics returns active", (t) => {
62
58
  const dir = makeTempDir("active");
63
- try {
64
- mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
65
- assert.equal(detectHealthWidgetProjectState(dir), "active");
66
- } finally {
67
- cleanup(dir);
68
- }
59
+ t.after(() => { cleanup(dir); });
60
+
61
+ mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
62
+ assert.equal(detectHealthWidgetProjectState(dir), "active");
69
63
  });
70
64
 
71
- test("buildHealthLines: none state shows onboarding copy", () => {
65
+ test("buildHealthLines: none state shows onboarding copy", (t) => {
72
66
  assert.deepEqual(buildHealthLines(activeData({ projectState: "none" })), [
73
67
  " GSD No project loaded — run /gsd to start",
74
68
  ]);
75
69
  });
76
70
 
77
- test("buildHealthLines: initialized state shows continue setup copy", () => {
71
+ test("buildHealthLines: initialized state shows continue setup copy", (t) => {
78
72
  assert.deepEqual(buildHealthLines(activeData({ projectState: "initialized" })), [
79
73
  " GSD Project initialized — run /gsd to continue setup",
80
74
  ]);
81
75
  });
82
76
 
83
- test("buildHealthLines: active state with ledger-driven spend shows spent summary", () => {
77
+ test("buildHealthLines: active state with ledger-driven spend shows spent summary", (t) => {
84
78
  const lines = buildHealthLines(activeData({ budgetSpent: 0.42 }));
85
79
  assert.equal(lines.length, 1);
86
80
  assert.match(lines[0]!, /● System OK/);
87
81
  assert.match(lines[0]!, /Spent: 42\.0¢/);
88
82
  });
89
83
 
90
- test("buildHealthLines: active state with budget ceiling shows percent summary", () => {
84
+ test("buildHealthLines: active state with budget ceiling shows percent summary", (t) => {
91
85
  const lines = buildHealthLines(activeData({ budgetSpent: 2.5, budgetCeiling: 10 }));
92
86
  assert.equal(lines.length, 1);
93
87
  assert.match(lines[0]!, /Budget: \$2\.50\/\$10\.00 \(25%\)/);
94
88
  });
95
89
 
96
- test("buildHealthLines: active state with issues reports issue summary", () => {
90
+ test("buildHealthLines: active state with issues reports issue summary", (t) => {
97
91
  const lines = buildHealthLines(activeData({
98
92
  providerIssue: "✗ OpenAI key missing",
99
93
  environmentErrorCount: 1,
@@ -104,17 +98,15 @@ test("buildHealthLines: active state with issues reports issue summary", () => {
104
98
  assert.match(lines[0]!, /Env: 1 error/);
105
99
  });
106
100
 
107
- test("detectHealthWidgetProjectState: metrics file alone does not imply project", () => {
101
+ test("detectHealthWidgetProjectState: metrics file alone does not imply project", (t) => {
108
102
  const dir = makeTempDir("metrics-only");
109
- try {
110
- mkdirSync(join(dir, ".gsd"), { recursive: true });
111
- writeFileSync(
112
- join(dir, ".gsd", "metrics.json"),
113
- JSON.stringify({ version: 1, projectStartedAt: Date.now(), units: [] }),
114
- "utf-8",
115
- );
116
- assert.equal(detectHealthWidgetProjectState(dir), "initialized");
117
- } finally {
118
- cleanup(dir);
119
- }
103
+ t.after(() => { cleanup(dir); });
104
+
105
+ mkdirSync(join(dir, ".gsd"), { recursive: true });
106
+ writeFileSync(
107
+ join(dir, ".gsd", "metrics.json"),
108
+ JSON.stringify({ version: 1, projectStartedAt: Date.now(), units: [] }),
109
+ "utf-8",
110
+ );
111
+ assert.equal(detectHealthWidgetProjectState(dir), "initialized");
120
112
  });
@@ -8,9 +8,9 @@ import {
8
8
  verifyExpectedArtifact,
9
9
  buildLoopRemediationSteps,
10
10
  } from "../auto.ts";
11
- import { createTestContext } from './test-helpers.ts';
11
+ import { describe, test, beforeEach, afterEach } from 'node:test';
12
+ import assert from 'node:assert/strict';
12
13
 
13
- const { assertEq, assertTrue, report } = createTestContext();
14
14
  function createFixtureBase(): string {
15
15
  const base = mkdtempSync(join(tmpdir(), "gsd-idle-recovery-test-"));
16
16
  mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks"), { recursive: true });
@@ -23,99 +23,91 @@ function cleanup(base: string): void {
23
23
 
24
24
  // ═══ resolveExpectedArtifactPath ═════════════════════════════════════════════
25
25
 
26
- {
27
- console.log("\n=== resolveExpectedArtifactPath: research-milestone ===");
26
+ test('resolveExpectedArtifactPath: research-milestone', () => {
28
27
  const base = createFixtureBase();
29
28
  try {
30
29
  const result = resolveExpectedArtifactPath("research-milestone", "M001", base);
31
- assertTrue(result !== null, "should resolve a path");
32
- assertTrue(result!.endsWith("M001-RESEARCH.md"), `path should end with M001-RESEARCH.md, got ${result}`);
30
+ assert.ok(result !== null, "should resolve a path");
31
+ assert.ok(result!.endsWith("M001-RESEARCH.md"), `path should end with M001-RESEARCH.md, got ${result}`);
33
32
  } finally {
34
33
  cleanup(base);
35
34
  }
36
- }
35
+ });
37
36
 
38
- {
39
- console.log("\n=== resolveExpectedArtifactPath: plan-milestone ===");
37
+ test('resolveExpectedArtifactPath: plan-milestone', () => {
40
38
  const base = createFixtureBase();
41
39
  try {
42
40
  const result = resolveExpectedArtifactPath("plan-milestone", "M001", base);
43
- assertTrue(result !== null, "should resolve a path");
44
- assertTrue(result!.endsWith("M001-ROADMAP.md"), `path should end with M001-ROADMAP.md, got ${result}`);
41
+ assert.ok(result !== null, "should resolve a path");
42
+ assert.ok(result!.endsWith("M001-ROADMAP.md"), `path should end with M001-ROADMAP.md, got ${result}`);
45
43
  } finally {
46
44
  cleanup(base);
47
45
  }
48
- }
46
+ });
49
47
 
50
- {
51
- console.log("\n=== resolveExpectedArtifactPath: research-slice ===");
48
+ test('resolveExpectedArtifactPath: research-slice', () => {
52
49
  const base = createFixtureBase();
53
50
  try {
54
51
  const result = resolveExpectedArtifactPath("research-slice", "M001/S01", base);
55
- assertTrue(result !== null, "should resolve a path");
56
- assertTrue(result!.endsWith("S01-RESEARCH.md"), `path should end with S01-RESEARCH.md, got ${result}`);
52
+ assert.ok(result !== null, "should resolve a path");
53
+ assert.ok(result!.endsWith("S01-RESEARCH.md"), `path should end with S01-RESEARCH.md, got ${result}`);
57
54
  } finally {
58
55
  cleanup(base);
59
56
  }
60
- }
57
+ });
61
58
 
62
- {
63
- console.log("\n=== resolveExpectedArtifactPath: plan-slice ===");
59
+ test('resolveExpectedArtifactPath: plan-slice', () => {
64
60
  const base = createFixtureBase();
65
61
  try {
66
62
  const result = resolveExpectedArtifactPath("plan-slice", "M001/S01", base);
67
- assertTrue(result !== null, "should resolve a path");
68
- assertTrue(result!.endsWith("S01-PLAN.md"), `path should end with S01-PLAN.md, got ${result}`);
63
+ assert.ok(result !== null, "should resolve a path");
64
+ assert.ok(result!.endsWith("S01-PLAN.md"), `path should end with S01-PLAN.md, got ${result}`);
69
65
  } finally {
70
66
  cleanup(base);
71
67
  }
72
- }
68
+ });
73
69
 
74
- {
75
- console.log("\n=== resolveExpectedArtifactPath: complete-milestone ===");
70
+ test('resolveExpectedArtifactPath: complete-milestone', () => {
76
71
  const base = createFixtureBase();
77
72
  try {
78
73
  const result = resolveExpectedArtifactPath("complete-milestone", "M001", base);
79
- assertTrue(result !== null, "should resolve a path");
80
- assertTrue(result!.endsWith("M001-SUMMARY.md"), `path should end with M001-SUMMARY.md, got ${result}`);
74
+ assert.ok(result !== null, "should resolve a path");
75
+ assert.ok(result!.endsWith("M001-SUMMARY.md"), `path should end with M001-SUMMARY.md, got ${result}`);
81
76
  } finally {
82
77
  cleanup(base);
83
78
  }
84
- }
79
+ });
85
80
 
86
- {
87
- console.log("\n=== resolveExpectedArtifactPath: unknown unit type → null ===");
81
+ test('resolveExpectedArtifactPath: unknown unit type → null', () => {
88
82
  const base = createFixtureBase();
89
83
  try {
90
84
  const result = resolveExpectedArtifactPath("unknown-type", "M001/S01", base);
91
- assertEq(result, null, "unknown type returns null");
85
+ assert.deepStrictEqual(result, null, "unknown type returns null");
92
86
  } finally {
93
87
  cleanup(base);
94
88
  }
95
- }
89
+ });
96
90
 
97
91
  // ═══ writeBlockerPlaceholder ═════════════════════════════════════════════════
98
92
 
99
- {
100
- console.log("\n=== writeBlockerPlaceholder: writes file for research-slice ===");
93
+ test('writeBlockerPlaceholder: writes file for research-slice', () => {
101
94
  const base = createFixtureBase();
102
95
  try {
103
96
  const result = writeBlockerPlaceholder("research-slice", "M001/S01", base, "idle recovery exhausted 2 attempts");
104
- assertTrue(result !== null, "should return relative path");
97
+ assert.ok(result !== null, "should return relative path");
105
98
  const absPath = resolveExpectedArtifactPath("research-slice", "M001/S01", base)!;
106
- assertTrue(existsSync(absPath), "file should exist on disk");
99
+ assert.ok(existsSync(absPath), "file should exist on disk");
107
100
  const content = readFileSync(absPath, "utf-8");
108
- assertTrue(content.includes("BLOCKER"), "should contain BLOCKER heading");
109
- assertTrue(content.includes("idle recovery exhausted 2 attempts"), "should contain the reason");
110
- assertTrue(content.includes("research-slice"), "should mention the unit type");
111
- assertTrue(content.includes("M001/S01"), "should mention the unit ID");
101
+ assert.ok(content.includes("BLOCKER"), "should contain BLOCKER heading");
102
+ assert.ok(content.includes("idle recovery exhausted 2 attempts"), "should contain the reason");
103
+ assert.ok(content.includes("research-slice"), "should mention the unit type");
104
+ assert.ok(content.includes("M001/S01"), "should mention the unit ID");
112
105
  } finally {
113
106
  cleanup(base);
114
107
  }
115
- }
108
+ });
116
109
 
117
- {
118
- console.log("\n=== writeBlockerPlaceholder: creates directory if missing ===");
110
+ test('writeBlockerPlaceholder: creates directory if missing', () => {
119
111
  const base = mkdtempSync(join(tmpdir(), "gsd-idle-recovery-test-"));
120
112
  try {
121
113
  // Only create milestone dir, not slice dir
@@ -123,38 +115,36 @@ function cleanup(base: string): void {
123
115
  // resolveSlicePath needs the slice dir to exist to resolve, so this should return null
124
116
  const result = writeBlockerPlaceholder("research-slice", "M001/S01", base, "test reason");
125
117
  // Since the slice dir doesn't exist, resolveExpectedArtifactPath returns null
126
- assertEq(result, null, "returns null when directory structure doesn't exist");
118
+ assert.deepStrictEqual(result, null, "returns null when directory structure doesn't exist");
127
119
  } finally {
128
120
  cleanup(base);
129
121
  }
130
- }
122
+ });
131
123
 
132
- {
133
- console.log("\n=== writeBlockerPlaceholder: writes file for research-milestone ===");
124
+ test('writeBlockerPlaceholder: writes file for research-milestone', () => {
134
125
  const base = createFixtureBase();
135
126
  try {
136
127
  const result = writeBlockerPlaceholder("research-milestone", "M001", base, "hard timeout");
137
- assertTrue(result !== null, "should return relative path");
128
+ assert.ok(result !== null, "should return relative path");
138
129
  const absPath = resolveExpectedArtifactPath("research-milestone", "M001", base)!;
139
- assertTrue(existsSync(absPath), "file should exist on disk");
130
+ assert.ok(existsSync(absPath), "file should exist on disk");
140
131
  const content = readFileSync(absPath, "utf-8");
141
- assertTrue(content.includes("BLOCKER"), "should contain BLOCKER heading");
142
- assertTrue(content.includes("hard timeout"), "should contain the reason");
132
+ assert.ok(content.includes("BLOCKER"), "should contain BLOCKER heading");
133
+ assert.ok(content.includes("hard timeout"), "should contain the reason");
143
134
  } finally {
144
135
  cleanup(base);
145
136
  }
146
- }
137
+ });
147
138
 
148
- {
149
- console.log("\n=== writeBlockerPlaceholder: unknown type → null ===");
139
+ test('writeBlockerPlaceholder: unknown type → null', () => {
150
140
  const base = createFixtureBase();
151
141
  try {
152
142
  const result = writeBlockerPlaceholder("unknown-type", "M001/S01", base, "test");
153
- assertEq(result, null, "unknown type returns null");
143
+ assert.deepStrictEqual(result, null, "unknown type returns null");
154
144
  } finally {
155
145
  cleanup(base);
156
146
  }
157
- }
147
+ });
158
148
 
159
149
  // ═══ verifyExpectedArtifact: complete-slice roadmap check ════════════════════
160
150
  // Regression for #indefinite-hang: complete-slice must verify roadmap [x] or
@@ -177,8 +167,7 @@ const ROADMAP_COMPLETE = `# M001: Test Milestone
177
167
  > After this: something works
178
168
  `;
179
169
 
180
- {
181
- console.log("\n=== verifyExpectedArtifact: complete-slice — all artifacts present + roadmap marked [x] returns true ===");
170
+ test('verifyExpectedArtifact: complete-slice — all artifacts present + roadmap marked [x] returns true', () => {
182
171
  const base = createFixtureBase();
183
172
  try {
184
173
  const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
@@ -186,14 +175,13 @@ const ROADMAP_COMPLETE = `# M001: Test Milestone
186
175
  writeFileSync(join(sliceDir, "S01-UAT.md"), "# UAT\n", "utf-8");
187
176
  writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), ROADMAP_COMPLETE, "utf-8");
188
177
  const result = verifyExpectedArtifact("complete-slice", "M001/S01", base);
189
- assertTrue(result === true, "SUMMARY + UAT + roadmap [x] should verify as true");
178
+ assert.ok(result === true, "SUMMARY + UAT + roadmap [x] should verify as true");
190
179
  } finally {
191
180
  cleanup(base);
192
181
  }
193
- }
182
+ });
194
183
 
195
- {
196
- console.log("\n=== verifyExpectedArtifact: complete-slice — SUMMARY + UAT present but roadmap NOT marked [x] returns false ===");
184
+ test('verifyExpectedArtifact: complete-slice — SUMMARY + UAT present but roadmap NOT marked [x] returns false', () => {
197
185
  const base = createFixtureBase();
198
186
  try {
199
187
  const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
@@ -201,14 +189,13 @@ const ROADMAP_COMPLETE = `# M001: Test Milestone
201
189
  writeFileSync(join(sliceDir, "S01-UAT.md"), "# UAT\n", "utf-8");
202
190
  writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), ROADMAP_INCOMPLETE, "utf-8");
203
191
  const result = verifyExpectedArtifact("complete-slice", "M001/S01", base);
204
- assertTrue(result === false, "roadmap not marked [x] should return false (crash recovery scenario)");
192
+ assert.ok(result === false, "roadmap not marked [x] should return false (crash recovery scenario)");
205
193
  } finally {
206
194
  cleanup(base);
207
195
  }
208
- }
196
+ });
209
197
 
210
- {
211
- console.log("\n=== verifyExpectedArtifact: complete-slice — SUMMARY present but UAT missing returns false ===");
198
+ test('verifyExpectedArtifact: complete-slice — SUMMARY present but UAT missing returns false', () => {
212
199
  const base = createFixtureBase();
213
200
  try {
214
201
  const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
@@ -216,14 +203,13 @@ const ROADMAP_COMPLETE = `# M001: Test Milestone
216
203
  // no UAT file
217
204
  writeFileSync(join(base, ".gsd", "milestones", "M001", "M001-ROADMAP.md"), ROADMAP_COMPLETE, "utf-8");
218
205
  const result = verifyExpectedArtifact("complete-slice", "M001/S01", base);
219
- assertTrue(result === false, "missing UAT should return false");
206
+ assert.ok(result === false, "missing UAT should return false");
220
207
  } finally {
221
208
  cleanup(base);
222
209
  }
223
- }
210
+ });
224
211
 
225
- {
226
- console.log("\n=== verifyExpectedArtifact: complete-slice — no roadmap file present is lenient (returns true) ===");
212
+ test('verifyExpectedArtifact: complete-slice — no roadmap file present is lenient (returns true)', () => {
227
213
  const base = createFixtureBase();
228
214
  try {
229
215
  const sliceDir = join(base, ".gsd", "milestones", "M001", "slices", "S01");
@@ -231,87 +217,80 @@ const ROADMAP_COMPLETE = `# M001: Test Milestone
231
217
  writeFileSync(join(sliceDir, "S01-UAT.md"), "# UAT\n", "utf-8");
232
218
  // no roadmap file
233
219
  const result = verifyExpectedArtifact("complete-slice", "M001/S01", base);
234
- assertTrue(result === true, "missing roadmap file should be lenient and return true");
220
+ assert.ok(result === true, "missing roadmap file should be lenient and return true");
235
221
  } finally {
236
222
  cleanup(base);
237
223
  }
238
- }
224
+ });
239
225
 
240
226
  // ═══ buildLoopRemediationSteps ═══════════════════════════════════════════════
241
227
 
242
- {
243
- console.log("\n=== buildLoopRemediationSteps: execute-task returns concrete steps ===");
228
+ test('buildLoopRemediationSteps: execute-task returns concrete steps', () => {
244
229
  const base = mkdtempSync(join(tmpdir(), "gsd-loop-remediation-test-"));
245
230
  try {
246
231
  mkdirSync(join(base, ".gsd", "milestones", "M002", "slices", "S03", "tasks"), { recursive: true });
247
232
  const result = buildLoopRemediationSteps("execute-task", "M002/S03/T01", base);
248
- assertTrue(result !== null, "should return remediation steps");
249
- assertTrue(result!.includes("gsd undo-task"), "steps include undo-task command");
250
- assertTrue(result!.includes("T01"), "steps mention the task ID");
251
- assertTrue(result!.includes("gsd undo-task"), "steps include gsd undo-task command");
233
+ assert.ok(result !== null, "should return remediation steps");
234
+ assert.ok(result!.includes("gsd undo-task"), "steps include undo-task command");
235
+ assert.ok(result!.includes("T01"), "steps mention the task ID");
236
+ assert.ok(result!.includes("gsd undo-task"), "steps include gsd undo-task command");
252
237
  } finally {
253
238
  rmSync(base, { recursive: true, force: true });
254
239
  }
255
- }
240
+ });
256
241
 
257
- {
258
- console.log("\n=== buildLoopRemediationSteps: plan-slice returns concrete steps ===");
242
+ test('buildLoopRemediationSteps: plan-slice returns concrete steps', () => {
259
243
  const base = mkdtempSync(join(tmpdir(), "gsd-loop-remediation-test-"));
260
244
  try {
261
245
  mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01"), { recursive: true });
262
246
  const result = buildLoopRemediationSteps("plan-slice", "M001/S01", base);
263
- assertTrue(result !== null, "should return remediation steps for plan-slice");
264
- assertTrue(result!.includes("S01-PLAN.md"), "steps mention the slice plan file");
265
- assertTrue(result!.includes("gsd recover"), "steps include gsd recover command");
247
+ assert.ok(result !== null, "should return remediation steps for plan-slice");
248
+ assert.ok(result!.includes("S01-PLAN.md"), "steps mention the slice plan file");
249
+ assert.ok(result!.includes("gsd recover"), "steps include gsd recover command");
266
250
  } finally {
267
251
  rmSync(base, { recursive: true, force: true });
268
252
  }
269
- }
253
+ });
270
254
 
271
- {
272
- console.log("\n=== buildLoopRemediationSteps: research-slice returns concrete steps ===");
255
+ test('buildLoopRemediationSteps: research-slice returns concrete steps', () => {
273
256
  const base = mkdtempSync(join(tmpdir(), "gsd-loop-remediation-test-"));
274
257
  try {
275
258
  mkdirSync(join(base, ".gsd", "milestones", "M001", "slices", "S01"), { recursive: true });
276
259
  const result = buildLoopRemediationSteps("research-slice", "M001/S01", base);
277
- assertTrue(result !== null, "should return remediation steps for research-slice");
278
- assertTrue(result!.includes("S01-RESEARCH.md"), "steps mention the slice research file");
279
- assertTrue(result!.includes("gsd recover"), "steps include gsd recover command");
260
+ assert.ok(result !== null, "should return remediation steps for research-slice");
261
+ assert.ok(result!.includes("S01-RESEARCH.md"), "steps mention the slice research file");
262
+ assert.ok(result!.includes("gsd recover"), "steps include gsd recover command");
280
263
  } finally {
281
264
  rmSync(base, { recursive: true, force: true });
282
265
  }
283
- }
266
+ });
284
267
 
285
- {
286
- console.log("\n=== buildLoopRemediationSteps: unknown type returns null ===");
268
+ test('buildLoopRemediationSteps: unknown type returns null', () => {
287
269
  const base = mkdtempSync(join(tmpdir(), "gsd-loop-remediation-test-"));
288
270
  try {
289
271
  const result = buildLoopRemediationSteps("unknown-type", "M001/S01", base);
290
- assertEq(result, null, "unknown type returns null");
272
+ assert.deepStrictEqual(result, null, "unknown type returns null");
291
273
  } finally {
292
274
  rmSync(base, { recursive: true, force: true });
293
275
  }
294
- }
276
+ });
295
277
 
296
278
  // ═══ verifyExpectedArtifact: hook unit types ═════════════════════════════════
297
279
 
298
- console.log("\n=== verifyExpectedArtifact: hook types always return true ===");
299
-
300
- {
280
+ test('verifyExpectedArtifact: hook types always return true', () => {
301
281
  const base = createFixtureBase();
302
282
  try {
303
283
  // Hook units don't have standard artifacts — they should always pass
304
284
  const result1 = verifyExpectedArtifact("hook/code-review", "M001/S01/T01", base);
305
- assertTrue(result1, "hook/code-review should always return true");
285
+ assert.ok(result1, "hook/code-review should always return true");
306
286
 
307
287
  const result2 = verifyExpectedArtifact("hook/simplify", "M001/S01/T02", base);
308
- assertTrue(result2, "hook/simplify should always return true");
288
+ assert.ok(result2, "hook/simplify should always return true");
309
289
 
310
290
  const result3 = verifyExpectedArtifact("hook/custom-hook", "M001/S01", base);
311
- assertTrue(result3, "hook/custom-hook at slice level should return true");
291
+ assert.ok(result3, "hook/custom-hook at slice level should return true");
312
292
  } finally {
313
293
  rmSync(base, { recursive: true, force: true });
314
294
  }
315
- }
295
+ });
316
296
 
317
- report();
@@ -7,10 +7,13 @@ import { isInfrastructureError, INFRA_ERROR_CODES } from "../auto/infra-errors.j
7
7
  // ── INFRA_ERROR_CODES constant ───────────────────────────────────────────────
8
8
 
9
9
  test("INFRA_ERROR_CODES contains the expected codes", () => {
10
- for (const code of ["ENOSPC", "ENOMEM", "EROFS", "EDQUOT", "EMFILE", "ENFILE"]) {
10
+ for (const code of [
11
+ "ENOSPC", "ENOMEM", "EROFS", "EDQUOT", "EMFILE", "ENFILE",
12
+ "ECONNREFUSED", "ENOTFOUND", "ENETUNREACH",
13
+ ]) {
11
14
  assert.ok(INFRA_ERROR_CODES.has(code), `missing ${code}`);
12
15
  }
13
- assert.equal(INFRA_ERROR_CODES.size, 6, "unexpected extra codes");
16
+ assert.equal(INFRA_ERROR_CODES.size, 9, "unexpected extra codes");
14
17
  });
15
18
 
16
19
  // ── isInfrastructureError: code property detection ───────────────────────────
@@ -45,6 +48,21 @@ test("detects ENFILE via code property", () => {
45
48
  assert.equal(isInfrastructureError(err), "ENFILE");
46
49
  });
47
50
 
51
+ test("detects ECONNREFUSED via code property", () => {
52
+ const err = Object.assign(new Error("connect ECONNREFUSED 127.0.0.1:3000"), { code: "ECONNREFUSED" });
53
+ assert.equal(isInfrastructureError(err), "ECONNREFUSED");
54
+ });
55
+
56
+ test("detects ENOTFOUND via code property", () => {
57
+ const err = Object.assign(new Error("getaddrinfo ENOTFOUND api.example.com"), { code: "ENOTFOUND" });
58
+ assert.equal(isInfrastructureError(err), "ENOTFOUND");
59
+ });
60
+
61
+ test("detects ENETUNREACH via code property", () => {
62
+ const err = Object.assign(new Error("connect ENETUNREACH 2607:f8b0:4004::"), { code: "ENETUNREACH" });
63
+ assert.equal(isInfrastructureError(err), "ENETUNREACH");
64
+ });
65
+
48
66
  // ── isInfrastructureError: message fallback ──────────────────────────────────
49
67
 
50
68
  test("falls back to message scanning when no code property", () => {
@@ -36,19 +36,17 @@ function cleanup(dir: string): void {
36
36
 
37
37
  // ─── Detection Integration Tests ────────────────────────────────────────────────
38
38
 
39
- test("init-wizard: clean folder detected as state=none", () => {
39
+ test("init-wizard: clean folder detected as state=none", (t) => {
40
40
  const dir = makeTempDir("clean");
41
- try {
42
- const detection = detectProjectState(dir);
43
- assert.equal(detection.state, "none");
44
- assert.equal(detection.v1, undefined);
45
- assert.equal(detection.v2, undefined);
46
- } finally {
47
- cleanup(dir);
48
- }
41
+ t.after(() => { cleanup(dir); });
42
+
43
+ const detection = detectProjectState(dir);
44
+ assert.equal(detection.state, "none");
45
+ assert.equal(detection.v1, undefined);
46
+ assert.equal(detection.v2, undefined);
49
47
  });
50
48
 
51
- test("init-wizard: v1 .planning/ triggers v1-planning state", () => {
49
+ test("init-wizard: v1 .planning/ triggers v1-planning state", (t) => {
52
50
  const dir = makeTempDir("v1");
53
51
  try {
54
52
  mkdirSync(join(dir, ".planning", "phases", "01"), { recursive: true });
@@ -65,7 +63,7 @@ test("init-wizard: v1 .planning/ triggers v1-planning state", () => {
65
63
  }
66
64
  });
67
65
 
68
- test("init-wizard: existing .gsd/ with milestones skips init", () => {
66
+ test("init-wizard: existing .gsd/ with milestones skips init", (t) => {
69
67
  const dir = makeTempDir("existing");
70
68
  try {
71
69
  mkdirSync(join(dir, ".gsd", "milestones", "M001"), { recursive: true });
@@ -80,7 +78,7 @@ test("init-wizard: existing .gsd/ with milestones skips init", () => {
80
78
  }
81
79
  });
82
80
 
83
- test("init-wizard: empty .gsd/ (no milestones) returns v2-gsd-empty", () => {
81
+ test("init-wizard: empty .gsd/ (no milestones) returns v2-gsd-empty", (t) => {
84
82
  const dir = makeTempDir("empty-gsd");
85
83
  try {
86
84
  mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
@@ -94,7 +92,7 @@ test("init-wizard: empty .gsd/ (no milestones) returns v2-gsd-empty", () => {
94
92
  }
95
93
  });
96
94
 
97
- test("init-wizard: project signals populate from Node.js project", () => {
95
+ test("init-wizard: project signals populate from Node.js project", (t) => {
98
96
  const dir = makeTempDir("node-project");
99
97
  try {
100
98
  writeFileSync(
@@ -121,7 +119,7 @@ test("init-wizard: project signals populate from Node.js project", () => {
121
119
  }
122
120
  });
123
121
 
124
- test("init-wizard: v2 .gsd/ preferences detected", () => {
122
+ test("init-wizard: v2 .gsd/ preferences detected", (t) => {
125
123
  const dir = makeTempDir("prefs-detect");
126
124
  try {
127
125
  mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
@@ -135,7 +133,7 @@ test("init-wizard: v2 .gsd/ preferences detected", () => {
135
133
  }
136
134
  });
137
135
 
138
- test("init-wizard: v2 uppercase PREFERENCES.md also detected", () => {
136
+ test("init-wizard: v2 uppercase PREFERENCES.md also detected", (t) => {
139
137
  const dir = makeTempDir("prefs-upper");
140
138
  try {
141
139
  mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
@@ -149,7 +147,7 @@ test("init-wizard: v2 uppercase PREFERENCES.md also detected", () => {
149
147
  }
150
148
  });
151
149
 
152
- test("init-wizard: CONTEXT.md detected in v2", () => {
150
+ test("init-wizard: CONTEXT.md detected in v2", (t) => {
153
151
  const dir = makeTempDir("context");
154
152
  try {
155
153
  mkdirSync(join(dir, ".gsd", "milestones"), { recursive: true });
@@ -163,7 +161,7 @@ test("init-wizard: CONTEXT.md detected in v2", () => {
163
161
  }
164
162
  });
165
163
 
166
- test("init-wizard: multiple project files detected together", () => {
164
+ test("init-wizard: multiple project files detected together", (t) => {
167
165
  const dir = makeTempDir("multi-files");
168
166
  try {
169
167
  writeFileSync(join(dir, "package.json"), JSON.stringify({ name: "test" }), "utf-8");
@@ -180,7 +178,7 @@ test("init-wizard: multiple project files detected together", () => {
180
178
  }
181
179
  });
182
180
 
183
- test("init-wizard: v1 with both .planning/ and .gsd/ prioritizes v2", () => {
181
+ test("init-wizard: v1 with both .planning/ and .gsd/ prioritizes v2", (t) => {
184
182
  const dir = makeTempDir("both-v1-v2");
185
183
  try {
186
184
  mkdirSync(join(dir, ".planning", "phases"), { recursive: true });