gsd-pi 2.44.0 → 2.45.0-dev.e0ee972

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 (505) hide show
  1. package/README.md +30 -12
  2. package/dist/help-text.js +1 -1
  3. package/dist/loader.js +34 -0
  4. package/dist/resources/extensions/gsd/activity-log.js +7 -0
  5. package/dist/resources/extensions/gsd/auto/infra-errors.js +3 -0
  6. package/dist/resources/extensions/gsd/auto/phases.js +52 -45
  7. package/dist/resources/extensions/gsd/auto/run-unit.js +6 -3
  8. package/dist/resources/extensions/gsd/auto-prompts.js +24 -1
  9. package/dist/resources/extensions/gsd/auto-start.js +31 -2
  10. package/dist/resources/extensions/gsd/auto-timers.js +57 -3
  11. package/dist/resources/extensions/gsd/auto-worktree-sync.js +4 -0
  12. package/dist/resources/extensions/gsd/auto-worktree.js +14 -10
  13. package/dist/resources/extensions/gsd/auto.js +34 -8
  14. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +168 -11
  15. package/dist/resources/extensions/gsd/bootstrap/system-context.js +46 -12
  16. package/dist/resources/extensions/gsd/commands/catalog.js +7 -1
  17. package/dist/resources/extensions/gsd/commands/handlers/core.js +2 -0
  18. package/dist/resources/extensions/gsd/commands/handlers/ops.js +10 -0
  19. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +5 -0
  20. package/dist/resources/extensions/gsd/commands-mcp-status.js +187 -0
  21. package/dist/resources/extensions/gsd/db-writer.js +40 -22
  22. package/dist/resources/extensions/gsd/doctor-checks.js +1 -1
  23. package/dist/resources/extensions/gsd/doctor.js +10 -2
  24. package/dist/resources/extensions/gsd/git-service.js +8 -3
  25. package/dist/resources/extensions/gsd/gsd-db.js +17 -2
  26. package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
  27. package/dist/resources/extensions/gsd/preferences-types.js +2 -2
  28. package/dist/resources/extensions/gsd/preferences.js +17 -5
  29. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
  30. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  31. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  32. package/dist/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  33. package/dist/resources/extensions/gsd/prompts/rethink.md +78 -0
  34. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  35. package/dist/resources/extensions/gsd/provider-error-pause.js +7 -0
  36. package/dist/resources/extensions/gsd/repo-identity.js +45 -7
  37. package/dist/resources/extensions/gsd/rethink.js +115 -0
  38. package/dist/resources/extensions/gsd/state.js +41 -3
  39. package/dist/resources/extensions/gsd/tools/plan-slice.js +1 -0
  40. package/dist/resources/extensions/gsd/tools/plan-task.js +1 -0
  41. package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -0
  42. package/dist/resources/extensions/gsd/tools/validate-milestone.js +88 -0
  43. package/dist/resources/extensions/gsd/workflow-logger.js +138 -0
  44. package/dist/resources/extensions/gsd/worktree-manager.js +34 -3
  45. package/dist/resources/extensions/gsd/worktree-resolver.js +43 -0
  46. package/dist/resources/extensions/mcp-client/index.js +14 -0
  47. package/dist/resources/extensions/voice/index.js +11 -16
  48. package/dist/resources/extensions/voice/linux-ready.js +67 -0
  49. package/dist/web/standalone/.next/BUILD_ID +1 -1
  50. package/dist/web/standalone/.next/app-path-routes-manifest.json +15 -15
  51. package/dist/web/standalone/.next/build-manifest.json +4 -4
  52. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  53. package/dist/web/standalone/.next/react-loadable-manifest.json +2 -2
  54. package/dist/web/standalone/.next/required-server-files.json +3 -3
  55. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  56. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  58. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  66. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found.rsc +5 -5
  69. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +5 -5
  70. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  74. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  75. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  82. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  108. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  120. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  126. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  140. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  142. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  144. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  146. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/index.html +1 -1
  156. package/dist/web/standalone/.next/server/app/index.rsc +6 -6
  157. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  158. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +6 -6
  159. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  160. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +4 -4
  161. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  162. package/dist/web/standalone/.next/server/app/page.js +2 -2
  163. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app-paths-manifest.json +15 -15
  165. package/dist/web/standalone/.next/server/chunks/229.js +1 -1
  166. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  167. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/middleware.js +2 -2
  170. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  172. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  173. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  174. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  175. package/dist/web/standalone/.next/static/chunks/4024.11ca5c01938e5948.js +9 -0
  176. package/dist/web/standalone/.next/static/chunks/{3721.bf31263de6d5fa46.js → 485.243af25f0cdf50d6.js} +2 -2
  177. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  178. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  179. package/dist/web/standalone/.next/static/chunks/app/page-6654a8cca61a3d1c.js +1 -0
  180. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  181. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  182. package/dist/web/standalone/.next/static/chunks/webpack-0a4cd455ec4197d2.js +1 -0
  183. package/dist/web/standalone/.next/static/css/dd4ae3f58ac9b600.css +1 -0
  184. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  185. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  186. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  187. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  188. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  189. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  190. package/dist/web/standalone/server.js +1 -1
  191. package/package.json +1 -1
  192. package/packages/native/dist/stream-process/index.js +2 -2
  193. package/packages/native/src/__tests__/stream-process.test.mjs +34 -0
  194. package/packages/native/src/stream-process/index.ts +2 -2
  195. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +3 -1
  196. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  197. package/packages/pi-coding-agent/dist/core/auth-storage.js +15 -1
  198. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  199. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +6 -8
  200. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  201. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +2 -0
  203. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js +24 -26
  205. package/packages/pi-coding-agent/dist/core/extensions/runner.test.js.map +1 -1
  206. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +2 -1
  207. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  208. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  209. package/packages/pi-coding-agent/dist/core/fs-utils.test.js +29 -48
  210. package/packages/pi-coding-agent/dist/core/fs-utils.test.js.map +1 -1
  211. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +4 -0
  212. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -1
  213. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +10 -5
  214. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -1
  215. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts +2 -0
  216. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.d.ts.map +1 -0
  217. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js +185 -0
  218. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.test.js.map +1 -0
  219. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +15 -0
  220. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +1 -0
  221. package/packages/pi-coding-agent/dist/core/local-model-check.js +41 -0
  222. package/packages/pi-coding-agent/dist/core/local-model-check.js.map +1 -0
  223. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +239 -10
  224. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  225. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +13 -1
  226. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  227. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  228. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  229. package/packages/pi-coding-agent/dist/core/package-commands.test.js +206 -195
  230. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -1
  231. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js +34 -44
  232. package/packages/pi-coding-agent/dist/core/resolve-config-value.test.js.map +1 -1
  233. package/packages/pi-coding-agent/dist/core/session-manager.test.js +30 -34
  234. package/packages/pi-coding-agent/dist/core/session-manager.test.js.map +1 -1
  235. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  236. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  237. package/packages/pi-coding-agent/dist/core/settings-manager.js +6 -0
  238. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  239. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js +10 -12
  240. package/packages/pi-coding-agent/dist/core/tools/edit-diff.test.js.map +1 -1
  241. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  242. package/packages/pi-coding-agent/dist/main.js +17 -0
  243. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  244. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +2 -0
  245. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +1 -0
  246. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +32 -0
  247. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +1 -0
  248. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +3 -1
  249. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  250. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +8 -1
  251. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  252. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  253. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  254. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +12 -0
  255. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  256. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +15 -0
  257. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +1 -0
  258. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +40 -0
  259. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +1 -0
  260. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  261. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +4 -1
  262. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  263. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +5 -2
  264. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  265. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +13 -2
  266. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  267. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  268. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +17 -8
  269. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  270. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  271. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +7 -3
  272. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  273. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js +43 -47
  274. package/packages/pi-coding-agent/dist/resources/extensions/memory/storage.test.js.map +1 -1
  275. package/packages/pi-coding-agent/package.json +1 -1
  276. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +7 -7
  277. package/packages/pi-coding-agent/src/core/auth-storage.ts +15 -1
  278. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +2 -0
  279. package/packages/pi-coding-agent/src/core/extensions/runner.test.ts +26 -26
  280. package/packages/pi-coding-agent/src/core/extensions/types.ts +2 -1
  281. package/packages/pi-coding-agent/src/core/fs-utils.test.ts +31 -43
  282. package/packages/pi-coding-agent/src/core/lifecycle-hooks.test.ts +227 -0
  283. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +11 -5
  284. package/packages/pi-coding-agent/src/core/local-model-check.ts +45 -0
  285. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +297 -11
  286. package/packages/pi-coding-agent/src/core/model-registry.ts +51 -4
  287. package/packages/pi-coding-agent/src/core/package-commands.test.ts +227 -205
  288. package/packages/pi-coding-agent/src/core/resolve-config-value.test.ts +40 -45
  289. package/packages/pi-coding-agent/src/core/session-manager.test.ts +33 -33
  290. package/packages/pi-coding-agent/src/core/settings-manager.ts +9 -0
  291. package/packages/pi-coding-agent/src/core/tools/edit-diff.test.ts +17 -17
  292. package/packages/pi-coding-agent/src/main.ts +19 -0
  293. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +38 -0
  294. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +10 -0
  295. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +15 -0
  296. package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +48 -0
  297. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +3 -1
  298. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +18 -3
  299. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +16 -7
  300. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +8 -1
  301. package/packages/pi-coding-agent/src/resources/extensions/memory/storage.test.ts +74 -74
  302. package/pkg/package.json +1 -1
  303. package/src/resources/extensions/gsd/activity-log.ts +1 -0
  304. package/src/resources/extensions/gsd/auto/infra-errors.ts +3 -0
  305. package/src/resources/extensions/gsd/auto/phases.ts +61 -59
  306. package/src/resources/extensions/gsd/auto/run-unit.ts +6 -3
  307. package/src/resources/extensions/gsd/auto-prompts.ts +24 -1
  308. package/src/resources/extensions/gsd/auto-start.ts +39 -2
  309. package/src/resources/extensions/gsd/auto-timers.ts +64 -3
  310. package/src/resources/extensions/gsd/auto-worktree-sync.ts +5 -0
  311. package/src/resources/extensions/gsd/auto-worktree.ts +17 -11
  312. package/src/resources/extensions/gsd/auto.ts +40 -6
  313. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +160 -11
  314. package/src/resources/extensions/gsd/bootstrap/system-context.ts +48 -11
  315. package/src/resources/extensions/gsd/commands/catalog.ts +7 -1
  316. package/src/resources/extensions/gsd/commands/handlers/core.ts +2 -0
  317. package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
  318. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +8 -0
  319. package/src/resources/extensions/gsd/commands-mcp-status.ts +247 -0
  320. package/src/resources/extensions/gsd/db-writer.ts +41 -27
  321. package/src/resources/extensions/gsd/doctor-checks.ts +1 -1
  322. package/src/resources/extensions/gsd/doctor.ts +9 -3
  323. package/src/resources/extensions/gsd/git-service.ts +6 -2
  324. package/src/resources/extensions/gsd/gsd-db.ts +21 -2
  325. package/src/resources/extensions/gsd/journal.ts +6 -1
  326. package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
  327. package/src/resources/extensions/gsd/preferences-types.ts +2 -2
  328. package/src/resources/extensions/gsd/preferences.ts +18 -4
  329. package/src/resources/extensions/gsd/prompts/complete-milestone.md +2 -4
  330. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  331. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  332. package/src/resources/extensions/gsd/prompts/replan-slice.md +3 -14
  333. package/src/resources/extensions/gsd/prompts/rethink.md +78 -0
  334. package/src/resources/extensions/gsd/prompts/validate-milestone.md +7 -37
  335. package/src/resources/extensions/gsd/provider-error-pause.ts +9 -0
  336. package/src/resources/extensions/gsd/repo-identity.ts +46 -7
  337. package/src/resources/extensions/gsd/rethink.ts +154 -0
  338. package/src/resources/extensions/gsd/state.ts +41 -1
  339. package/src/resources/extensions/gsd/tests/all-milestones-complete-merge.test.ts +99 -99
  340. package/src/resources/extensions/gsd/tests/auto-lock-creation.test.ts +14 -16
  341. package/src/resources/extensions/gsd/tests/auto-paused-session-validation.test.ts +43 -57
  342. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +88 -0
  343. package/src/resources/extensions/gsd/tests/auto-preflight.test.ts +11 -13
  344. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +465 -523
  345. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +73 -75
  346. package/src/resources/extensions/gsd/tests/auto-start-needs-discussion.test.ts +34 -56
  347. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +533 -656
  348. package/src/resources/extensions/gsd/tests/auto-worktree.test.ts +165 -143
  349. package/src/resources/extensions/gsd/tests/cache-staleness-regression.test.ts +29 -52
  350. package/src/resources/extensions/gsd/tests/captures.test.ts +148 -176
  351. package/src/resources/extensions/gsd/tests/claude-import-tui.test.ts +32 -33
  352. package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +141 -143
  353. package/src/resources/extensions/gsd/tests/commands-inspect-open-db.test.ts +25 -25
  354. package/src/resources/extensions/gsd/tests/commands-logs.test.ts +81 -81
  355. package/src/resources/extensions/gsd/tests/complete-milestone.test.ts +38 -59
  356. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +228 -263
  357. package/src/resources/extensions/gsd/tests/complete-task.test.ts +250 -302
  358. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +114 -0
  359. package/src/resources/extensions/gsd/tests/context-store.test.ts +354 -367
  360. package/src/resources/extensions/gsd/tests/continue-here.test.ts +68 -72
  361. package/src/resources/extensions/gsd/tests/cost-projection.test.ts +92 -106
  362. package/src/resources/extensions/gsd/tests/crash-recovery.test.ts +27 -35
  363. package/src/resources/extensions/gsd/tests/dashboard-budget.test.ts +220 -237
  364. package/src/resources/extensions/gsd/tests/db-writer.test.ts +465 -416
  365. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +76 -92
  366. package/src/resources/extensions/gsd/tests/derive-state-crossval.test.ts +68 -83
  367. package/src/resources/extensions/gsd/tests/derive-state-db-disk-reconcile.test.ts +121 -0
  368. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +210 -181
  369. package/src/resources/extensions/gsd/tests/derive-state-deps.test.ts +78 -101
  370. package/src/resources/extensions/gsd/tests/derive-state.test.ts +192 -227
  371. package/src/resources/extensions/gsd/tests/detection.test.ts +232 -278
  372. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +30 -34
  373. package/src/resources/extensions/gsd/tests/dispatch-guard.test.ts +164 -180
  374. package/src/resources/extensions/gsd/tests/dispatch-missing-task-plans.test.ts +43 -49
  375. package/src/resources/extensions/gsd/tests/dispatch-uat-last-completed.test.ts +28 -32
  376. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +27 -29
  377. package/src/resources/extensions/gsd/tests/doctor-delimiter-fix.test.ts +34 -38
  378. package/src/resources/extensions/gsd/tests/doctor-enhancements.test.ts +54 -75
  379. package/src/resources/extensions/gsd/tests/doctor-environment-worktree.test.ts +21 -32
  380. package/src/resources/extensions/gsd/tests/doctor-environment.test.ts +72 -97
  381. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +38 -44
  382. package/src/resources/extensions/gsd/tests/doctor-git.test.ts +104 -145
  383. package/src/resources/extensions/gsd/tests/doctor-proactive.test.ts +84 -106
  384. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +54 -60
  385. package/src/resources/extensions/gsd/tests/doctor-runtime.test.ts +72 -93
  386. package/src/resources/extensions/gsd/tests/doctor.test.ts +104 -134
  387. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +123 -131
  388. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +120 -0
  389. package/src/resources/extensions/gsd/tests/exit-command.test.ts +20 -24
  390. package/src/resources/extensions/gsd/tests/feature-branch-lifecycle-integration.test.ts +48 -57
  391. package/src/resources/extensions/gsd/tests/files-loadfile-eisdir.test.ts +5 -7
  392. package/src/resources/extensions/gsd/tests/flag-file-db.test.ts +30 -42
  393. package/src/resources/extensions/gsd/tests/freeform-decisions.test.ts +198 -206
  394. package/src/resources/extensions/gsd/tests/git-locale.test.ts +13 -27
  395. package/src/resources/extensions/gsd/tests/git-service.test.ts +285 -388
  396. package/src/resources/extensions/gsd/tests/gitignore-tracked-gsd.test.ts +31 -39
  397. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +63 -69
  398. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +255 -264
  399. package/src/resources/extensions/gsd/tests/gsd-inspect.test.ts +108 -119
  400. package/src/resources/extensions/gsd/tests/gsd-recover.test.ts +81 -103
  401. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +229 -262
  402. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +13 -13
  403. package/src/resources/extensions/gsd/tests/health-widget.test.ts +29 -37
  404. package/src/resources/extensions/gsd/tests/idle-recovery.test.ts +81 -102
  405. package/src/resources/extensions/gsd/tests/infra-error.test.ts +20 -2
  406. package/src/resources/extensions/gsd/tests/inherited-repo-home-dir.test.ts +121 -0
  407. package/src/resources/extensions/gsd/tests/init-wizard.test.ts +16 -18
  408. package/src/resources/extensions/gsd/tests/integration-edge.test.ts +41 -46
  409. package/src/resources/extensions/gsd/tests/integration-lifecycle.test.ts +42 -53
  410. package/src/resources/extensions/gsd/tests/integration-mixed-milestones.test.ts +75 -91
  411. package/src/resources/extensions/gsd/tests/integration-proof.test.ts +18 -18
  412. package/src/resources/extensions/gsd/tests/knowledge.test.ts +89 -0
  413. package/src/resources/extensions/gsd/tests/markdown-renderer.test.ts +150 -194
  414. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +103 -0
  415. package/src/resources/extensions/gsd/tests/md-importer.test.ts +101 -125
  416. package/src/resources/extensions/gsd/tests/memory-extractor.test.ts +45 -54
  417. package/src/resources/extensions/gsd/tests/memory-store.test.ts +80 -93
  418. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +66 -0
  419. package/src/resources/extensions/gsd/tests/migrate-command.test.ts +57 -66
  420. package/src/resources/extensions/gsd/tests/migrate-hierarchy.test.ts +83 -93
  421. package/src/resources/extensions/gsd/tests/migrate-parser.test.ts +161 -170
  422. package/src/resources/extensions/gsd/tests/migrate-transformer.test.ts +125 -141
  423. package/src/resources/extensions/gsd/tests/migrate-validator-parsers.test.ts +107 -131
  424. package/src/resources/extensions/gsd/tests/migrate-writer-integration.test.ts +87 -96
  425. package/src/resources/extensions/gsd/tests/migrate-writer.test.ts +125 -164
  426. package/src/resources/extensions/gsd/tests/must-have-parser.test.ts +81 -94
  427. package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +75 -37
  428. package/src/resources/extensions/gsd/tests/overrides.test.ts +99 -106
  429. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +40 -47
  430. package/src/resources/extensions/gsd/tests/parallel-worker-monitoring.test.ts +25 -28
  431. package/src/resources/extensions/gsd/tests/parallel-workers-multi-milestone-e2e.test.ts +66 -83
  432. package/src/resources/extensions/gsd/tests/park-edge-cases.test.ts +54 -77
  433. package/src/resources/extensions/gsd/tests/park-milestone.test.ts +68 -115
  434. package/src/resources/extensions/gsd/tests/parsers.test.ts +546 -611
  435. package/src/resources/extensions/gsd/tests/paths.test.ts +72 -87
  436. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +77 -117
  437. package/src/resources/extensions/gsd/tests/preferences.test.ts +34 -9
  438. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +11 -7
  439. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +56 -56
  440. package/src/resources/extensions/gsd/tests/queue-draft-detection.test.ts +93 -119
  441. package/src/resources/extensions/gsd/tests/queue-order.test.ts +70 -82
  442. package/src/resources/extensions/gsd/tests/queue-reorder-e2e.test.ts +42 -55
  443. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +100 -0
  444. package/src/resources/extensions/gsd/tests/quick-branch-lifecycle.test.ts +45 -73
  445. package/src/resources/extensions/gsd/tests/reassess-prompt.test.ts +28 -38
  446. package/src/resources/extensions/gsd/tests/recovery-attempts-reset.test.ts +176 -0
  447. package/src/resources/extensions/gsd/tests/replan-slice.test.ts +73 -80
  448. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +71 -74
  449. package/src/resources/extensions/gsd/tests/requirements.test.ts +70 -75
  450. package/src/resources/extensions/gsd/tests/retry-state-reset.test.ts +44 -66
  451. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +114 -181
  452. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +63 -65
  453. package/src/resources/extensions/gsd/tests/run-uat.test.ts +66 -128
  454. package/src/resources/extensions/gsd/tests/session-lock-multipath.test.ts +18 -25
  455. package/src/resources/extensions/gsd/tests/session-lock-regression.test.ts +37 -44
  456. package/src/resources/extensions/gsd/tests/shared-wal.test.ts +19 -26
  457. package/src/resources/extensions/gsd/tests/sqlite-unavailable-gate.test.ts +63 -0
  458. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +6 -8
  459. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +67 -0
  460. package/src/resources/extensions/gsd/tests/survivor-branch-complete.test.ts +108 -0
  461. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +22 -28
  462. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +49 -0
  463. package/src/resources/extensions/gsd/tests/token-savings.test.ts +54 -56
  464. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +23 -25
  465. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +10 -11
  466. package/src/resources/extensions/gsd/tests/unique-milestone-ids.test.ts +66 -82
  467. package/src/resources/extensions/gsd/tests/unit-runtime.test.ts +46 -47
  468. package/src/resources/extensions/gsd/tests/visualizer-critical-path.test.ts +20 -22
  469. package/src/resources/extensions/gsd/tests/visualizer-data.test.ts +84 -86
  470. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +41 -43
  471. package/src/resources/extensions/gsd/tests/visualizer-views.test.ts +94 -96
  472. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +11 -13
  473. package/src/resources/extensions/gsd/tests/worker-registry.test.ts +27 -29
  474. package/src/resources/extensions/gsd/tests/workflow-logger.test.ts +275 -0
  475. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +50 -52
  476. package/src/resources/extensions/gsd/tests/worktree-bugfix.test.ts +10 -13
  477. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +14 -18
  478. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +38 -39
  479. package/src/resources/extensions/gsd/tests/worktree-e2e.test.ts +17 -21
  480. package/src/resources/extensions/gsd/tests/worktree-health.test.ts +25 -30
  481. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +30 -37
  482. package/src/resources/extensions/gsd/tests/worktree-journal-events.test.ts +220 -0
  483. package/src/resources/extensions/gsd/tests/worktree-submodule-safety.test.ts +65 -0
  484. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +15 -22
  485. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +59 -66
  486. package/src/resources/extensions/gsd/tests/worktree.test.ts +44 -50
  487. package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -0
  488. package/src/resources/extensions/gsd/tools/plan-task.ts +2 -0
  489. package/src/resources/extensions/gsd/tools/replan-slice.ts +3 -0
  490. package/src/resources/extensions/gsd/tools/validate-milestone.ts +127 -0
  491. package/src/resources/extensions/gsd/workflow-logger.ts +193 -0
  492. package/src/resources/extensions/gsd/worktree-manager.ts +41 -5
  493. package/src/resources/extensions/gsd/worktree-resolver.ts +44 -0
  494. package/src/resources/extensions/mcp-client/index.ts +20 -0
  495. package/src/resources/extensions/voice/index.ts +11 -21
  496. package/src/resources/extensions/voice/linux-ready.ts +87 -0
  497. package/src/resources/extensions/voice/tests/linux-ready.test.ts +124 -0
  498. package/dist/web/standalone/.next/static/chunks/4024.0de81b543b28b9fe.js +0 -9
  499. package/dist/web/standalone/.next/static/chunks/app/page-7e9530a7122506c5.js +0 -1
  500. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  501. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  502. package/dist/web/standalone/.next/static/chunks/webpack-9014b5adb127a98a.js +0 -1
  503. package/dist/web/standalone/.next/static/css/8a727f372cf53002.css +0 -1
  504. /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → dFMji9G1LZ-Tv36el9pRT}/_buildManifest.js +0 -0
  505. /package/dist/web/standalone/.next/static/{mgkxN0mGP6gSUmGPEzbk_ → dFMji9G1LZ-Tv36el9pRT}/_ssgManifest.js +0 -0
@@ -1,13 +1,11 @@
1
+ import { describe, test } from 'node:test';
2
+ import assert from 'node:assert/strict';
1
3
  import { mkdtempSync, mkdirSync, rmSync, realpathSync } from "node:fs";
2
4
  import { join } from "node:path";
3
5
  import { tmpdir } from "node:os";
4
6
  import { spawnSync } from "node:child_process";
5
7
 
6
8
  import { gsdRoot, _clearGsdRootCache } from "../paths.ts";
7
- import { createTestContext } from "./test-helpers.ts";
8
-
9
- const { assertEq, assertTrue, report } = createTestContext();
10
-
11
9
  /** Create a tmp dir and resolve symlinks + 8.3 short names (macOS /var→/private/var, Windows RUNNER~1→runneradmin). */
12
10
  function tmp(): string {
13
11
  const p = mkdtempSync(join(tmpdir(), "gsd-paths-test-"));
@@ -23,91 +21,78 @@ function initGit(dir: string): void {
23
21
  spawnSync("git", ["commit", "--allow-empty", "-m", "init"], { cwd: dir });
24
22
  }
25
23
 
26
- // ── tests ──────────────────────────────────────────────────────────────────
27
-
28
- {
29
- // Case 1: .gsd exists at basePath — fast path
30
- const root = tmp();
31
- try {
32
- mkdirSync(join(root, ".gsd"));
33
- _clearGsdRootCache();
34
- const result = gsdRoot(root);
35
- assertEq(result, join(root, ".gsd"), "fast path: returns basePath/.gsd");
36
- } finally { cleanup(root); }
37
- }
38
-
39
- {
40
- // Case 2: .gsd exists at git root, cwd is a subdirectory
41
- const root = tmp();
42
- try {
43
- initGit(root);
44
- mkdirSync(join(root, ".gsd"));
45
- const sub = join(root, "src", "deep");
46
- mkdirSync(sub, { recursive: true });
47
- _clearGsdRootCache();
48
- const result = gsdRoot(sub);
49
- assertEq(result, join(root, ".gsd"), "git-root probe: finds .gsd at git root from subdirectory");
50
- } finally { cleanup(root); }
51
- }
24
+ describe('paths', () => {
25
+ test('Case 1: .gsd exists at basePath — fast path', () => {
26
+ const root = tmp();
27
+ try {
28
+ mkdirSync(join(root, ".gsd"));
29
+ _clearGsdRootCache();
30
+ const result = gsdRoot(root);
31
+ assert.deepStrictEqual(result, join(root, ".gsd"), "fast path: returns basePath/.gsd");
32
+ } finally { cleanup(root); }
33
+ });
52
34
 
53
- {
54
- // Case 3: .gsd in an ancestor — walk-up finds it (git repo with no .gsd at root)
55
- const root = tmp();
56
- try {
57
- // Init a git repo so git probe returns root — but put .gsd one level deeper
58
- // to force the walk-up path: root/project/.gsd, cwd = root/project/src/deep
59
- initGit(root);
60
- const project = join(root, "project");
61
- mkdirSync(join(project, ".gsd"), { recursive: true });
62
- const deep = join(project, "src", "deep");
63
- mkdirSync(deep, { recursive: true });
64
- _clearGsdRootCache();
65
- // git probe returns root (no .gsd there), so walk-up takes over and finds project/.gsd
66
- const result = gsdRoot(deep);
67
- assertEq(result, join(project, ".gsd"), "walk-up: finds .gsd in ancestor when git root has none");
68
- } finally { cleanup(root); }
69
- }
35
+ test('Case 2: .gsd exists at git root, cwd is a subdirectory', () => {
36
+ const root = tmp();
37
+ try {
38
+ initGit(root);
39
+ mkdirSync(join(root, ".gsd"));
40
+ const sub = join(root, "src", "deep");
41
+ mkdirSync(sub, { recursive: true });
42
+ _clearGsdRootCache();
43
+ const result = gsdRoot(sub);
44
+ assert.deepStrictEqual(result, join(root, ".gsd"), "git-root probe: finds .gsd at git root from subdirectory");
45
+ } finally { cleanup(root); }
46
+ });
70
47
 
71
- {
72
- // Case 4: .gsd nowhere — fallback returns original basePath/.gsd
73
- // Use an isolated git repo so we fully control the environment above basePath
74
- const root = tmp();
75
- try {
76
- initGit(root); // git root = root, no .gsd anywhere
77
- const sub = join(root, "src");
78
- mkdirSync(sub, { recursive: true });
79
- _clearGsdRootCache();
80
- const result = gsdRoot(sub);
81
- // git probe finds root (no .gsd), walk-up finds nothing fallback = sub/.gsd
82
- assertEq(result, join(sub, ".gsd"), "fallback: returns basePath/.gsd when .gsd not found anywhere");
83
- } finally { cleanup(root); }
84
- }
48
+ test('Case 3: .gsd in an ancestor — walk-up finds it', () => {
49
+ const root = tmp();
50
+ try {
51
+ initGit(root);
52
+ const project = join(root, "project");
53
+ mkdirSync(join(project, ".gsd"), { recursive: true });
54
+ const deep = join(project, "src", "deep");
55
+ mkdirSync(deep, { recursive: true });
56
+ _clearGsdRootCache();
57
+ const result = gsdRoot(deep);
58
+ assert.deepStrictEqual(result, join(project, ".gsd"), "walk-up: finds .gsd in ancestor when git root has none");
59
+ } finally { cleanup(root); }
60
+ });
85
61
 
86
- {
87
- // Case 5: cache — second call returns same value without re-probing
88
- const root = tmp();
89
- try {
90
- mkdirSync(join(root, ".gsd"));
91
- _clearGsdRootCache();
92
- const first = gsdRoot(root);
93
- const second = gsdRoot(root);
94
- assertEq(first, second, "cache: same result returned on second call");
95
- assertTrue(first === second, "cache: identity check (same string)");
96
- } finally { cleanup(root); }
97
- }
62
+ test('Case 4: .gsd nowhere — fallback returns original basePath/.gsd', () => {
63
+ const root = tmp();
64
+ try {
65
+ initGit(root);
66
+ const sub = join(root, "src");
67
+ mkdirSync(sub, { recursive: true });
68
+ _clearGsdRootCache();
69
+ const result = gsdRoot(sub);
70
+ assert.deepStrictEqual(result, join(sub, ".gsd"), "fallback: returns basePath/.gsd when .gsd not found anywhere");
71
+ } finally { cleanup(root); }
72
+ });
98
73
 
99
- {
100
- // Case 6: .gsd at basePath takes precedence over ancestor .gsd
101
- const outer = tmp();
102
- try {
103
- initGit(outer);
104
- mkdirSync(join(outer, ".gsd"));
105
- const inner = join(outer, "nested");
106
- mkdirSync(join(inner, ".gsd"), { recursive: true });
107
- _clearGsdRootCache();
108
- const result = gsdRoot(inner);
109
- assertEq(result, join(inner, ".gsd"), "precedence: nearest .gsd wins over ancestor");
110
- } finally { cleanup(outer); }
111
- }
74
+ test('Case 5: cache — second call returns same value without re-probing', () => {
75
+ const root = tmp();
76
+ try {
77
+ mkdirSync(join(root, ".gsd"));
78
+ _clearGsdRootCache();
79
+ const first = gsdRoot(root);
80
+ const second = gsdRoot(root);
81
+ assert.deepStrictEqual(first, second, "cache: same result returned on second call");
82
+ assert.ok(first === second, "cache: identity check (same string)");
83
+ } finally { cleanup(root); }
84
+ });
112
85
 
113
- report();
86
+ test('Case 6: .gsd at basePath takes precedence over ancestor .gsd', () => {
87
+ const outer = tmp();
88
+ try {
89
+ initGit(outer);
90
+ mkdirSync(join(outer, ".gsd"));
91
+ const inner = join(outer, "nested");
92
+ mkdirSync(join(inner, ".gsd"), { recursive: true });
93
+ _clearGsdRootCache();
94
+ const result = gsdRoot(inner);
95
+ assert.deepStrictEqual(result, join(inner, ".gsd"), "precedence: nearest .gsd wins over ancestor");
96
+ } finally { cleanup(outer); }
97
+ });
98
+ });
@@ -1,9 +1,10 @@
1
1
  // GSD Extension — Hook Engine Tests (Post-Unit, Pre-Dispatch, State Persistence)
2
2
 
3
+ import { describe, test } from 'node:test';
4
+ import assert from 'node:assert/strict';
3
5
  import { mkdtempSync, mkdirSync, rmSync, writeFileSync, existsSync, readFileSync } from "node:fs";
4
6
  import { join } from "node:path";
5
7
  import { tmpdir } from "node:os";
6
- import { createTestContext } from "./test-helpers.ts";
7
8
  import {
8
9
  checkPostUnitHooks,
9
10
  getActiveHook,
@@ -20,8 +21,6 @@ import {
20
21
  triggerHookManually,
21
22
  } from "../post-unit-hooks.ts";
22
23
 
23
- const { assertEq, assertTrue, assertMatch, report } = createTestContext();
24
-
25
24
  // ─── Fixture Helpers ───────────────────────────────────────────────────────
26
25
 
27
26
  function createFixtureBase(): string {
@@ -36,14 +35,14 @@ function createFixtureBase(): string {
36
35
 
37
36
  // ─── resolveHookArtifactPath ───────────────────────────────────────────────
38
37
 
39
- console.log("\n=== resolveHookArtifactPath ===");
40
38
 
41
- {
39
+ describe('post-unit-hooks', () => {
40
+ test('resolveHookArtifactPath', () => {
42
41
  const base = "/project";
43
42
 
44
43
  // Task-level
45
44
  const taskPath = resolveHookArtifactPath(base, "M001/S01/T01", "REVIEW-PASS.md");
46
- assertEq(
45
+ assert.deepStrictEqual(
47
46
  taskPath,
48
47
  join(base, ".gsd", "milestones", "M001", "slices", "S01", "tasks", "T01-REVIEW-PASS.md"),
49
48
  "task-level artifact path",
@@ -51,7 +50,7 @@ console.log("\n=== resolveHookArtifactPath ===");
51
50
 
52
51
  // Slice-level
53
52
  const slicePath = resolveHookArtifactPath(base, "M001/S01", "REVIEW-PASS.md");
54
- assertEq(
53
+ assert.deepStrictEqual(
55
54
  slicePath,
56
55
  join(base, ".gsd", "milestones", "M001", "slices", "S01", "REVIEW-PASS.md"),
57
56
  "slice-level artifact path",
@@ -59,129 +58,106 @@ console.log("\n=== resolveHookArtifactPath ===");
59
58
 
60
59
  // Milestone-level
61
60
  const milestonePath = resolveHookArtifactPath(base, "M001", "REVIEW-PASS.md");
62
- assertEq(
61
+ assert.deepStrictEqual(
63
62
  milestonePath,
64
63
  join(base, ".gsd", "milestones", "M001", "REVIEW-PASS.md"),
65
64
  "milestone-level artifact path",
66
65
  );
67
- }
66
+ });
68
67
 
69
68
  // ─── resetHookState ────────────────────────────────────────────────────────
70
-
71
- console.log("\n=== resetHookState ===");
72
-
73
- {
69
+ test('resetHookState', () => {
74
70
  resetHookState();
75
- assertEq(getActiveHook(), null, "no active hook after reset");
76
- assertTrue(!isRetryPending(), "no retry pending after reset");
77
- assertEq(consumeRetryTrigger(), null, "no retry trigger after reset");
78
- }
71
+ assert.deepStrictEqual(getActiveHook(), null, "no active hook after reset");
72
+ assert.ok(!isRetryPending(), "no retry pending after reset");
73
+ assert.deepStrictEqual(consumeRetryTrigger(), null, "no retry trigger after reset");
74
+ });
79
75
 
80
76
  // ─── checkPostUnitHooks with no hooks configured ───────────────────────────
81
-
82
- console.log("\n=== No hooks configured ===");
83
-
84
- {
77
+ test('No hooks configured', () => {
85
78
  resetHookState();
86
79
  const base = createFixtureBase();
87
80
  try {
88
81
  const result = checkPostUnitHooks("execute-task", "M001/S01/T01", base);
89
- assertEq(result, null, "returns null when no hooks configured");
82
+ assert.deepStrictEqual(result, null, "returns null when no hooks configured");
90
83
  } finally {
91
84
  rmSync(base, { recursive: true, force: true });
92
85
  }
93
- }
86
+ });
94
87
 
95
88
  // ─── Hook units don't trigger hooks (no hook-on-hook) ──────────────────────
96
-
97
- console.log("\n=== Hook-on-hook prevention ===");
98
-
99
- {
89
+ test('Hook-on-hook prevention', () => {
100
90
  resetHookState();
101
91
  const base = createFixtureBase();
102
92
  try {
103
93
  const result = checkPostUnitHooks("hook/code-review", "M001/S01/T01", base);
104
- assertEq(result, null, "hook units don't trigger other hooks");
94
+ assert.deepStrictEqual(result, null, "hook units don't trigger other hooks");
105
95
  } finally {
106
96
  rmSync(base, { recursive: true, force: true });
107
97
  }
108
- }
98
+ });
109
99
 
110
100
  // ─── consumeRetryTrigger clears state ──────────────────────────────────────
111
-
112
- console.log("\n=== consumeRetryTrigger clears state ===");
113
-
114
- {
101
+ test('consumeRetryTrigger clears state', () => {
115
102
  resetHookState();
116
- assertEq(consumeRetryTrigger(), null, "no trigger initially");
117
- assertTrue(!isRetryPending(), "no retry initially");
118
- }
103
+ assert.deepStrictEqual(consumeRetryTrigger(), null, "no trigger initially");
104
+ assert.ok(!isRetryPending(), "no retry initially");
105
+ });
119
106
 
120
107
  // ─── Variable substitution in prompts ──────────────────────────────────────
121
-
122
- console.log("\n=== Variable substitution ===");
123
-
124
- {
108
+ test('Variable substitution', () => {
125
109
  const base = "/project";
126
110
 
127
111
  // 3-part ID
128
112
  const path3 = resolveHookArtifactPath(base, "M002/S03/T05", "result.md");
129
- assertTrue(path3.includes("M002"), "3-part ID extracts milestoneId");
130
- assertTrue(path3.includes("S03"), "3-part ID extracts sliceId");
131
- assertTrue(path3.includes("T05"), "3-part ID extracts taskId");
132
- assertTrue(path3.includes("milestones"), "3-part ID includes milestones/ segment");
113
+ assert.ok(path3.includes("M002"), "3-part ID extracts milestoneId");
114
+ assert.ok(path3.includes("S03"), "3-part ID extracts sliceId");
115
+ assert.ok(path3.includes("T05"), "3-part ID extracts taskId");
116
+ assert.ok(path3.includes("milestones"), "3-part ID includes milestones/ segment");
133
117
 
134
118
  // 2-part ID
135
119
  const path2 = resolveHookArtifactPath(base, "M002/S03", "result.md");
136
- assertTrue(path2.includes("M002"), "2-part ID extracts milestoneId");
137
- assertTrue(path2.includes("S03"), "2-part ID extracts sliceId");
138
- assertTrue(path2.includes("milestones"), "2-part ID includes milestones/ segment");
120
+ assert.ok(path2.includes("M002"), "2-part ID extracts milestoneId");
121
+ assert.ok(path2.includes("S03"), "2-part ID extracts sliceId");
122
+ assert.ok(path2.includes("milestones"), "2-part ID includes milestones/ segment");
139
123
 
140
124
  // 1-part ID
141
125
  const path1 = resolveHookArtifactPath(base, "M002", "result.md");
142
- assertTrue(path1.includes("M002"), "1-part ID extracts milestoneId");
143
- assertTrue(path1.includes("milestones"), "1-part ID includes milestones/ segment");
144
- }
126
+ assert.ok(path1.includes("M002"), "1-part ID extracts milestoneId");
127
+ assert.ok(path1.includes("milestones"), "1-part ID includes milestones/ segment");
128
+ });
145
129
 
146
130
  // ═══════════════════════════════════════════════════════════════════════════
147
131
  // Phase 2: Pre-Dispatch Hook Tests
148
132
  // ═══════════════════════════════════════════════════════════════════════════
149
-
150
- console.log("\n=== Pre-dispatch: no hooks configured ===");
151
-
152
- {
133
+ test('Pre-dispatch: no hooks configured', () => {
153
134
  const base = createFixtureBase();
154
135
  try {
155
136
  const result = runPreDispatchHooks("execute-task", "M001/S01/T01", "original prompt", base);
156
- assertEq(result.action, "proceed", "proceeds when no hooks");
157
- assertEq(result.prompt, "original prompt", "prompt unchanged");
158
- assertEq(result.firedHooks.length, 0, "no hooks fired");
137
+ assert.deepStrictEqual(result.action, "proceed", "proceeds when no hooks");
138
+ assert.deepStrictEqual(result.prompt, "original prompt", "prompt unchanged");
139
+ assert.deepStrictEqual(result.firedHooks.length, 0, "no hooks fired");
159
140
  } finally {
160
141
  rmSync(base, { recursive: true, force: true });
161
142
  }
162
- }
163
-
164
- console.log("\n=== Pre-dispatch: hook units bypass ===");
143
+ });
165
144
 
166
- {
145
+ test('Pre-dispatch: hook units bypass', () => {
167
146
  const base = createFixtureBase();
168
147
  try {
169
148
  const result = runPreDispatchHooks("hook/review", "M001/S01/T01", "hook prompt", base);
170
- assertEq(result.action, "proceed", "hook units always proceed");
171
- assertEq(result.prompt, "hook prompt", "hook prompt unchanged");
172
- assertEq(result.firedHooks.length, 0, "no hooks fired for hook units");
149
+ assert.deepStrictEqual(result.action, "proceed", "hook units always proceed");
150
+ assert.deepStrictEqual(result.prompt, "hook prompt", "hook prompt unchanged");
151
+ assert.deepStrictEqual(result.firedHooks.length, 0, "no hooks fired for hook units");
173
152
  } finally {
174
153
  rmSync(base, { recursive: true, force: true });
175
154
  }
176
- }
155
+ });
177
156
 
178
157
  // ═══════════════════════════════════════════════════════════════════════════
179
158
  // Phase 3: State Persistence Tests
180
159
  // ═══════════════════════════════════════════════════════════════════════════
181
-
182
- console.log("\n=== State persistence: persist and restore ===");
183
-
184
- {
160
+ test('State persistence: persist and restore', () => {
185
161
  const base = createFixtureBase();
186
162
  try {
187
163
  resetHookState();
@@ -189,19 +165,17 @@ console.log("\n=== State persistence: persist and restore ===");
189
165
  // Persist empty state
190
166
  persistHookState(base);
191
167
  const filePath = join(base, ".gsd", "hook-state.json");
192
- assertTrue(existsSync(filePath), "hook-state.json created");
168
+ assert.ok(existsSync(filePath), "hook-state.json created");
193
169
 
194
170
  const content = JSON.parse(readFileSync(filePath, "utf-8"));
195
- assertEq(typeof content.savedAt, "string", "savedAt is a string");
196
- assertEq(Object.keys(content.cycleCounts).length, 0, "empty cycle counts");
171
+ assert.deepStrictEqual(typeof content.savedAt, "string", "savedAt is a string");
172
+ assert.deepStrictEqual(Object.keys(content.cycleCounts).length, 0, "empty cycle counts");
197
173
  } finally {
198
174
  rmSync(base, { recursive: true, force: true });
199
175
  }
200
- }
201
-
202
- console.log("\n=== State persistence: restore from disk ===");
176
+ });
203
177
 
204
- {
178
+ test('State persistence: restore from disk', () => {
205
179
  const base = createFixtureBase();
206
180
  try {
207
181
  resetHookState();
@@ -222,16 +196,14 @@ console.log("\n=== State persistence: restore from disk ===");
222
196
  // Verify by persisting and reading back
223
197
  persistHookState(base);
224
198
  const restored = JSON.parse(readFileSync(stateFile, "utf-8"));
225
- assertEq(restored.cycleCounts["review/execute-task/M001/S01/T01"], 2, "cycle count restored for review");
226
- assertEq(restored.cycleCounts["simplify/execute-task/M001/S01/T02"], 1, "cycle count restored for simplify");
199
+ assert.deepStrictEqual(restored.cycleCounts["review/execute-task/M001/S01/T01"], 2, "cycle count restored for review");
200
+ assert.deepStrictEqual(restored.cycleCounts["simplify/execute-task/M001/S01/T02"], 1, "cycle count restored for simplify");
227
201
  } finally {
228
202
  rmSync(base, { recursive: true, force: true });
229
203
  }
230
- }
231
-
232
- console.log("\n=== State persistence: clear ===");
204
+ });
233
205
 
234
- {
206
+ test('State persistence: clear', () => {
235
207
  const base = createFixtureBase();
236
208
  try {
237
209
  resetHookState();
@@ -246,77 +218,65 @@ console.log("\n=== State persistence: clear ===");
246
218
  clearPersistedHookState(base);
247
219
 
248
220
  const cleared = JSON.parse(readFileSync(stateFile, "utf-8"));
249
- assertEq(Object.keys(cleared.cycleCounts).length, 0, "cycle counts cleared");
221
+ assert.deepStrictEqual(Object.keys(cleared.cycleCounts).length, 0, "cycle counts cleared");
250
222
  } finally {
251
223
  rmSync(base, { recursive: true, force: true });
252
224
  }
253
- }
225
+ });
254
226
 
255
- console.log("\n=== State persistence: restore handles missing file ===");
256
-
257
- {
227
+ test('State persistence: restore handles missing file', () => {
258
228
  const base = createFixtureBase();
259
229
  try {
260
230
  resetHookState();
261
231
  // Should not throw
262
232
  restoreHookState(base);
263
- assertEq(getActiveHook(), null, "no active hook after restore from missing file");
233
+ assert.deepStrictEqual(getActiveHook(), null, "no active hook after restore from missing file");
264
234
  } finally {
265
235
  rmSync(base, { recursive: true, force: true });
266
236
  }
267
- }
237
+ });
268
238
 
269
- console.log("\n=== State persistence: restore handles corrupt file ===");
270
-
271
- {
239
+ test('State persistence: restore handles corrupt file', () => {
272
240
  const base = createFixtureBase();
273
241
  try {
274
242
  resetHookState();
275
243
  writeFileSync(join(base, ".gsd", "hook-state.json"), "not json", "utf-8");
276
244
  // Should not throw
277
245
  restoreHookState(base);
278
- assertEq(getActiveHook(), null, "no active hook after corrupt restore");
246
+ assert.deepStrictEqual(getActiveHook(), null, "no active hook after corrupt restore");
279
247
  } finally {
280
248
  rmSync(base, { recursive: true, force: true });
281
249
  }
282
- }
250
+ });
283
251
 
284
252
  // ═══════════════════════════════════════════════════════════════════════════
285
253
  // Phase 3: Hook Status Reporting Tests
286
254
  // ═══════════════════════════════════════════════════════════════════════════
287
-
288
- console.log("\n=== Hook status: no hooks ===");
289
-
290
- {
255
+ test('Hook status: no hooks', () => {
291
256
  resetHookState();
292
257
  const entries = getHookStatus();
293
258
  // No preferences file = no hooks
294
- assertEq(entries.length, 0, "no entries when no hooks configured");
259
+ assert.deepStrictEqual(entries.length, 0, "no entries when no hooks configured");
295
260
 
296
261
  const formatted = formatHookStatus();
297
- assertMatch(formatted, /No hooks configured/, "status message says no hooks");
298
- }
262
+ assert.match(formatted, /No hooks configured/, "status message says no hooks");
263
+ });
299
264
 
300
265
  // ═══════════════════════════════════════════════════════════════════════════
301
266
  // Phase 4: Manual Hook Trigger Tests
302
267
  // ═══════════════════════════════════════════════════════════════════════════
303
-
304
- console.log("\n=== triggerHookManually: hook not found ===");
305
-
306
- {
268
+ test('triggerHookManually: hook not found', () => {
307
269
  resetHookState();
308
270
  const base = createFixtureBase();
309
271
  try {
310
272
  const result = triggerHookManually("nonexistent-hook", "execute-task", "M001/S01/T01", base);
311
- assertEq(result, null, "returns null when hook not found");
273
+ assert.deepStrictEqual(result, null, "returns null when hook not found");
312
274
  } finally {
313
275
  rmSync(base, { recursive: true, force: true });
314
276
  }
315
- }
277
+ });
316
278
 
317
- console.log("\n=== triggerHookManually: with configured hook ===");
318
-
319
- {
279
+ test('triggerHookManually: with configured hook', () => {
320
280
  resetHookState();
321
281
  const base = createFixtureBase();
322
282
  try {
@@ -325,16 +285,16 @@ console.log("\n=== triggerHookManually: with configured hook ===");
325
285
  const result = triggerHookManually("code-review", "execute-task", "M001/S01/T01", base);
326
286
  // Result depends on whether code-review hook is configured in preferences
327
287
  // The function should either return null or a valid HookDispatchResult
328
- assertTrue(result === null || typeof result === "object", "returns null or object");
288
+ assert.ok(result === null || typeof result === "object", "returns null or object");
329
289
  if (result) {
330
- assertEq(result.hookName, "code-review", "hook name in result");
331
- assertEq(result.unitType, "hook/code-review", "unit type is hook-prefixed");
332
- assertEq(result.unitId, "M001/S01/T01", "unit ID preserved");
333
- assertTrue(typeof result.prompt === "string", "prompt is a string");
290
+ assert.deepStrictEqual(result.hookName, "code-review", "hook name in result");
291
+ assert.deepStrictEqual(result.unitType, "hook/code-review", "unit type is hook-prefixed");
292
+ assert.deepStrictEqual(result.unitId, "M001/S01/T01", "unit ID preserved");
293
+ assert.ok(typeof result.prompt === "string", "prompt is a string");
334
294
  }
335
295
  } finally {
336
296
  rmSync(base, { recursive: true, force: true });
337
297
  }
338
- }
298
+ });
339
299
 
340
- report();
300
+ });
@@ -15,6 +15,7 @@ import {
15
15
  applyModeDefaults,
16
16
  getIsolationMode,
17
17
  parsePreferencesMarkdown,
18
+ _resetParseWarningFlag,
18
19
  } from "../preferences.ts";
19
20
  import type { GSDPreferences, GSDModelConfigV2, GSDPhaseModelConfig } from "../preferences.ts";
20
21
 
@@ -40,18 +41,16 @@ test("git.merge_to_main produces deprecation warning", () => {
40
41
  });
41
42
 
42
43
 
43
- test("getIsolationMode defaults to worktree when preferences have no isolation setting", () => {
44
+ test("getIsolationMode defaults to none when preferences have no isolation setting", () => {
44
45
  // Validate the default via validatePreferences: when no isolation is set,
45
- // preferences.git.isolation is undefined, and getIsolationMode returns "worktree".
46
- // We test the function's logic by verifying its documented default.
46
+ // preferences.git.isolation is undefined, and getIsolationMode returns "none".
47
+ // Default changed from "worktree" to "none" so GSD works out of the box
48
+ // without preferences.md (#2480).
47
49
  const { preferences } = validatePreferences({});
48
50
  assert.equal(preferences.git?.isolation, undefined, "no isolation in empty prefs");
49
- // The function returns "worktree" when prefs?.git?.isolation is not "none" or "branch"
50
- // This is a compile-time-verifiable truth from the function body — test it directly
51
- // by constructing the same conditions getIsolationMode checks.
52
51
  const isolation = preferences.git?.isolation;
53
- const expected = isolation === "none" ? "none" : isolation === "branch" ? "branch" : "worktree";
54
- assert.equal(expected, "worktree", "default isolation mode is worktree");
52
+ const expected = isolation === "worktree" ? "worktree" : isolation === "branch" ? "branch" : "none";
53
+ assert.equal(expected, "none", "default isolation mode is none");
55
54
  });
56
55
 
57
56
  // ── Mode defaults ────────────────────────────────────────────────────────────
@@ -62,7 +61,7 @@ test("solo mode applies correct defaults", () => {
62
61
  assert.equal(result.git?.push_branches, false);
63
62
  assert.equal(result.git?.pre_merge_check, false);
64
63
  assert.equal(result.git?.merge_strategy, "squash");
65
- assert.equal(result.git?.isolation, "worktree");
64
+ assert.equal(result.git?.isolation, "none");
66
65
  assert.equal(result.unique_milestone_ids, false);
67
66
  });
68
67
 
@@ -352,3 +351,29 @@ test("handles empty models config", () => {
352
351
  assert.notEqual(prefs, null);
353
352
  assert.equal(prefs!.models, undefined);
354
353
  });
354
+
355
+ // ── Warn-once for unrecognized format (#2373) ────────────────────────────────
356
+
357
+ test("unrecognized format warning is emitted at most once (#2373)", () => {
358
+ const warnings: string[] = [];
359
+ const origWarn = console.warn;
360
+ console.warn = (...args: unknown[]) => warnings.push(args.join(" "));
361
+ try {
362
+ // Reset internal warned flag so the test starts clean
363
+ _resetParseWarningFlag();
364
+
365
+ const unrecognized = "This is just plain text with no frontmatter or headings.";
366
+
367
+ // Call multiple times — simulates repeated preference loads
368
+ parsePreferencesMarkdown(unrecognized);
369
+ parsePreferencesMarkdown(unrecognized);
370
+ parsePreferencesMarkdown(unrecognized);
371
+
372
+ const relevant = warnings.filter(w => w.includes("unrecognized format"));
373
+ assert.equal(relevant.length, 1, `expected exactly 1 warning, got ${relevant.length}: ${JSON.stringify(relevant)}`);
374
+ } finally {
375
+ console.warn = origWarn;
376
+ // Reset so other tests aren't affected by the flag state
377
+ _resetParseWarningFlag();
378
+ }
379
+ });