gsd-pi 2.65.0 → 2.66.0-dev.6c91c1f

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 (458) hide show
  1. package/dist/mcp-server.js +6 -2
  2. package/dist/resources/extensions/browser-tools/capture.js +20 -1
  3. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
  4. package/dist/resources/extensions/gsd/auto/finalize-timeout.js +2 -0
  5. package/dist/resources/extensions/gsd/auto/loop.js +2 -2
  6. package/dist/resources/extensions/gsd/auto/phases.js +48 -5
  7. package/dist/resources/extensions/gsd/auto/run-unit.js +13 -2
  8. package/dist/resources/extensions/gsd/auto/session.js +4 -0
  9. package/dist/resources/extensions/gsd/auto/types.js +2 -0
  10. package/dist/resources/extensions/gsd/auto-dashboard.js +2 -1
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +99 -9
  12. package/dist/resources/extensions/gsd/auto-model-selection.js +7 -5
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +17 -6
  14. package/dist/resources/extensions/gsd/auto-prompts.js +24 -0
  15. package/dist/resources/extensions/gsd/auto-recovery.js +40 -22
  16. package/dist/resources/extensions/gsd/auto-start.js +175 -12
  17. package/dist/resources/extensions/gsd/auto-tool-tracking.js +10 -0
  18. package/dist/resources/extensions/gsd/auto-worktree.js +29 -7
  19. package/dist/resources/extensions/gsd/auto.js +21 -15
  20. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +17 -4
  21. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +10 -0
  22. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +6 -4
  23. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -1
  24. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +11 -3
  25. package/dist/resources/extensions/gsd/bootstrap/system-context.js +3 -1
  26. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +31 -1
  27. package/dist/resources/extensions/gsd/commands/context.js +8 -1
  28. package/dist/resources/extensions/gsd/commands/handlers/core.js +23 -2
  29. package/dist/resources/extensions/gsd/commands-extensions.js +1 -1
  30. package/dist/resources/extensions/gsd/config-overlay.js +312 -0
  31. package/dist/resources/extensions/gsd/db-writer.js +13 -3
  32. package/dist/resources/extensions/gsd/detection.js +1 -1
  33. package/dist/resources/extensions/gsd/dispatch-guard.js +2 -1
  34. package/dist/resources/extensions/gsd/docs/preferences-reference.md +1 -0
  35. package/dist/resources/extensions/gsd/doctor.js +2 -1
  36. package/dist/resources/extensions/gsd/files.js +17 -0
  37. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  38. package/dist/resources/extensions/gsd/gsd-db.js +47 -4
  39. package/dist/resources/extensions/gsd/guided-flow.js +220 -29
  40. package/dist/resources/extensions/gsd/index.js +1 -1
  41. package/dist/resources/extensions/gsd/json-persistence.js +5 -2
  42. package/dist/resources/extensions/gsd/md-importer.js +14 -7
  43. package/dist/resources/extensions/gsd/notification-overlay.js +1 -1
  44. package/dist/resources/extensions/gsd/notification-widget.js +2 -1
  45. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +1 -1
  46. package/dist/resources/extensions/gsd/parallel-orchestrator.js +17 -11
  47. package/dist/resources/extensions/gsd/pre-execution-checks.js +26 -5
  48. package/dist/resources/extensions/gsd/preferences-types.js +3 -0
  49. package/dist/resources/extensions/gsd/preferences-validation.js +45 -1
  50. package/dist/resources/extensions/gsd/preferences.js +9 -2
  51. package/dist/resources/extensions/gsd/preparation.js +1092 -0
  52. package/dist/resources/extensions/gsd/prompt-validation.js +67 -0
  53. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
  54. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  55. package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
  56. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -0
  57. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +6 -1
  58. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
  59. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
  60. package/dist/resources/extensions/gsd/prompts/queue.md +2 -0
  61. package/dist/resources/extensions/gsd/prompts/rethink.md +2 -1
  62. package/dist/resources/extensions/gsd/prompts/system.md +2 -2
  63. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
  64. package/dist/resources/extensions/gsd/quick.js +19 -15
  65. package/dist/resources/extensions/gsd/reactive-graph.js +12 -0
  66. package/dist/resources/extensions/gsd/roadmap-slices.js +24 -5
  67. package/dist/resources/extensions/gsd/safety/content-validator.js +3 -3
  68. package/dist/resources/extensions/gsd/session-lock.js +23 -1
  69. package/dist/resources/extensions/gsd/state.js +115 -28
  70. package/dist/resources/extensions/gsd/templates/context-enhanced.md +138 -0
  71. package/dist/resources/extensions/gsd/tools/complete-milestone.js +15 -3
  72. package/dist/resources/extensions/gsd/tools/complete-slice.js +27 -6
  73. package/dist/resources/extensions/gsd/tools/complete-task.js +31 -7
  74. package/dist/resources/extensions/gsd/tools/plan-milestone.js +7 -5
  75. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +5 -2
  76. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +119 -0
  77. package/dist/resources/extensions/gsd/tools/reopen-slice.js +30 -0
  78. package/dist/resources/extensions/gsd/tools/reopen-task.js +18 -0
  79. package/dist/resources/extensions/gsd/triage-resolution.js +33 -16
  80. package/dist/resources/extensions/gsd/undo.js +3 -2
  81. package/dist/resources/extensions/gsd/workflow-events.js +1 -0
  82. package/dist/resources/extensions/gsd/workflow-logger.js +1 -1
  83. package/dist/resources/extensions/gsd/workflow-projections.js +7 -9
  84. package/dist/resources/extensions/gsd/workflow-reconcile.js +100 -9
  85. package/dist/resources/extensions/gsd/workflow-templates.js +11 -2
  86. package/dist/resources/extensions/gsd/worktree-manager.js +5 -2
  87. package/dist/resources/extensions/gsd/worktree.js +9 -0
  88. package/dist/resources/extensions/shared/interview-ui.js +1 -1
  89. package/dist/resources/extensions/subagent/agents.js +19 -5
  90. package/dist/web/standalone/.next/BUILD_ID +1 -1
  91. package/dist/web/standalone/.next/app-path-routes-manifest.json +11 -11
  92. package/dist/web/standalone/.next/build-manifest.json +4 -4
  93. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  94. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  95. package/dist/web/standalone/.next/required-server-files.json +3 -3
  96. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  97. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  98. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  99. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  100. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  101. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  102. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  103. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  104. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  107. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  108. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  109. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  110. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  111. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  113. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  123. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  135. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  155. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  165. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  166. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  171. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +2 -2
  185. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  186. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  187. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  188. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  189. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  190. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  191. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  199. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  200. package/dist/web/standalone/.next/server/app/index.html +1 -1
  201. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  202. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  203. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  204. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  205. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  206. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  207. package/dist/web/standalone/.next/server/app/page.js +2 -2
  208. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/app-paths-manifest.json +11 -11
  210. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  211. package/dist/web/standalone/.next/server/chunks/7471.js +3 -3
  212. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  213. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  214. package/dist/web/standalone/.next/server/middleware.js +2 -2
  215. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  216. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  217. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  218. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  219. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  220. package/dist/web/standalone/.next/static/chunks/6502.8874bcae249c02e1.js +9 -0
  221. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  222. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  223. package/dist/web/standalone/.next/static/chunks/app/page-0c485498795110d6.js +1 -0
  224. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  225. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  226. package/dist/web/standalone/.next/static/chunks/{webpack-a1c1e452c6b32d04.js → webpack-9fed74684e1c5bb1.js} +1 -1
  227. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  228. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  229. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  230. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  231. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  232. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  233. package/dist/web/standalone/server.js +1 -1
  234. package/package.json +1 -1
  235. package/packages/pi-coding-agent/dist/core/retry-handler.d.ts.map +1 -1
  236. package/packages/pi-coding-agent/dist/core/retry-handler.js +30 -19
  237. package/packages/pi-coding-agent/dist/core/retry-handler.js.map +1 -1
  238. package/packages/pi-coding-agent/dist/core/retry-handler.test.js +51 -0
  239. package/packages/pi-coding-agent/dist/core/retry-handler.test.js.map +1 -1
  240. package/packages/pi-coding-agent/dist/core/sdk.js +9 -9
  241. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  242. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts +2 -1
  243. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.d.ts.map +1 -1
  244. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js +10 -1
  245. package/packages/pi-coding-agent/dist/modes/interactive/components/provider-manager.js.map +1 -1
  246. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts +1 -0
  247. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  248. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +20 -5
  249. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  250. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +15 -1
  251. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  252. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +18 -0
  253. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  254. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  255. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -0
  256. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  257. package/packages/pi-coding-agent/package.json +1 -1
  258. package/packages/pi-coding-agent/src/core/retry-handler.test.ts +80 -0
  259. package/packages/pi-coding-agent/src/core/retry-handler.ts +37 -25
  260. package/packages/pi-coding-agent/src/core/sdk.ts +9 -9
  261. package/packages/pi-coding-agent/src/modes/interactive/components/provider-manager.ts +10 -0
  262. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +20 -4
  263. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +27 -0
  264. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +16 -1
  265. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +5 -0
  266. package/packages/pi-tui/dist/components/image.d.ts +2 -0
  267. package/packages/pi-tui/dist/components/image.d.ts.map +1 -1
  268. package/packages/pi-tui/dist/components/image.js +4 -0
  269. package/packages/pi-tui/dist/components/image.js.map +1 -1
  270. package/packages/pi-tui/dist/components/image.test.d.ts +6 -0
  271. package/packages/pi-tui/dist/components/image.test.d.ts.map +1 -0
  272. package/packages/pi-tui/dist/components/image.test.js +32 -0
  273. package/packages/pi-tui/dist/components/image.test.js.map +1 -0
  274. package/packages/pi-tui/src/components/image.test.ts +36 -0
  275. package/packages/pi-tui/src/components/image.ts +5 -0
  276. package/pkg/package.json +1 -1
  277. package/src/resources/extensions/browser-tools/capture.ts +19 -1
  278. package/src/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +93 -0
  279. package/src/resources/extensions/gsd/auto/finalize-timeout.ts +3 -0
  280. package/src/resources/extensions/gsd/auto/loop.ts +2 -2
  281. package/src/resources/extensions/gsd/auto/phases.ts +68 -3
  282. package/src/resources/extensions/gsd/auto/run-unit.ts +12 -2
  283. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  284. package/src/resources/extensions/gsd/auto/types.ts +5 -0
  285. package/src/resources/extensions/gsd/auto-dashboard.ts +2 -1
  286. package/src/resources/extensions/gsd/auto-dispatch.ts +110 -9
  287. package/src/resources/extensions/gsd/auto-model-selection.ts +7 -5
  288. package/src/resources/extensions/gsd/auto-post-unit.ts +16 -6
  289. package/src/resources/extensions/gsd/auto-prompts.ts +31 -0
  290. package/src/resources/extensions/gsd/auto-recovery.ts +29 -23
  291. package/src/resources/extensions/gsd/auto-start.ts +188 -10
  292. package/src/resources/extensions/gsd/auto-tool-tracking.ts +10 -0
  293. package/src/resources/extensions/gsd/auto-worktree.ts +28 -7
  294. package/src/resources/extensions/gsd/auto.ts +19 -8
  295. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +16 -4
  296. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +10 -0
  297. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +5 -4
  298. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +4 -1
  299. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +11 -3
  300. package/src/resources/extensions/gsd/bootstrap/system-context.ts +3 -1
  301. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +36 -1
  302. package/src/resources/extensions/gsd/commands/context.ts +7 -1
  303. package/src/resources/extensions/gsd/commands/handlers/core.ts +26 -2
  304. package/src/resources/extensions/gsd/commands-extensions.ts +1 -1
  305. package/src/resources/extensions/gsd/config-overlay.ts +331 -0
  306. package/src/resources/extensions/gsd/db-writer.ts +11 -3
  307. package/src/resources/extensions/gsd/detection.ts +1 -1
  308. package/src/resources/extensions/gsd/dispatch-guard.ts +2 -1
  309. package/src/resources/extensions/gsd/docs/preferences-reference.md +1 -0
  310. package/src/resources/extensions/gsd/doctor.ts +2 -1
  311. package/src/resources/extensions/gsd/files.ts +19 -0
  312. package/src/resources/extensions/gsd/gitignore.ts +1 -0
  313. package/src/resources/extensions/gsd/gsd-db.ts +46 -4
  314. package/src/resources/extensions/gsd/guided-flow.ts +254 -30
  315. package/src/resources/extensions/gsd/index.ts +1 -0
  316. package/src/resources/extensions/gsd/json-persistence.ts +6 -3
  317. package/src/resources/extensions/gsd/md-importer.ts +13 -6
  318. package/src/resources/extensions/gsd/notification-overlay.ts +1 -1
  319. package/src/resources/extensions/gsd/notification-widget.ts +2 -1
  320. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +1 -1
  321. package/src/resources/extensions/gsd/parallel-orchestrator.ts +19 -11
  322. package/src/resources/extensions/gsd/pre-execution-checks.ts +32 -7
  323. package/src/resources/extensions/gsd/preferences-types.ts +25 -0
  324. package/src/resources/extensions/gsd/preferences-validation.ts +45 -1
  325. package/src/resources/extensions/gsd/preferences.ts +9 -2
  326. package/src/resources/extensions/gsd/preparation.ts +1419 -0
  327. package/src/resources/extensions/gsd/prompt-validation.ts +88 -0
  328. package/src/resources/extensions/gsd/prompts/complete-milestone.md +3 -3
  329. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  330. package/src/resources/extensions/gsd/prompts/discuss-prepared.md +424 -0
  331. package/src/resources/extensions/gsd/prompts/discuss.md +2 -0
  332. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +6 -1
  333. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -4
  334. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +23 -0
  335. package/src/resources/extensions/gsd/prompts/queue.md +2 -0
  336. package/src/resources/extensions/gsd/prompts/rethink.md +2 -1
  337. package/src/resources/extensions/gsd/prompts/system.md +2 -2
  338. package/src/resources/extensions/gsd/prompts/validate-milestone.md +56 -23
  339. package/src/resources/extensions/gsd/quick.ts +20 -15
  340. package/src/resources/extensions/gsd/reactive-graph.ts +18 -0
  341. package/src/resources/extensions/gsd/roadmap-slices.ts +21 -5
  342. package/src/resources/extensions/gsd/safety/content-validator.ts +3 -3
  343. package/src/resources/extensions/gsd/session-lock.ts +17 -1
  344. package/src/resources/extensions/gsd/state.ts +115 -26
  345. package/src/resources/extensions/gsd/templates/context-enhanced.md +138 -0
  346. package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +223 -0
  347. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +33 -2
  348. package/src/resources/extensions/gsd/tests/auto-remediate-slice-status.test.ts +56 -0
  349. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +41 -0
  350. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +72 -0
  351. package/src/resources/extensions/gsd/tests/complete-task-normalize-lists.test.ts +54 -0
  352. package/src/resources/extensions/gsd/tests/defer-milestone-stamp.test.ts +30 -0
  353. package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -3
  354. package/src/resources/extensions/gsd/tests/discuss-incremental-persistence.test.ts +36 -0
  355. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +46 -0
  356. package/src/resources/extensions/gsd/tests/dispatch-guard-closed-status.test.ts +33 -0
  357. package/src/resources/extensions/gsd/tests/dispatcher-stuck-planning.test.ts +37 -0
  358. package/src/resources/extensions/gsd/tests/error-success-mask.test.ts +37 -0
  359. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +125 -0
  360. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed.test.ts +48 -0
  361. package/src/resources/extensions/gsd/tests/format-shortcut.test.ts +69 -0
  362. package/src/resources/extensions/gsd/tests/frontmatter-parse-noise.test.ts +42 -0
  363. package/src/resources/extensions/gsd/tests/gitignore-bg-shell.test.ts +38 -0
  364. package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +103 -0
  365. package/src/resources/extensions/gsd/tests/import-done-milestones.test.ts +42 -0
  366. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +11 -9
  367. package/src/resources/extensions/gsd/tests/integration/state-machine-edge-cases.test.ts +4 -2
  368. package/src/resources/extensions/gsd/tests/integration/state-machine-live-validation.test.ts +28 -30
  369. package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +53 -0
  370. package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +525 -0
  371. package/src/resources/extensions/gsd/tests/isolation-none-branch-guard.test.ts +62 -0
  372. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +11 -10
  373. package/src/resources/extensions/gsd/tests/needs-remediation-revalidation.test.ts +48 -0
  374. package/src/resources/extensions/gsd/tests/note-captures-executed.test.ts +46 -0
  375. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +189 -0
  376. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +77 -0
  377. package/src/resources/extensions/gsd/tests/phantom-ghost-detection.test.ts +55 -0
  378. package/src/resources/extensions/gsd/tests/phantom-milestone-default-queued.test.ts +39 -0
  379. package/src/resources/extensions/gsd/tests/pre-exec-backtick-strip.test.ts +68 -0
  380. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +284 -20
  381. package/src/resources/extensions/gsd/tests/pre-execution-fail-closed.test.ts +2 -2
  382. package/src/resources/extensions/gsd/tests/pre-execution-pause-wiring.test.ts +2 -2
  383. package/src/resources/extensions/gsd/tests/preparation.test.ts +1211 -0
  384. package/src/resources/extensions/gsd/tests/project-root-cwd-crash.test.ts +53 -0
  385. package/src/resources/extensions/gsd/tests/projection-no-plan-overwrite.test.ts +83 -0
  386. package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +669 -0
  387. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -4
  388. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +85 -0
  389. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -1
  390. package/src/resources/extensions/gsd/tests/query-tools-db-open.test.ts +47 -0
  391. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +107 -0
  392. package/src/resources/extensions/gsd/tests/reactive-graph.test.ts +45 -0
  393. package/src/resources/extensions/gsd/tests/restore-tools-after-discuss.test.ts +63 -0
  394. package/src/resources/extensions/gsd/tests/rogue-file-detection.test.ts +4 -5
  395. package/src/resources/extensions/gsd/tests/run-uat-replay-cap.test.ts +51 -0
  396. package/src/resources/extensions/gsd/tests/show-config-command.test.ts +56 -0
  397. package/src/resources/extensions/gsd/tests/skip-slice-state-rebuild.test.ts +31 -0
  398. package/src/resources/extensions/gsd/tests/skipped-validation-completion.test.ts +39 -0
  399. package/src/resources/extensions/gsd/tests/slice-sequence-insert.test.ts +51 -0
  400. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +1 -1
  401. package/src/resources/extensions/gsd/tests/stale-lockfile-recovery.test.ts +36 -0
  402. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +147 -0
  403. package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +13 -0
  404. package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +21 -0
  405. package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +21 -0
  406. package/src/resources/extensions/gsd/tests/state-machine-full-walkthrough.test.ts +6 -7
  407. package/src/resources/extensions/gsd/tests/status-db-open.test.ts +47 -0
  408. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +1 -0
  409. package/src/resources/extensions/gsd/tests/subagent-agent-discovery.test.ts +47 -0
  410. package/src/resources/extensions/gsd/tests/symlink-extension-discovery.test.ts +125 -0
  411. package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +65 -0
  412. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +29 -1
  413. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +2 -1
  414. package/src/resources/extensions/gsd/tests/validate-milestone.test.ts +3 -4
  415. package/src/resources/extensions/gsd/tests/verification-operational-gate.test.ts +15 -0
  416. package/src/resources/extensions/gsd/tests/verify-artifact-tightened.test.ts +89 -0
  417. package/src/resources/extensions/gsd/tests/wave1-critical-regressions.test.ts +49 -0
  418. package/src/resources/extensions/gsd/tests/wave2-events-regressions.test.ts +48 -0
  419. package/src/resources/extensions/gsd/tests/wave3-session-regressions.test.ts +47 -0
  420. package/src/resources/extensions/gsd/tests/wave4-write-safety-regressions.test.ts +70 -0
  421. package/src/resources/extensions/gsd/tests/wave5-consistency-regressions.test.ts +165 -0
  422. package/src/resources/extensions/gsd/tests/worker-model-override.test.ts +48 -0
  423. package/src/resources/extensions/gsd/tests/workflow-logger-audit.test.ts +6 -3
  424. package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +38 -0
  425. package/src/resources/extensions/gsd/tests/worktree-integration.test.ts +16 -0
  426. package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +20 -0
  427. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +16 -17
  428. package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +13 -9
  429. package/src/resources/extensions/gsd/tests/worktree.test.ts +26 -9
  430. package/src/resources/extensions/gsd/tests/write-gate.test.ts +127 -2
  431. package/src/resources/extensions/gsd/tests/zero-slice-roadmap-guided.test.ts +19 -0
  432. package/src/resources/extensions/gsd/tools/complete-milestone.ts +13 -3
  433. package/src/resources/extensions/gsd/tools/complete-slice.ts +26 -6
  434. package/src/resources/extensions/gsd/tools/complete-task.ts +29 -7
  435. package/src/resources/extensions/gsd/tools/plan-milestone.ts +11 -9
  436. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +5 -2
  437. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +152 -0
  438. package/src/resources/extensions/gsd/tools/reopen-slice.ts +27 -0
  439. package/src/resources/extensions/gsd/tools/reopen-task.ts +17 -0
  440. package/src/resources/extensions/gsd/triage-resolution.ts +37 -17
  441. package/src/resources/extensions/gsd/types.ts +4 -0
  442. package/src/resources/extensions/gsd/undo.ts +3 -2
  443. package/src/resources/extensions/gsd/workflow-events.ts +5 -3
  444. package/src/resources/extensions/gsd/workflow-logger.ts +1 -1
  445. package/src/resources/extensions/gsd/workflow-projections.ts +7 -8
  446. package/src/resources/extensions/gsd/workflow-reconcile.ts +109 -8
  447. package/src/resources/extensions/gsd/workflow-templates.ts +11 -2
  448. package/src/resources/extensions/gsd/worktree-manager.ts +4 -2
  449. package/src/resources/extensions/gsd/worktree.ts +10 -0
  450. package/src/resources/extensions/shared/interview-ui.ts +1 -1
  451. package/src/resources/extensions/shared/tests/interview-notes-loop.test.ts +8 -10
  452. package/src/resources/extensions/subagent/agents.ts +30 -6
  453. package/dist/web/standalone/.next/static/chunks/6502.7593d7797a4b3999.js +0 -9
  454. package/dist/web/standalone/.next/static/chunks/app/page-62be3b5fa91e4c8f.js +0 -1
  455. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  456. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  457. /package/dist/web/standalone/.next/static/{MRM3OSYIAa4HMDqVGQ9nt → _X1i-S7l1jZfb7lmIZozb}/_buildManifest.js +0 -0
  458. /package/dist/web/standalone/.next/static/{MRM3OSYIAa4HMDqVGQ9nt → _X1i-S7l1jZfb7lmIZozb}/_ssgManifest.js +0 -0
@@ -0,0 +1,525 @@
1
+ /**
2
+ * Integration tests for the prepared discussion system.
3
+ *
4
+ * Exercises the full preparation pipeline against the real GSD-2 codebase:
5
+ * - runPreparation() produces valid briefs
6
+ * - TypeScript is detected as primary language
7
+ * - Module structure includes top-level directories
8
+ * - Completes within R112 timing requirement (<60s)
9
+ * - prepareAndBuildDiscussPrompt() uses discuss-prepared template when enabled
10
+ * - Fallback to standard prompt when preparation is disabled
11
+ */
12
+
13
+ import test from "node:test";
14
+ import assert from "node:assert/strict";
15
+ import { join } from "node:path";
16
+ import { existsSync } from "node:fs";
17
+ import {
18
+ runPreparation,
19
+ formatCodebaseBrief,
20
+ formatPriorContextBrief,
21
+ formatEcosystemBrief,
22
+ type PreparationUIContext,
23
+ type PreparationPreferences,
24
+ type PreparationResult,
25
+ } from "../preparation.ts";
26
+ import { validateEnhancedContext } from "../prompt-validation.ts";
27
+ import { getLastPreparationResult, clearPreparationResult } from "../guided-flow.ts";
28
+
29
+ // ─── Test Helpers ───────────────────────────────────────────────────────────────
30
+
31
+ /**
32
+ * Mock UI context that captures notifications for testing.
33
+ * Follows the pattern from preparation.test.ts.
34
+ */
35
+ function createMockUI(): PreparationUIContext & { notifications: Array<{ message: string; type?: string }> } {
36
+ const notifications: Array<{ message: string; type?: string }> = [];
37
+ return {
38
+ notifications,
39
+ notify(message: string, type?: "info" | "warning" | "error" | "success") {
40
+ notifications.push({ message, type });
41
+ },
42
+ };
43
+ }
44
+
45
+ /**
46
+ * Get the GSD extension source directory for integration testing.
47
+ * This is the real codebase we'll analyze.
48
+ */
49
+ function getGsdExtensionDir(): string {
50
+ // Navigate from tests/ up to gsd/ directory
51
+ return join(import.meta.dirname, "..");
52
+ }
53
+
54
+ /**
55
+ * Get the GSD-2 project root for full codebase analysis.
56
+ */
57
+ function getProjectRoot(): string {
58
+ // Navigate from tests/ up to the project root
59
+ // tests/ -> gsd/ -> extensions/ -> resources/ -> src/ -> gsd-2/
60
+ return join(import.meta.dirname, "..", "..", "..", "..", "..");
61
+ }
62
+
63
+ // ─── R111 Validation: runPreparation against real codebase ──────────────────────
64
+
65
+ test("R111: runPreparation() produces valid codebase brief for GSD extension", async (t) => {
66
+ const dir = getGsdExtensionDir();
67
+ const ui = createMockUI();
68
+ const prefs: PreparationPreferences = {
69
+ discuss_preparation: true,
70
+ discuss_web_research: false, // Skip web research to avoid API key requirement
71
+ discuss_depth: "standard",
72
+ };
73
+
74
+ const result = await runPreparation(dir, ui, prefs);
75
+
76
+ // Verify preparation completed successfully
77
+ assert.equal(result.enabled, true, "preparation should be enabled");
78
+ assert.ok(result.codebase, "should have codebase brief");
79
+ assert.ok(result.codebaseBrief, "should have formatted codebase brief");
80
+
81
+ // Verify TypeScript is detected as primary language
82
+ assert.equal(
83
+ result.codebase.techStack.primaryLanguage,
84
+ "javascript/typescript",
85
+ "should detect TypeScript as primary language",
86
+ );
87
+
88
+ // Verify module structure includes top-level directories
89
+ const topLevelDirs = result.codebase.moduleStructure.topLevelDirs;
90
+ assert.ok(topLevelDirs.length > 0, "should detect top-level directories");
91
+
92
+ // Common directories in the GSD extension
93
+ const expectedDirs = ["tests", "prompts", "templates", "migrate"];
94
+ const foundExpected = expectedDirs.filter(d => topLevelDirs.includes(d));
95
+ assert.ok(
96
+ foundExpected.length >= 2,
97
+ `should detect common directories, found: ${topLevelDirs.join(", ")}`,
98
+ );
99
+
100
+ // Verify sampled files exist
101
+ assert.ok(result.codebase.sampledFiles.length > 0, "should sample source files");
102
+ });
103
+
104
+ test("R111: runPreparation() produces valid prior context brief", async (t) => {
105
+ const dir = getGsdExtensionDir();
106
+ const ui = createMockUI();
107
+ const prefs: PreparationPreferences = {
108
+ discuss_preparation: true,
109
+ discuss_web_research: false,
110
+ };
111
+
112
+ const result = await runPreparation(dir, ui, prefs);
113
+
114
+ // Verify prior context brief structure
115
+ assert.ok(result.priorContext, "should have prior context");
116
+ assert.ok(result.priorContextBrief, "should have formatted prior context brief");
117
+
118
+ // Prior context aggregates decisions, requirements, knowledge, summaries
119
+ assert.ok("decisions" in result.priorContext, "should have decisions");
120
+ assert.ok("requirements" in result.priorContext, "should have requirements");
121
+ assert.ok("knowledge" in result.priorContext, "should have knowledge");
122
+ assert.ok("summaries" in result.priorContext, "should have summaries");
123
+ });
124
+
125
+ test("R111: runPreparation() produces valid ecosystem brief (skipped without API key)", async (t) => {
126
+ const dir = getGsdExtensionDir();
127
+ const ui = createMockUI();
128
+ const prefs: PreparationPreferences = {
129
+ discuss_preparation: true,
130
+ discuss_web_research: false, // Explicitly disable
131
+ };
132
+
133
+ const result = await runPreparation(dir, ui, prefs);
134
+
135
+ // Verify ecosystem brief structure
136
+ assert.ok(result.ecosystem, "should have ecosystem brief");
137
+ assert.ok(result.ecosystemBrief, "should have formatted ecosystem brief");
138
+ assert.equal(result.ecosystem.available, false, "ecosystem should be unavailable when web research disabled");
139
+ assert.ok(result.ecosystem.skippedReason, "should have skip reason");
140
+ });
141
+
142
+ test("R112: runPreparation() completes within 60s requirement", async (t) => {
143
+ const dir = getGsdExtensionDir();
144
+ const prefs: PreparationPreferences = {
145
+ discuss_preparation: true,
146
+ discuss_web_research: false,
147
+ discuss_depth: "standard",
148
+ };
149
+
150
+ const startTime = performance.now();
151
+ const result = await runPreparation(dir, null, prefs);
152
+ const elapsed = performance.now() - startTime;
153
+
154
+ // R112 requirement: preparation must complete within 60 seconds
155
+ assert.ok(result.durationMs < 60000, `should complete within 60s, took ${result.durationMs}ms`);
156
+ assert.ok(elapsed < 60000, `wall-clock time should be under 60s, was ${elapsed}ms`);
157
+
158
+ // Should be much faster for a local directory analysis
159
+ assert.ok(result.durationMs < 10000, `should typically complete within 10s, took ${result.durationMs}ms`);
160
+ });
161
+
162
+ // ─── Codebase Pattern Detection ─────────────────────────────────────────────────
163
+
164
+ test("runPreparation() detects code patterns from GSD extension", async (t) => {
165
+ const dir = getGsdExtensionDir();
166
+ const prefs: PreparationPreferences = {
167
+ discuss_preparation: true,
168
+ discuss_web_research: false,
169
+ };
170
+
171
+ const result = await runPreparation(dir, null, prefs);
172
+
173
+ // The GSD extension uses async/await extensively
174
+ assert.ok(
175
+ result.codebase.patterns.asyncStyle === "async/await" || result.codebase.patterns.asyncStyle === "mixed",
176
+ `should detect async/await or mixed, got ${result.codebase.patterns.asyncStyle}`,
177
+ );
178
+
179
+ // The GSD extension uses try/catch for error handling
180
+ assert.ok(
181
+ result.codebase.patterns.errorHandling === "try/catch" || result.codebase.patterns.errorHandling === "mixed",
182
+ `should detect try/catch or mixed, got ${result.codebase.patterns.errorHandling}`,
183
+ );
184
+
185
+ // TypeScript uses camelCase or mixed naming
186
+ assert.ok(
187
+ result.codebase.patterns.namingConvention === "camelCase" || result.codebase.patterns.namingConvention === "mixed",
188
+ `should detect camelCase or mixed, got ${result.codebase.patterns.namingConvention}`,
189
+ );
190
+
191
+ // Evidence should be populated
192
+ assert.ok(result.codebase.patterns.evidence.asyncStyle.length > 0, "should have async style evidence");
193
+ });
194
+
195
+ test("runPreparation() samples TypeScript files from src/ or project root", async (t) => {
196
+ const dir = getGsdExtensionDir();
197
+ const prefs: PreparationPreferences = {
198
+ discuss_preparation: true,
199
+ discuss_web_research: false,
200
+ };
201
+
202
+ const result = await runPreparation(dir, null, prefs);
203
+
204
+ // Should sample TypeScript files
205
+ const tsFiles = result.codebase.sampledFiles.filter(
206
+ f => f.endsWith(".ts") || f.endsWith(".tsx"),
207
+ );
208
+ assert.ok(tsFiles.length > 0, "should sample TypeScript files");
209
+
210
+ // Should exclude test files
211
+ const testFiles = result.codebase.sampledFiles.filter(
212
+ f => f.includes(".test.") || f.includes(".spec."),
213
+ );
214
+ assert.equal(testFiles.length, 0, "should not sample test files");
215
+ });
216
+
217
+ // ─── Brief Formatting ───────────────────────────────────────────────────────────
218
+
219
+ test("formatCodebaseBrief() produces LLM-readable markdown", async (t) => {
220
+ const dir = getGsdExtensionDir();
221
+ const prefs: PreparationPreferences = {
222
+ discuss_preparation: true,
223
+ discuss_web_research: false,
224
+ };
225
+
226
+ const result = await runPreparation(dir, null, prefs);
227
+ const formatted = formatCodebaseBrief(result.codebase);
228
+
229
+ // Should contain expected sections
230
+ assert.ok(formatted.includes("## Tech Stack"), "should have Tech Stack section");
231
+ assert.ok(formatted.includes("## Module Structure"), "should have Module Structure section");
232
+ assert.ok(formatted.includes("## Code Patterns"), "should have Code Patterns section");
233
+
234
+ // Should contain detected tech
235
+ assert.ok(formatted.includes("javascript/typescript"), "should include detected language");
236
+
237
+ // Should be within character limit
238
+ assert.ok(formatted.length <= 3000, `should cap at 3000 chars, got ${formatted.length}`);
239
+ });
240
+
241
+ test("formatPriorContextBrief() produces structured prior context output", async (t) => {
242
+ const dir = getGsdExtensionDir();
243
+ const prefs: PreparationPreferences = {
244
+ discuss_preparation: true,
245
+ discuss_web_research: false,
246
+ };
247
+
248
+ const result = await runPreparation(dir, null, prefs);
249
+ const formatted = formatPriorContextBrief(result.priorContext);
250
+
251
+ // Should contain expected sections
252
+ assert.ok(formatted.includes("## Prior Decisions"), "should have Prior Decisions section");
253
+ assert.ok(formatted.includes("## Prior Requirements"), "should have Prior Requirements section");
254
+ assert.ok(formatted.includes("## Prior Knowledge"), "should have Prior Knowledge section");
255
+ assert.ok(formatted.includes("## Prior Milestone Summaries"), "should have Prior Milestone Summaries section");
256
+
257
+ // Should be within character limit
258
+ assert.ok(formatted.length <= 6000, `should cap at 6000 chars, got ${formatted.length}`);
259
+ });
260
+
261
+ test("formatEcosystemBrief() returns simplified message (research happens during discussion)", async (t) => {
262
+ const dir = getGsdExtensionDir();
263
+ const prefs: PreparationPreferences = {
264
+ discuss_preparation: true,
265
+ discuss_web_research: false,
266
+ };
267
+
268
+ const result = await runPreparation(dir, null, prefs);
269
+ const formatted = formatEcosystemBrief(result.ecosystem);
270
+
271
+ // Should contain section header
272
+ assert.ok(formatted.includes("## Ecosystem Research"), "should have Ecosystem Research section");
273
+
274
+ // Should indicate research happens during discussion
275
+ assert.ok(formatted.includes("during the discussion"), "should mention research happens during discussion");
276
+ assert.ok(formatted.includes("web search tools"), "should mention web search tools");
277
+
278
+ // Should be within character limit
279
+ assert.ok(formatted.length <= 4000, `should cap at 4000 chars, got ${formatted.length}`);
280
+ });
281
+
282
+ // ─── Preparation Result Storage ─────────────────────────────────────────────────
283
+
284
+ test("getLastPreparationResult() returns null initially", async (t) => {
285
+ // Clear any existing state
286
+ clearPreparationResult();
287
+
288
+ const result = getLastPreparationResult();
289
+ assert.equal(result, null, "should return null when no preparation has run");
290
+ });
291
+
292
+ test("clearPreparationResult() clears stored result", async (t) => {
293
+ // This test verifies the clear function works
294
+ // We can't easily test the set behavior without running the full guided-flow
295
+ clearPreparationResult();
296
+ const result = getLastPreparationResult();
297
+ assert.equal(result, null, "should be null after clear");
298
+ });
299
+
300
+ // ─── TUI Progress Notifications ─────────────────────────────────────────────────
301
+
302
+ test("runPreparation() emits TUI progress notifications", async (t) => {
303
+ const dir = getGsdExtensionDir();
304
+ const ui = createMockUI();
305
+ const prefs: PreparationPreferences = {
306
+ discuss_preparation: true,
307
+ discuss_web_research: false,
308
+ };
309
+
310
+ await runPreparation(dir, ui, prefs);
311
+
312
+ // Should have notifications for each phase
313
+ assert.ok(ui.notifications.length > 0, "should have notifications");
314
+
315
+ // Verify codebase analysis notifications
316
+ assert.ok(
317
+ ui.notifications.some(n => n.message.includes("Analyzing codebase")),
318
+ "should show codebase analysis start",
319
+ );
320
+ assert.ok(
321
+ ui.notifications.some(n => n.message.includes("✓ Analyzed codebase")),
322
+ "should show codebase analysis complete",
323
+ );
324
+
325
+ // Verify prior context notifications
326
+ assert.ok(
327
+ ui.notifications.some(n => n.message.includes("Reviewing prior context")),
328
+ "should show prior context start",
329
+ );
330
+ assert.ok(
331
+ ui.notifications.some(n => n.message.includes("✓ Reviewed prior context")),
332
+ "should show prior context complete",
333
+ );
334
+ });
335
+
336
+ test("runPreparation() works in silent mode (no UI)", async (t) => {
337
+ const dir = getGsdExtensionDir();
338
+ const prefs: PreparationPreferences = {
339
+ discuss_preparation: true,
340
+ discuss_web_research: false,
341
+ };
342
+
343
+ // Pass null for UI
344
+ const result = await runPreparation(dir, null, prefs);
345
+
346
+ // Should complete without error
347
+ assert.equal(result.enabled, true, "should work without UI");
348
+ assert.ok(result.codebase, "should have codebase");
349
+ assert.ok(result.priorContext, "should have priorContext");
350
+ assert.ok(result.durationMs > 0, "should have duration");
351
+ });
352
+
353
+ // ─── Preference-Controlled Behavior ─────────────────────────────────────────────
354
+
355
+ test("runPreparation() returns early when discuss_preparation is false", async (t) => {
356
+ const dir = getGsdExtensionDir();
357
+ const ui = createMockUI();
358
+ const prefs: PreparationPreferences = {
359
+ discuss_preparation: false,
360
+ };
361
+
362
+ const result = await runPreparation(dir, ui, prefs);
363
+
364
+ assert.equal(result.enabled, false, "should indicate preparation disabled");
365
+ assert.equal(result.codebaseBrief, "", "should have empty codebase brief");
366
+ assert.equal(result.priorContextBrief, "", "should have empty prior context brief");
367
+ assert.equal(result.ecosystemBrief, "", "should have empty ecosystem brief");
368
+ assert.equal(ui.notifications.length, 0, "should not show any notifications");
369
+ });
370
+
371
+ test("runPreparation() ecosystem research always returns unavailable (happens during discussion)", async (t) => {
372
+ const dir = getGsdExtensionDir();
373
+ const ui = createMockUI();
374
+ const prefs: PreparationPreferences = {
375
+ discuss_preparation: true,
376
+ discuss_web_research: true, // Even with this enabled, ecosystem research returns unavailable
377
+ };
378
+
379
+ const result = await runPreparation(dir, ui, prefs);
380
+
381
+ assert.equal(result.enabled, true);
382
+ assert.equal(result.ecosystemResearchPerformed, false, "should not perform ecosystem research from preparation");
383
+ assert.equal(result.ecosystem.available, false);
384
+ assert.ok(
385
+ result.ecosystem.skippedReason?.includes("during the discussion"),
386
+ "should indicate research happens during discussion",
387
+ );
388
+
389
+ // Should NOT have ecosystem research notifications (no longer part of preparation)
390
+ assert.ok(
391
+ !ui.notifications.some(n => n.message.includes("Researching ecosystem")),
392
+ "should not show ecosystem research notification",
393
+ );
394
+ });
395
+
396
+ // ─── validateEnhancedContext Integration ────────────────────────────────────────
397
+
398
+ test("validateEnhancedContext() validates required sections", async (t) => {
399
+ // Test with valid enhanced context
400
+ const validContext = `# M001 — Test Milestone
401
+
402
+ ## Scope
403
+
404
+ This milestone covers X, Y, Z.
405
+
406
+ ## Architectural Decisions
407
+
408
+ ### Decision 1: Use TypeScript
409
+
410
+ We will use TypeScript for type safety.
411
+
412
+ ## Acceptance Criteria
413
+
414
+ - [ ] Feature A works
415
+ - [ ] Feature B works
416
+ `;
417
+
418
+ const validResult = validateEnhancedContext(validContext);
419
+ assert.equal(validResult.valid, true, "should validate complete context");
420
+ assert.deepEqual(validResult.missing, [], "should have no missing sections");
421
+
422
+ // Test with missing sections
423
+ const invalidContext = `# M001 — Test Milestone
424
+
425
+ ## Scope
426
+
427
+ This milestone covers X, Y, Z.
428
+ `;
429
+
430
+ const invalidResult = validateEnhancedContext(invalidContext);
431
+ assert.equal(invalidResult.valid, false, "should reject incomplete context");
432
+ assert.ok(invalidResult.missing.length > 0, "should list missing sections");
433
+ assert.ok(
434
+ invalidResult.missing.some(m => m.includes("Architectural Decisions")),
435
+ "should report missing Architectural Decisions",
436
+ );
437
+ assert.ok(
438
+ invalidResult.missing.some(m => m.includes("Acceptance Criteria")),
439
+ "should report missing Acceptance Criteria",
440
+ );
441
+ });
442
+
443
+ test("validateEnhancedContext() requires decision entries in Architectural Decisions", async (t) => {
444
+ // Empty architectural decisions section
445
+ const emptyDecisions = `# M001 — Test Milestone
446
+
447
+ ## Scope
448
+
449
+ This milestone covers X, Y, Z.
450
+
451
+ ## Architectural Decisions
452
+
453
+ (No decisions yet)
454
+
455
+ ## Acceptance Criteria
456
+
457
+ - [ ] Feature A works
458
+ `;
459
+
460
+ const result = validateEnhancedContext(emptyDecisions);
461
+ assert.equal(result.valid, false, "should reject empty decisions section");
462
+ assert.ok(
463
+ result.missing.some(m => m.includes("decision entry")),
464
+ "should report missing decision entry",
465
+ );
466
+ });
467
+
468
+ // ─── Full Pipeline Integration ──────────────────────────────────────────────────
469
+
470
+ test("Full pipeline: preparation produces consistent results across runs", async (t) => {
471
+ const dir = getGsdExtensionDir();
472
+ const prefs: PreparationPreferences = {
473
+ discuss_preparation: true,
474
+ discuss_web_research: false,
475
+ };
476
+
477
+ // Run preparation twice
478
+ const result1 = await runPreparation(dir, null, prefs);
479
+ const result2 = await runPreparation(dir, null, prefs);
480
+
481
+ // Results should be consistent (same codebase, same analysis)
482
+ assert.equal(
483
+ result1.codebase.techStack.primaryLanguage,
484
+ result2.codebase.techStack.primaryLanguage,
485
+ "primary language should be consistent",
486
+ );
487
+
488
+ assert.deepEqual(
489
+ result1.codebase.moduleStructure.topLevelDirs.sort(),
490
+ result2.codebase.moduleStructure.topLevelDirs.sort(),
491
+ "top-level directories should be consistent",
492
+ );
493
+
494
+ assert.equal(
495
+ result1.codebase.patterns.asyncStyle,
496
+ result2.codebase.patterns.asyncStyle,
497
+ "async style should be consistent",
498
+ );
499
+ });
500
+
501
+ test("Full pipeline: preparation handles empty .gsd directory gracefully", async (t) => {
502
+ // The GSD extension directory may or may not have a .gsd subdirectory
503
+ // Either way, preparation should not crash
504
+ const dir = getGsdExtensionDir();
505
+ const prefs: PreparationPreferences = {
506
+ discuss_preparation: true,
507
+ discuss_web_research: false,
508
+ };
509
+
510
+ let result: PreparationResult | undefined;
511
+ let error: unknown;
512
+
513
+ try {
514
+ result = await runPreparation(dir, null, prefs);
515
+ } catch (e) {
516
+ error = e;
517
+ }
518
+
519
+ assert.equal(error, undefined, "should not throw");
520
+ assert.ok(result, "should return result");
521
+ assert.equal(result!.enabled, true, "should be enabled");
522
+
523
+ // Prior context should gracefully handle missing files
524
+ assert.ok(result!.priorContext, "should have prior context even if files missing");
525
+ });
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Regression test for #3675 — isolation:none stale branch guard
3
+ *
4
+ * When switching from isolation:branch/worktree to isolation:none, HEAD
5
+ * could remain on a milestone/<MID> branch. The fix in auto-start.ts
6
+ * detects this and auto-checks out to the integration branch.
7
+ *
8
+ * This structural test verifies the milestone/ branch check exists
9
+ * in auto-start.ts.
10
+ */
11
+
12
+ import { describe, test } from 'node:test';
13
+ import assert from 'node:assert/strict';
14
+ import { readFileSync } from 'node:fs';
15
+ import { fileURLToPath } from 'node:url';
16
+ import { dirname, join } from 'node:path';
17
+
18
+ const __filename = fileURLToPath(import.meta.url);
19
+ const __dirname = dirname(__filename);
20
+
21
+ const source = readFileSync(join(__dirname, '..', 'auto-start.ts'), 'utf-8');
22
+
23
+ describe('isolation:none stale branch guard (#3675)', () => {
24
+ test('checks for milestone/ branch prefix', () => {
25
+ assert.match(source, /startsWith\(["']milestone\//,
26
+ 'auto-start should check for milestone/ branch prefix');
27
+ });
28
+
29
+ test('imports nativeGetCurrentBranch', () => {
30
+ assert.match(source, /nativeGetCurrentBranch/,
31
+ 'auto-start should import nativeGetCurrentBranch');
32
+ });
33
+
34
+ test('imports nativeDetectMainBranch', () => {
35
+ assert.match(source, /nativeDetectMainBranch/,
36
+ 'auto-start should import nativeDetectMainBranch');
37
+ });
38
+
39
+ test('imports nativeCheckoutBranch', () => {
40
+ assert.match(source, /nativeCheckoutBranch/,
41
+ 'auto-start should import nativeCheckoutBranch');
42
+ });
43
+
44
+ test('guard is conditional on isolation mode "none"', () => {
45
+ assert.match(source, /getIsolationMode\(\)\s*===\s*["']none["']/,
46
+ 'guard should only activate when isolation mode is "none"');
47
+ });
48
+
49
+ test('calls nativeCheckoutBranch to return to integration branch', () => {
50
+ assert.match(source, /nativeCheckoutBranch\(base,\s*integrationBranch\)/,
51
+ 'should checkout to the integration branch');
52
+ });
53
+
54
+ test('guard is wrapped in try-catch (non-fatal)', () => {
55
+ // Find the milestone/ check and verify it is inside a try block
56
+ const milestoneIdx = source.indexOf('startsWith("milestone/")');
57
+ assert.ok(milestoneIdx > 0, 'milestone/ check should exist');
58
+ const before = source.slice(Math.max(0, milestoneIdx - 500), milestoneIdx);
59
+ assert.match(before, /try\s*\{/,
60
+ 'milestone branch guard should be inside a try block');
61
+ });
62
+ });
@@ -216,7 +216,7 @@ test("runDispatch emits dispatch-match with correct rule and flowId", async () =
216
216
  mid: "M001",
217
217
  midTitle: "Test Milestone",
218
218
  };
219
- const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0 };
219
+ const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 };
220
220
 
221
221
  const result = await runDispatch(ic, preData, loopState);
222
222
 
@@ -248,7 +248,7 @@ test("runDispatch emits dispatch-stop when dispatch returns stop action", async
248
248
  mid: "M001",
249
249
  midTitle: "Test",
250
250
  };
251
- const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0 };
251
+ const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 };
252
252
 
253
253
  const result = await runDispatch(ic, preData, loopState);
254
254
  assert.equal(result.action, "break");
@@ -303,6 +303,7 @@ test("runDispatch checks prior-slice completion against the project root in work
303
303
  const result = await runDispatch(ic, preData, {
304
304
  recentUnits: [],
305
305
  stuckRecoveryAttempts: 0,
306
+ consecutiveFinalizeTimeouts: 0,
306
307
  });
307
308
 
308
309
  assert.equal(result.action, "next");
@@ -343,7 +344,7 @@ test("runUnitPhase emits unit-start and unit-end with causedBy reference", async
343
344
  isRetry: false,
344
345
  previousTier: undefined,
345
346
  };
346
- const loopState: LoopState = { recentUnits: [{ key: "execute-task/M001/S01/T01" }], stuckRecoveryAttempts: 0 };
347
+ const loopState: LoopState = { recentUnits: [{ key: "execute-task/M001/S01/T01" }], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 };
347
348
 
348
349
  // Start runUnitPhase (it will block on runUnit internally)
349
350
  const unitPromise = runUnitPhase(ic, iterData, loopState);
@@ -400,7 +401,7 @@ test("all events from a mock iteration have monotonically increasing seq and sam
400
401
  mid: "M001",
401
402
  midTitle: "Test",
402
403
  };
403
- const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0 };
404
+ const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 };
404
405
  const dispatchResult = await runDispatch(ic, preData, loopState);
405
406
  assert.equal(dispatchResult.action, "next");
406
407
 
@@ -446,7 +447,7 @@ test("dispatch-match events include matchedRule field matching the rule name", a
446
447
  midTitle: "Test",
447
448
  };
448
449
 
449
- await runDispatch(ic, preData, { recentUnits: [], stuckRecoveryAttempts: 0 });
450
+ await runDispatch(ic, preData, { recentUnits: [], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 });
450
451
 
451
452
  const matchEvents = capture.events.filter(e => e.eventType === "dispatch-match");
452
453
  assert.equal(matchEvents.length, 1);
@@ -475,7 +476,7 @@ test("pre-dispatch-hook event is emitted when hooks fire", async () => {
475
476
  midTitle: "Test",
476
477
  };
477
478
 
478
- await runDispatch(ic, preData, { recentUnits: [], stuckRecoveryAttempts: 0 });
479
+ await runDispatch(ic, preData, { recentUnits: [], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 });
479
480
 
480
481
  const hookEvents = capture.events.filter(e => e.eventType === "pre-dispatch-hook");
481
482
  assert.equal(hookEvents.length, 1, "should emit one pre-dispatch-hook event");
@@ -497,7 +498,7 @@ test("terminal event is emitted on milestone-complete", async () => {
497
498
  }) as any,
498
499
  });
499
500
  const ic = makeIC(deps);
500
- const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0 };
501
+ const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 };
501
502
 
502
503
  const result = await runPreDispatch(ic, loopState);
503
504
  assert.equal(result.action, "break");
@@ -521,7 +522,7 @@ test("terminal event is emitted on blocked state", async () => {
521
522
  }) as any,
522
523
  });
523
524
  const ic = makeIC(deps);
524
- const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0 };
525
+ const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 };
525
526
 
526
527
  const result = await runPreDispatch(ic, loopState);
527
528
  assert.equal(result.action, "break");
@@ -550,7 +551,7 @@ test("milestone-transition event is emitted when milestone changes", async () =>
550
551
  const ic = makeIC(deps);
551
552
  // Session says current milestone is M001, but state will return M002
552
553
  ic.s.currentMilestoneId = "M001";
553
- const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0 };
554
+ const loopState: LoopState = { recentUnits: [], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 };
554
555
 
555
556
  await runPreDispatch(ic, loopState);
556
557
 
@@ -580,7 +581,7 @@ test("unit-end event contains errorContext when unit is cancelled with structure
580
581
  isRetry: false,
581
582
  previousTier: undefined,
582
583
  };
583
- const loopState: LoopState = { recentUnits: [{ key: "execute-task/M001/S01/T01" }], stuckRecoveryAttempts: 0 };
584
+ const loopState: LoopState = { recentUnits: [{ key: "execute-task/M001/S01/T01" }], stuckRecoveryAttempts: 0, consecutiveFinalizeTimeouts: 0 };
584
585
 
585
586
  const unitPromise = runUnitPhase(ic, iterData, loopState);
586
587
  await new Promise(r => setTimeout(r, 50));