@opengsd/gsd-pi 1.2.0-dev.844675c9 → 1.2.0-dev.955e4da0

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 (530) hide show
  1. package/dist/cli-web-branch.d.ts +2 -0
  2. package/dist/cli-web-branch.js +9 -2
  3. package/dist/help-text.js +5 -0
  4. package/dist/resources/.managed-resources-content-hash +1 -1
  5. package/dist/resources/extensions/ask-user-questions.js +78 -23
  6. package/dist/resources/extensions/bg-shell/utilities.js +2 -2
  7. package/dist/resources/extensions/claude-code-cli/models.js +9 -0
  8. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +92 -230
  9. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
  10. package/dist/resources/extensions/github-sync/templates.js +3 -3
  11. package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
  12. package/dist/resources/extensions/gsd/auto/loop.js +74 -56
  13. package/dist/resources/extensions/gsd/auto/orchestrator.js +142 -15
  14. package/dist/resources/extensions/gsd/auto/phases.js +34 -4
  15. package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
  16. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  17. package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
  18. package/dist/resources/extensions/gsd/auto-dispatch.js +6 -5
  19. package/dist/resources/extensions/gsd/auto-model-selection.js +8 -0
  20. package/dist/resources/extensions/gsd/auto-post-unit.js +12 -9
  21. package/dist/resources/extensions/gsd/auto-prompts.js +81 -8
  22. package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
  23. package/dist/resources/extensions/gsd/auto-runtime-state.js +14 -0
  24. package/dist/resources/extensions/gsd/auto-start.js +20 -36
  25. package/dist/resources/extensions/gsd/auto-timers.js +16 -2
  26. package/dist/resources/extensions/gsd/auto-tool-tracking.js +32 -0
  27. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +4 -29
  28. package/dist/resources/extensions/gsd/auto-verification.js +7 -7
  29. package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
  30. package/dist/resources/extensions/gsd/auto-worktree.js +34 -289
  31. package/dist/resources/extensions/gsd/auto.js +15 -14
  32. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
  33. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +20 -43
  34. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
  35. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +131 -140
  36. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +89 -8
  37. package/dist/resources/extensions/gsd/captures.js +5 -13
  38. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
  39. package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
  40. package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
  41. package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
  42. package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
  43. package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
  44. package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
  45. package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
  46. package/dist/resources/extensions/gsd/commands-ship.js +2 -2
  47. package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
  48. package/dist/resources/extensions/gsd/db/engine.js +755 -0
  49. package/dist/resources/extensions/gsd/db/queries.js +372 -0
  50. package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
  51. package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
  52. package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
  53. package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
  54. package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
  55. package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
  56. package/dist/resources/extensions/gsd/db-workspace.js +103 -0
  57. package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
  58. package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
  59. package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  60. package/dist/resources/extensions/gsd/doctor-environment.js +8 -10
  61. package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
  62. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +9 -2
  63. package/dist/resources/extensions/gsd/doctor.js +16 -9
  64. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  65. package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
  66. package/dist/resources/extensions/gsd/git-service.js +1 -0
  67. package/dist/resources/extensions/gsd/gitignore.js +3 -0
  68. package/dist/resources/extensions/gsd/gsd-db.js +183 -2048
  69. package/dist/resources/extensions/gsd/guided-flow.js +68 -471
  70. package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
  71. package/dist/resources/extensions/gsd/markdown-renderer.js +2 -1
  72. package/dist/resources/extensions/gsd/mcp-filter.js +2 -1
  73. package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
  74. package/dist/resources/extensions/gsd/md-importer.js +4 -3
  75. package/dist/resources/extensions/gsd/migrate/safety.js +19 -11
  76. package/dist/resources/extensions/gsd/migration-auto-check.js +27 -5
  77. package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
  78. package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
  79. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
  80. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
  81. package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
  82. package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
  83. package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
  84. package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
  85. package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
  86. package/dist/resources/extensions/gsd/model-router.js +3 -0
  87. package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
  88. package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
  89. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +7 -5
  90. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
  91. package/dist/resources/extensions/gsd/paths.js +10 -24
  92. package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
  93. package/dist/resources/extensions/gsd/preferences.js +161 -29
  94. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  95. package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
  96. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
  97. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  98. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  99. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  100. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  101. package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
  102. package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
  103. package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
  104. package/dist/resources/extensions/gsd/question-transport.js +86 -0
  105. package/dist/resources/extensions/gsd/recovery-classification.js +12 -1
  106. package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
  107. package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
  108. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
  109. package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
  110. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
  111. package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
  112. package/dist/resources/extensions/gsd/state.js +13 -5
  113. package/dist/resources/extensions/gsd/status-guards.js +56 -8
  114. package/dist/resources/extensions/gsd/templates/plan.md +7 -0
  115. package/dist/resources/extensions/gsd/templates/project.md +1 -0
  116. package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
  117. package/dist/resources/extensions/gsd/templates/uat.md +5 -1
  118. package/dist/resources/extensions/gsd/tool-contract.js +52 -8
  119. package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
  120. package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
  121. package/dist/resources/extensions/gsd/tools/complete-slice.js +24 -43
  122. package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -5
  123. package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
  124. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
  125. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +11 -29
  126. package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
  127. package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
  128. package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
  129. package/dist/resources/extensions/gsd/uat-policy.js +16 -10
  130. package/dist/resources/extensions/gsd/uat-run.js +9 -14
  131. package/dist/resources/extensions/gsd/undo.js +8 -7
  132. package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
  133. package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
  134. package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
  135. package/dist/resources/extensions/gsd/user-input-boundary.js +23 -0
  136. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  137. package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
  138. package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
  139. package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
  140. package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
  141. package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
  142. package/dist/resources/extensions/gsd/worktree-git-recovery.js +287 -0
  143. package/dist/resources/extensions/gsd/worktree-lifecycle.js +9 -1
  144. package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
  145. package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
  146. package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
  147. package/dist/resources/extensions/gsd/worktree-root.js +17 -6
  148. package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
  149. package/dist/resources/extensions/gsd/worktree-session-state.js +12 -10
  150. package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
  151. package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
  152. package/dist/resources/extensions/shared/interview-ui.js +2 -2
  153. package/dist/resources/shared/claude-runtime-floor.js +182 -0
  154. package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
  155. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  156. package/dist/update-cmd.js +20 -0
  157. package/dist/web/standalone/.next/BUILD_ID +1 -1
  158. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  159. package/dist/web/standalone/.next/build-manifest.json +3 -3
  160. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  161. package/dist/web/standalone/.next/react-loadable-manifest.json +8 -8
  162. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  163. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  164. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  165. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  166. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  167. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  168. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  169. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  170. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  171. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  172. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  173. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  174. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  175. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  176. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  177. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  178. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  179. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  180. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  182. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  183. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  184. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  185. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  186. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  187. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  188. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  189. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  190. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  191. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  192. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  193. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  194. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  195. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  196. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  197. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  198. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  199. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  200. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  201. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  202. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  203. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  204. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  205. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  206. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  207. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  208. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  209. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  210. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  211. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  212. package/dist/web/standalone/.next/server/app/index.html +1 -1
  213. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  214. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  215. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  216. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  217. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  218. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  219. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  220. package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
  221. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  222. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  223. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  224. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  225. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  226. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  227. package/dist/web/standalone/.next/static/chunks/2659.b7b129ee6a769448.js +1 -0
  228. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
  229. package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
  230. package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
  231. package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
  232. package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
  233. package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
  234. package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
  235. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  236. package/dist/web-mode.d.ts +2 -0
  237. package/dist/web-mode.js +20 -8
  238. package/dist/worktree-status-banner.js +7 -3
  239. package/package.json +2 -1
  240. package/packages/cloud-mcp-gateway/package.json +2 -2
  241. package/packages/contracts/package.json +1 -1
  242. package/packages/daemon/package.json +4 -4
  243. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
  244. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  245. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
  246. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  247. package/packages/gsd-agent-core/package.json +5 -5
  248. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  249. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +3 -0
  250. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  251. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  252. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +106 -40
  253. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  254. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
  255. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
  256. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
  257. package/packages/gsd-agent-modes/package.json +7 -7
  258. package/packages/mcp-server/dist/server.d.ts +10 -0
  259. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  260. package/packages/mcp-server/dist/server.js +8 -0
  261. package/packages/mcp-server/dist/server.js.map +1 -1
  262. package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
  263. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  264. package/packages/mcp-server/dist/workflow-tools.js +32 -22
  265. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  266. package/packages/mcp-server/package.json +3 -3
  267. package/packages/native/package.json +1 -1
  268. package/packages/pi-agent-core/package.json +1 -1
  269. package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
  270. package/packages/pi-ai/dist/image-models.generated.js +6 -6
  271. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  272. package/packages/pi-ai/dist/models.generated.d.ts +295 -98
  273. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  274. package/packages/pi-ai/dist/models.generated.js +309 -154
  275. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  276. package/packages/pi-ai/package.json +1 -1
  277. package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
  278. package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
  279. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  280. package/packages/pi-coding-agent/package.json +7 -7
  281. package/packages/pi-tui/dist/components/input.js +1 -1
  282. package/packages/pi-tui/dist/components/input.js.map +1 -1
  283. package/packages/pi-tui/dist/keys.d.ts.map +1 -1
  284. package/packages/pi-tui/dist/keys.js +39 -30
  285. package/packages/pi-tui/dist/keys.js.map +1 -1
  286. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  287. package/packages/pi-tui/dist/stdin-buffer.js +22 -0
  288. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  289. package/packages/pi-tui/package.json +2 -2
  290. package/packages/rpc-client/package.json +2 -2
  291. package/pkg/package.json +1 -1
  292. package/src/resources/extensions/ask-user-questions.ts +87 -24
  293. package/src/resources/extensions/bg-shell/utilities.ts +2 -2
  294. package/src/resources/extensions/claude-code-cli/models.ts +9 -0
  295. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +114 -281
  296. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +268 -0
  297. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
  298. package/src/resources/extensions/github-sync/templates.ts +3 -3
  299. package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
  300. package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
  301. package/src/resources/extensions/gsd/auto/contracts.ts +32 -2
  302. package/src/resources/extensions/gsd/auto/loop-deps.ts +3 -1
  303. package/src/resources/extensions/gsd/auto/loop.ts +83 -61
  304. package/src/resources/extensions/gsd/auto/orchestrator.ts +164 -17
  305. package/src/resources/extensions/gsd/auto/phases.ts +45 -4
  306. package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
  307. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  308. package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
  309. package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
  310. package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
  311. package/src/resources/extensions/gsd/auto-post-unit.ts +16 -8
  312. package/src/resources/extensions/gsd/auto-prompts.ts +107 -9
  313. package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
  314. package/src/resources/extensions/gsd/auto-runtime-state.ts +26 -0
  315. package/src/resources/extensions/gsd/auto-start.ts +25 -34
  316. package/src/resources/extensions/gsd/auto-timers.ts +16 -2
  317. package/src/resources/extensions/gsd/auto-tool-tracking.ts +35 -0
  318. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +9 -30
  319. package/src/resources/extensions/gsd/auto-verification.ts +7 -8
  320. package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
  321. package/src/resources/extensions/gsd/auto-worktree.ts +53 -306
  322. package/src/resources/extensions/gsd/auto.ts +27 -17
  323. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
  324. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +20 -43
  325. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
  326. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +147 -153
  327. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +132 -6
  328. package/src/resources/extensions/gsd/captures.ts +5 -14
  329. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
  330. package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
  331. package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
  332. package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
  333. package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
  334. package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
  335. package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
  336. package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
  337. package/src/resources/extensions/gsd/commands-ship.ts +2 -2
  338. package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
  339. package/src/resources/extensions/gsd/db/engine.ts +809 -0
  340. package/src/resources/extensions/gsd/db/queries.ts +453 -0
  341. package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
  342. package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
  343. package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
  344. package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
  345. package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
  346. package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
  347. package/src/resources/extensions/gsd/db-workspace.ts +170 -0
  348. package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
  349. package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
  350. package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  351. package/src/resources/extensions/gsd/doctor-environment.ts +8 -11
  352. package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
  353. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +10 -3
  354. package/src/resources/extensions/gsd/doctor.ts +15 -5
  355. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  356. package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
  357. package/src/resources/extensions/gsd/git-service.ts +1 -0
  358. package/src/resources/extensions/gsd/gitignore.ts +3 -0
  359. package/src/resources/extensions/gsd/gsd-db.ts +185 -2373
  360. package/src/resources/extensions/gsd/guided-flow.ts +81 -561
  361. package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
  362. package/src/resources/extensions/gsd/markdown-renderer.ts +2 -1
  363. package/src/resources/extensions/gsd/mcp-filter.ts +2 -1
  364. package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
  365. package/src/resources/extensions/gsd/md-importer.ts +3 -3
  366. package/src/resources/extensions/gsd/migrate/safety.ts +17 -9
  367. package/src/resources/extensions/gsd/migration-auto-check.ts +30 -5
  368. package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
  369. package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
  370. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
  371. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
  372. package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
  373. package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
  374. package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
  375. package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
  376. package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
  377. package/src/resources/extensions/gsd/model-router.ts +3 -0
  378. package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
  379. package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
  380. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +6 -5
  381. package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
  382. package/src/resources/extensions/gsd/paths.ts +9 -22
  383. package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
  384. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  385. package/src/resources/extensions/gsd/preferences.ts +191 -28
  386. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  387. package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
  388. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
  389. package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  390. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  391. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  392. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  393. package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
  394. package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
  395. package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
  396. package/src/resources/extensions/gsd/question-transport.ts +138 -0
  397. package/src/resources/extensions/gsd/recovery-classification.ts +14 -1
  398. package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
  399. package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
  400. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
  401. package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
  402. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
  403. package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
  404. package/src/resources/extensions/gsd/state.ts +15 -5
  405. package/src/resources/extensions/gsd/status-guards.ts +59 -8
  406. package/src/resources/extensions/gsd/templates/plan.md +7 -0
  407. package/src/resources/extensions/gsd/templates/project.md +1 -0
  408. package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
  409. package/src/resources/extensions/gsd/templates/uat.md +5 -1
  410. package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
  411. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
  412. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +444 -5
  413. package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
  414. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
  415. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +133 -4
  416. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
  417. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
  418. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
  419. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
  420. package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
  421. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
  422. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +22 -0
  423. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  424. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
  425. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
  426. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
  427. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
  428. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
  429. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
  430. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
  431. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
  432. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
  433. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
  434. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
  435. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +5 -4
  436. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +1 -1
  437. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
  438. package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
  439. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +143 -1
  440. package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
  441. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
  442. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
  443. package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
  444. package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
  445. package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
  446. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
  447. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  448. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
  449. package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
  450. package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
  451. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +46 -0
  452. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
  453. package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
  454. package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
  455. package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
  456. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +185 -1
  457. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
  458. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
  459. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
  460. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
  461. package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
  462. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +144 -7
  463. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
  464. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +2 -1
  465. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
  466. package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
  467. package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
  468. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
  469. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
  470. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
  471. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +86 -1
  472. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
  473. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
  474. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
  475. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
  476. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
  477. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +43 -1
  478. package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
  479. package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
  480. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
  481. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
  482. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
  483. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
  484. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
  485. package/src/resources/extensions/gsd/tests/write-gate.test.ts +121 -0
  486. package/src/resources/extensions/gsd/tool-contract.ts +86 -8
  487. package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
  488. package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
  489. package/src/resources/extensions/gsd/tools/complete-slice.ts +23 -58
  490. package/src/resources/extensions/gsd/tools/exec-tool.ts +5 -5
  491. package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
  492. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
  493. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +11 -38
  494. package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
  495. package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
  496. package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
  497. package/src/resources/extensions/gsd/uat-policy.ts +19 -10
  498. package/src/resources/extensions/gsd/uat-run.ts +10 -14
  499. package/src/resources/extensions/gsd/undo.ts +9 -8
  500. package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
  501. package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
  502. package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
  503. package/src/resources/extensions/gsd/user-input-boundary.ts +18 -0
  504. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  505. package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
  506. package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
  507. package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
  508. package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
  509. package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
  510. package/src/resources/extensions/gsd/worktree-git-recovery.ts +308 -0
  511. package/src/resources/extensions/gsd/worktree-lifecycle.ts +17 -17
  512. package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
  513. package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
  514. package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
  515. package/src/resources/extensions/gsd/worktree-root.ts +17 -6
  516. package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
  517. package/src/resources/extensions/gsd/worktree-session-state.ts +12 -10
  518. package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
  519. package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
  520. package/src/resources/extensions/shared/interview-ui.ts +15 -2
  521. package/src/resources/shared/claude-runtime-floor.ts +248 -0
  522. package/src/resources/skills/gsd-browser/SKILL.md +1 -1
  523. package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
  524. package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
  525. package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
  526. package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
  527. package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
  528. package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
  529. /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → C24pqUd-aru-l0Dp0gLZP}/_buildManifest.js +0 -0
  530. /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → C24pqUd-aru-l0Dp0gLZP}/_ssgManifest.js +0 -0
@@ -33,6 +33,8 @@ import type { UnifiedRule } from "../rule-types.js";
33
33
  import { supportsStructuredQuestions } from "../workflow-mcp.js";
34
34
  import {
35
35
  closeDatabase,
36
+ insertAssessment,
37
+ insertGateRow,
36
38
  insertMilestone,
37
39
  insertSlice,
38
40
  insertTask,
@@ -302,6 +304,46 @@ test("advance() sets active unit and is reflected in status", async (t) => {
302
304
  });
303
305
  });
304
306
 
307
+ test("advance() blocks source dispatch when an earlier slice is incomplete", async (t) => {
308
+ const f = makeFixture({
309
+ dispatch: () => ({
310
+ action: "dispatch",
311
+ unitType: "execute-task",
312
+ unitId: "M001/S02/T01",
313
+ prompt: "fixture-prompt",
314
+ }),
315
+ });
316
+ t.after(() => f.cleanup());
317
+
318
+ insertSlice({
319
+ id: "S02",
320
+ milestoneId: "M001",
321
+ title: "Second slice",
322
+ status: "active",
323
+ risk: "low",
324
+ depends: [],
325
+ demo: "",
326
+ sequence: 2,
327
+ });
328
+ insertTask({
329
+ id: "T01",
330
+ sliceId: "S02",
331
+ milestoneId: "M001",
332
+ title: "Second task",
333
+ status: "active",
334
+ });
335
+
336
+ const result = await f.orchestrator.advance();
337
+
338
+ assert.equal(result.kind, "blocked");
339
+ if (result.kind !== "blocked") return;
340
+ assert.equal(result.action, "stop");
341
+ assert.match(result.reason, /earlier slice M001\/S01 is not complete/);
342
+ assert.equal(f.session.pendingOrchestrationDispatch, null);
343
+ assert.deepEqual(f.orchestrator.getStatus().activeUnit, undefined);
344
+ assert.ok(f.journalNames().includes("advance-blocked"));
345
+ });
346
+
305
347
  test("getStatus() returns defensive copy of activeUnit", async (t) => {
306
348
  const f = makeFixture();
307
349
  t.after(() => f.cleanup());
@@ -374,10 +416,65 @@ test("advance() reports completion when complete state has no next unit", async
374
416
 
375
417
  assert.equal(result.kind, "stopped");
376
418
  if (result.kind !== "stopped") return;
377
- assert.equal(result.reason, "all milestones complete");
419
+ assert.equal(result.reason, "All milestones complete");
420
+ assert.equal(result.terminalOutcome?.code, "all-complete");
378
421
  assert.equal(f.orchestrator.getStatus().phase, "stopped");
379
422
  });
380
423
 
424
+ test("advance() blocks all-complete stop when completed milestone is still unmerged in a worktree", async (t) => {
425
+ const f = makeFixture({ complete: true, noTask: true });
426
+ t.after(() => f.cleanup());
427
+
428
+ insertSlice({
429
+ id: "S01",
430
+ milestoneId: "M001",
431
+ title: "Slice",
432
+ status: "complete",
433
+ risk: "low",
434
+ depends: [],
435
+ demo: "",
436
+ sequence: 1,
437
+ });
438
+ insertAssessment({
439
+ path: "milestones/M001/M001-VALIDATION.md",
440
+ milestoneId: "M001",
441
+ status: "pass",
442
+ scope: "milestone-validation",
443
+ fullContent: "verdict: pass",
444
+ });
445
+ insertGateRow({
446
+ milestoneId: "M001",
447
+ sliceId: "S01",
448
+ gateId: "Q3",
449
+ scope: "slice",
450
+ status: "pending",
451
+ });
452
+
453
+ const worktreePath = join(f.base, ".gsd", "worktrees", "M001");
454
+ mkdirSync(join(f.base, ".gsd", "worktrees"), { recursive: true });
455
+ execFileSync("git", ["worktree", "add", "-b", "milestone/M001", worktreePath], { cwd: f.base, stdio: "ignore" });
456
+ mkdirSync(join(worktreePath, ".gsd", "milestones", "M001"), { recursive: true });
457
+ writeFileSync(join(worktreePath, ".gsd", "milestones", "M001", "M001-SUMMARY.md"), "# Milestone Summary\n");
458
+ f.session.basePath = worktreePath;
459
+ f.session.originalBasePath = f.base;
460
+ f.session.currentMilestoneId = "M001";
461
+ f.session.milestoneMergedInPhases = false;
462
+
463
+ const result = await f.orchestrator.advance();
464
+
465
+ assert.equal(result.kind, "blocked");
466
+ if (result.kind !== "blocked") return;
467
+ assert.equal(result.action, "pause");
468
+ assert.equal(result.terminalOutcome?.code, "settlement-blocked");
469
+ assert.match(result.reason, /worktree branch has not been merged to main/);
470
+ assert.doesNotMatch(result.reason, /quality gate Q3 is still pending/);
471
+ assert.equal(f.orchestrator.getStatus().phase, "paused");
472
+ assert.equal(f.session.milestoneSettlement?.ok, false);
473
+ const names = f.journalNames();
474
+ assert.ok(names.includes("advance-blocked"));
475
+ assert.ok(!names.includes("advance-stopped"));
476
+ });
477
+
381
478
  test("advance() stopped clears previous activeUnit and resets idempotent lock", async (t) => {
382
479
  // First advance dispatches; then we make the milestone resolve to no unit by
383
480
  // closing it on disk + DB and re-deriving. Simpler: drive a fixture that
@@ -696,7 +793,10 @@ test("stuck-loop: start() resets the ring so a fresh saturation cycle is require
696
793
  assert.equal(next.kind, "advanced");
697
794
  });
698
795
 
699
- test("stuck-loop: resume() resets the ring", async (t) => {
796
+ test("stuck-loop: resume() preserves ring so detection accumulates across pause/resume", async (t) => {
797
+ // Regression for #572: resume() must NOT reset dispatchKeyWindow. Before the
798
+ // fix, a pause/resume cycle cleared the window, letting a stuck loop silently
799
+ // re-accumulate STUCK_WINDOW_SIZE dispatches before being detected again.
700
800
  const f = makeFixture();
701
801
  t.after(() => f.cleanup());
702
802
 
@@ -707,11 +807,39 @@ test("stuck-loop: resume() resets the ring", async (t) => {
707
807
  const resumed = await f.orchestrator.resume();
708
808
  assert.equal(resumed.kind, "resumed");
709
809
 
810
+ // The ring is preserved, so the next advance pushes it to STUCK_WINDOW_SIZE
811
+ // and triggers stuck-loop detection — not a fresh dispatch.
710
812
  const next = await f.orchestrator.advance();
711
- assert.equal(next.kind, "advanced");
813
+ assert.equal(next.kind, "blocked");
814
+ if (next.kind !== "blocked") return;
815
+ assert.equal(next.action, "stop");
816
+ assert.ok(next.reason.startsWith("stuck-loop:"), `expected stuck-loop reason, got: ${next.reason}`);
817
+ });
818
+
819
+ test("stuck-loop: stop('pause') preserves ring across the stop/resume cycle", async (t) => {
820
+ // Regression for #572: stop("pause") must behave the same as resume() —
821
+ // the window must survive so detection accumulates across pause/resume pairs.
822
+ const f = makeFixture();
823
+ t.after(() => f.cleanup());
824
+
825
+ for (let i = 0; i < STUCK_WINDOW_SIZE - 1; i++) {
826
+ await f.orchestrator.advance();
827
+ }
828
+
829
+ const stopped = await f.orchestrator.stop("pause");
830
+ assert.equal(stopped.kind, "stopped");
831
+
832
+ const resumed = await f.orchestrator.resume();
833
+ assert.equal(resumed.kind, "resumed");
834
+
835
+ const next = await f.orchestrator.advance();
836
+ assert.equal(next.kind, "blocked");
837
+ if (next.kind !== "blocked") return;
838
+ assert.equal(next.action, "stop");
839
+ assert.ok(next.reason.startsWith("stuck-loop:"), `expected stuck-loop reason, got: ${next.reason}`);
712
840
  });
713
841
 
714
- test("stuck-loop: stop() resets the ring", async (t) => {
842
+ test("stuck-loop: stop('user-request') resets the ring (hard stop)", async (t) => {
715
843
  const f = makeFixture();
716
844
  t.after(() => f.cleanup());
717
845
 
@@ -722,6 +850,7 @@ test("stuck-loop: stop() resets the ring", async (t) => {
722
850
  const stopped = await f.orchestrator.stop("user-request");
723
851
  assert.equal(stopped.kind, "stopped");
724
852
 
853
+ // Hard stop clears the ring, so the next advance dispatches fresh.
725
854
  const next = await f.orchestrator.advance();
726
855
  assert.equal(next.kind, "advanced");
727
856
  });
@@ -306,7 +306,9 @@ test("pauseAuto records the expected worktree path when paused from project root
306
306
 
307
307
  const meta = readPausedSessionMetadata(base);
308
308
  assert.ok(meta);
309
- assert.equal(meta.worktreePath, join(base, ".gsd", "worktrees", "M001"));
309
+ // No worktree exists yet, so the recorded path is the canonical
310
+ // .gsd-worktrees/ creation location (worktree-placement seam).
311
+ assert.equal(meta.worktreePath, join(base, ".gsd-worktrees", "M001"));
310
312
  } finally {
311
313
  autoSession.reset();
312
314
  try {
@@ -88,3 +88,49 @@ test("detects session execution tools supported by the evidence collector", () =
88
88
 
89
89
  assert.equal(_hasExecutionToolCallsInSessionForTest(entries), true);
90
90
  });
91
+
92
+ test("detects execution tool calls in bare agent-end messages (no session-entry wrapper)", () => {
93
+ // The auto loop passes opts.agentEndMessages as bare {role, content}
94
+ // messages — not {type: "message", message} session-manager entries.
95
+ const entries = [
96
+ {
97
+ role: "assistant",
98
+ content: [
99
+ {
100
+ type: "toolCall",
101
+ name: "Bash",
102
+ arguments: { command: "test -s index.html && grep -q localStorage index.html" },
103
+ },
104
+ ],
105
+ },
106
+ ];
107
+
108
+ assert.equal(_hasExecutionToolCallsInSessionForTest(entries), true);
109
+ });
110
+
111
+ test("does not suppress for bare agent-end messages without execution tools", () => {
112
+ const entries = [
113
+ {
114
+ role: "assistant",
115
+ content: [
116
+ { type: "text", text: "Task complete." },
117
+ { type: "toolCall", name: "Write", arguments: { file_path: "index.html" } },
118
+ ],
119
+ },
120
+ ];
121
+
122
+ assert.equal(_hasExecutionToolCallsInSessionForTest(entries), false);
123
+ });
124
+
125
+ test("ignores bare user messages with toolCall-shaped content", () => {
126
+ const entries = [
127
+ {
128
+ role: "user",
129
+ content: [
130
+ { type: "toolCall", name: "bash", arguments: { command: "echo hi" } },
131
+ ],
132
+ },
133
+ ];
134
+
135
+ assert.equal(_hasExecutionToolCallsInSessionForTest(entries), false);
136
+ });
@@ -6,12 +6,15 @@ import assert from "node:assert/strict";
6
6
 
7
7
  import {
8
8
  autoSession,
9
+ clearAutoToolSurfaceSnapshot,
9
10
  clearToolInvocationError,
10
11
  getAutoRuntimeSnapshot,
12
+ recordAutoToolSurfaceSnapshot,
11
13
  } from "../auto-runtime-state.ts";
12
14
 
13
15
  test("getAutoRuntimeSnapshot includes orchestration phase when available", () => {
14
16
  autoSession.reset();
17
+ clearAutoToolSurfaceSnapshot();
15
18
  autoSession.active = true;
16
19
  autoSession.basePath = "/tmp/project";
17
20
  autoSession.orchestration = {
@@ -33,10 +36,40 @@ test("getAutoRuntimeSnapshot includes orchestration phase when available", () =>
33
36
  assert.equal(snap.orchestrationPhase, "running");
34
37
  assert.equal(snap.orchestrationTransitionCount, 3);
35
38
  assert.equal(snap.orchestrationLastTransitionAt, 123);
39
+ assert.equal(snap.toolSurface, null);
36
40
 
37
41
  autoSession.reset();
38
42
  });
39
43
 
44
+ test("getAutoRuntimeSnapshot includes the active typed tool-surface snapshot", () => {
45
+ autoSession.reset();
46
+ clearAutoToolSurfaceSnapshot();
47
+ autoSession.active = true;
48
+
49
+ recordAutoToolSurfaceSnapshot({
50
+ source: "dispatch-scope",
51
+ unitType: "run-uat",
52
+ modelFacingToolNames: ["read", "read", "gsd_uat_exec"],
53
+ registeredToolNames: ["read", "browser_navigate"],
54
+ scopedToolNames: ["read", "browser_navigate"],
55
+ presentedToolNames: ["gsd_uat_exec"],
56
+ capturedAt: 123,
57
+ });
58
+
59
+ const snap = getAutoRuntimeSnapshot();
60
+
61
+ assert.equal(snap.toolSurface?.source, "dispatch-scope");
62
+ assert.equal(snap.toolSurface?.unitType, "run-uat");
63
+ assert.deepEqual(snap.toolSurface?.modelFacingToolNames, ["read", "gsd_uat_exec"]);
64
+ assert.deepEqual(snap.toolSurface?.registeredToolNames, ["read", "browser_navigate"]);
65
+ assert.deepEqual(snap.toolSurface?.scopedToolNames, ["read", "browser_navigate"]);
66
+ assert.deepEqual(snap.toolSurface?.presentedToolNames, ["gsd_uat_exec"]);
67
+ assert.equal(snap.toolSurface?.capturedAt, 123);
68
+
69
+ autoSession.reset();
70
+ clearAutoToolSurfaceSnapshot();
71
+ });
72
+
40
73
  test("clearToolInvocationError clears stale tool error state for active auto sessions", () => {
41
74
  autoSession.reset();
42
75
  autoSession.active = true;
@@ -56,4 +89,5 @@ test("getAutoRuntimeSnapshot omits orchestration phase when seam not wired", ()
56
89
  assert.equal(snap.orchestrationPhase, undefined);
57
90
  assert.equal(snap.orchestrationTransitionCount, undefined);
58
91
  assert.equal(snap.orchestrationLastTransitionAt, undefined);
92
+ assert.equal(snap.toolSurface, null);
59
93
  });
@@ -184,7 +184,7 @@ describe("auto-worktree workspace registry", () => {
184
184
  git(["commit", "-m", "add milestone"], tempDir);
185
185
 
186
186
  createAutoWorktree(tempDir, "M003");
187
- const wtDir = join(tempDir, ".gsd", "worktrees", "M003");
187
+ const wtDir = join(tempDir, ".gsd-worktrees", "M003");
188
188
  writeFileSync(join(wtDir, "feature.txt"), "implemented\n");
189
189
  git(["add", "feature.txt"], wtDir);
190
190
  git(["commit", "-m", "feat: implement M003"], wtDir);
@@ -216,7 +216,7 @@ describe("auto-worktree workspace registry", () => {
216
216
  git(["commit", "-m", "add milestone"], tempDir);
217
217
 
218
218
  createAutoWorktree(tempDir, "M004");
219
- const wtDir = join(tempDir, ".gsd", "worktrees", "M004");
219
+ const wtDir = join(tempDir, ".gsd-worktrees", "M004");
220
220
  writeFileSync(join(wtDir, "feature.txt"), "implemented\n");
221
221
  git(["add", "feature.txt"], wtDir);
222
222
  git(["commit", "-m", "feat: implement M004"], wtDir);
@@ -35,7 +35,8 @@ test("repair target accepts a missing expected milestone worktree", () => {
35
35
 
36
36
  assert.equal(result.ok, true);
37
37
  if (result.ok) {
38
- assert.equal(result.expectedPath, join(base, ".gsd", "worktrees", "M001"));
38
+ // No worktree exists yet, so the expected path is the canonical container.
39
+ assert.equal(result.expectedPath, join(base, ".gsd-worktrees", "M001"));
39
40
  }
40
41
  } finally {
41
42
  cleanup(base);
@@ -192,7 +193,8 @@ test("paused metadata path resolves to the expected worktree while paused at pro
192
193
  baseIsAutoWorktree: false,
193
194
  });
194
195
 
195
- assert.equal(result, join(base, ".gsd", "worktrees", "M001"));
196
+ // No worktree exists yet, so resolution lands at the canonical container.
197
+ assert.equal(result, join(base, ".gsd-worktrees", "M001"));
196
198
  } finally {
197
199
  cleanup(base);
198
200
  }
@@ -17,6 +17,7 @@ import { tmpdir } from "node:os";
17
17
  import { randomUUID } from "node:crypto";
18
18
 
19
19
  import { resolveCanonicalMilestoneRoot } from "../worktree-manager.ts";
20
+ import { resolveCloseoutArtifactProjection } from "../artifact-projection.ts";
20
21
 
21
22
  function makeTmpBase(): string {
22
23
  const base = join(tmpdir(), `gsd-canon-test-${randomUUID()}`);
@@ -106,3 +107,22 @@ test("only returns the worktree for the requested milestone, not siblings", () =
106
107
  cleanup(base);
107
108
  }
108
109
  });
110
+
111
+ test("resolveCloseoutArtifactProjection names project and canonical artifact roots", () => {
112
+ const base = makeTmpBase();
113
+ try {
114
+ const wtPath = makeLiveWorktree(base, "M001");
115
+ const projection = resolveCloseoutArtifactProjection({
116
+ milestoneId: "M001",
117
+ basePath: wtPath,
118
+ originalBasePath: base,
119
+ });
120
+
121
+ assert.equal(projection.projectRoot, base);
122
+ assert.equal(projection.canonicalMilestoneRoot, wtPath);
123
+ assert.equal(projection.summaryArtifactBasePath, wtPath);
124
+ assert.equal(projection.gateEvidenceBasePath, wtPath);
125
+ } finally {
126
+ cleanup(base);
127
+ }
128
+ });
@@ -73,4 +73,26 @@ describe("clear stale pending auto-start (#3667)", () => {
73
73
  "pending auto-start gate must clear stale map entries for completed discussions",
74
74
  );
75
75
  });
76
+
77
+ test("guided-flow does not treat a live discuss turn as a stale pending entry", () => {
78
+ const source = readFileSync(join(__dirname, "..", "guided-flow.ts"), "utf-8");
79
+ assert.ok(
80
+ source.includes("!isAgentTurnInFlight(ctx)"),
81
+ "stale-entry deletion must be gated on no agent turn being in flight — a dispatched " +
82
+ "discuss turn can think for over 30s before writing its first artifact, and deleting " +
83
+ "its entry re-dispatches the workflow (duplicate interview + duplicate completion message)",
84
+ );
85
+ assert.ok(
86
+ source.includes('const milestoneHasDraft = !!resolveMilestoneFile(basePath, entry.milestoneId, "CONTEXT-DRAFT");'),
87
+ "stale-entry check must treat an existing CONTEXT-DRAFT as proof of an in-progress interview",
88
+ );
89
+ assert.ok(
90
+ source.includes("!milestoneHasDraft"),
91
+ "stale-entry deletion must require the CONTEXT-DRAFT to be absent",
92
+ );
93
+ assert.ok(
94
+ source.includes("ctx.hasPendingMessages"),
95
+ "in-flight detection must also cover dispatched-but-not-yet-started queued messages",
96
+ );
97
+ });
76
98
  });
@@ -696,3 +696,25 @@ test("ensureCodebaseMapFresh: does not rewrite expired metadata when fingerprint
696
696
  cleanup(base);
697
697
  }
698
698
  });
699
+
700
+ test("ensureCodebaseMapFresh: detects file changes within the TTL window", () => {
701
+ const base = makeTmpRepo();
702
+ try {
703
+ addFile(base, "src/main.ts");
704
+ // Generate initial map with a long TTL so the cache is still active.
705
+ const initial = ensureCodebaseMapFresh(base, undefined, { ttlMs: 60_000 });
706
+ assert.equal(initial.status, "generated");
707
+
708
+ // Add a new tracked file while the TTL is still active.
709
+ addFile(base, "src/new.ts");
710
+
711
+ // Must detect the change even though the TTL has not expired.
712
+ const refreshed = ensureCodebaseMapFresh(base, undefined, { ttlMs: 60_000 });
713
+ assert.equal(refreshed.status, "updated");
714
+ assert.equal(refreshed.reason, "files-changed");
715
+ const written = readCodebaseMap(base);
716
+ assert.ok(written?.includes("`src/new.ts`"));
717
+ } finally {
718
+ cleanup(base);
719
+ }
720
+ });
@@ -64,3 +64,14 @@ test("getWorkspaceGitBlockMessageForBase allows doctor on product conflicts", as
64
64
  cleanup(base);
65
65
  }
66
66
  });
67
+
68
+ test("getWorkspaceGitBlockMessageForBase allows forensics on product conflicts", async () => {
69
+ const base = makeTempRepo("gsd-dispatch-ws-git-forensics-");
70
+ try {
71
+ seedProductConflict(base);
72
+ const blocked = await getWorkspaceGitBlockMessageForBase(base, "forensics");
73
+ assert.equal(blocked, null);
74
+ } finally {
75
+ cleanup(base);
76
+ }
77
+ });
@@ -10,7 +10,7 @@
10
10
  */
11
11
  import test from "node:test";
12
12
  import assert from "node:assert/strict";
13
- import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
13
+ import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, statSync, writeFileSync } from "node:fs";
14
14
  import { join } from "node:path";
15
15
  import { tmpdir } from "node:os";
16
16
  import { randomUUID } from "node:crypto";
@@ -486,3 +486,40 @@ test("state.ts needs-remediation blocker messages reference /gsd verdict", async
486
486
  `expected at least 2 references to /gsd verdict in state.ts blockers, found ${occurrences.length}`,
487
487
  );
488
488
  });
489
+
490
+ // ─── WAL checkpoint regression (#563) ───────────────────────────────────
491
+
492
+ test("handleVerdict pass checkpoints WAL so subsequent processes see the updated verdict (#563)", async () => {
493
+ // Regression: before the fix, executeValidateMilestone wrote the assessment
494
+ // only into the WAL file. The next /gsd auto invocation (a new process)
495
+ // opened gsd.db directly and saw stale pre-verdict data because the WAL
496
+ // had not been flushed. The fix adds checkpointDatabase() after a
497
+ // successful verdict so the WAL is truncated and gsd.db is self-contained.
498
+ const base = makeBase();
499
+ try {
500
+ openTestDb(base);
501
+ seedMilestone("M001", "Checkpoint Test Milestone");
502
+ seedSlice("M001", "S01", "complete");
503
+ writeValidation(base, "M001", "needs-attention");
504
+
505
+ const { ctx } = makeMockCtx();
506
+ await handleVerdict("pass --milestone M001", ctx, base);
507
+
508
+ // After handleVerdict succeeds, PRAGMA wal_checkpoint(TRUNCATE) must have
509
+ // run. The WAL file is truncated to zero bytes — a new process reading
510
+ // gsd.db directly sees the updated verdict without needing the WAL.
511
+ const walPath = join(base, ".gsd", "gsd.db-wal");
512
+ if (existsSync(walPath)) {
513
+ const { size } = statSync(walPath);
514
+ assert.equal(
515
+ size,
516
+ 0,
517
+ "WAL must be zero bytes after handleVerdict pass — checkpointDatabase() was not called (#563)",
518
+ );
519
+ }
520
+ } finally {
521
+ closeDatabase();
522
+ invalidateStateCache();
523
+ cleanup(base);
524
+ }
525
+ });
@@ -14,7 +14,15 @@ import { execFileSync } from "node:child_process";
14
14
 
15
15
  import { DISPATCH_RULES, resolveDispatch, type DispatchContext } from "../auto-dispatch.ts";
16
16
  import { AutoSession } from "../auto/session.ts";
17
- import { closeDatabase, insertAssessment, insertGateRow, insertMilestone, insertSlice, openDatabase } from "../gsd-db.ts";
17
+ import {
18
+ closeDatabase,
19
+ getPendingGates,
20
+ insertAssessment,
21
+ insertGateRow,
22
+ insertMilestone,
23
+ insertSlice,
24
+ openDatabase,
25
+ } from "../gsd-db.ts";
18
26
 
19
27
  function makeBase(): string {
20
28
  const base = mkdtempSync(join(tmpdir(), "gsd-complete-dispatch-"));
@@ -243,7 +251,7 @@ describe("complete phase dispatch guard (#5683)", () => {
243
251
  assert.equal(result?.reason, "All milestones complete.");
244
252
  });
245
253
 
246
- test("blocks terminal stop when closed milestone still has pending gates", async () => {
254
+ test("closes stale pending gates from milestone validation before terminal stop", async () => {
247
255
  base = makeBase();
248
256
  openDatabase(join(base, ".gsd", "gsd.db"));
249
257
  insertMilestone({ id: "M001", title: "Milestone One", status: "complete" });
@@ -268,10 +276,33 @@ describe("complete phase dispatch guard (#5683)", () => {
268
276
 
269
277
  const result = await rule.match(ctx);
270
278
 
279
+ assert.equal(result?.action, "stop");
280
+ assert.equal(result?.reason, "All milestones complete.");
281
+ assert.deepEqual(getPendingGates("M001", "S01"), []);
282
+ });
283
+
284
+ test("blocks terminal stop when pending gates have no closeout evidence", async () => {
285
+ base = makeBase();
286
+ openDatabase(join(base, ".gsd", "gsd.db"));
287
+ insertMilestone({ id: "M001", title: "Milestone One", status: "complete" });
288
+ insertSlice({ milestoneId: "M001", id: "S01", title: "Done", status: "complete" });
289
+ insertGateRow({
290
+ milestoneId: "M001",
291
+ sliceId: "S01",
292
+ gateId: "Q3",
293
+ scope: "slice",
294
+ status: "pending",
295
+ });
296
+
297
+ const ctx = buildDispatchCtx(base);
298
+ ctx.state.phase = "complete";
299
+
300
+ const result = await rule.match(ctx);
301
+
271
302
  assert.equal(result?.action, "stop");
272
303
  assert.equal(result?.level, "warning");
273
304
  assert.match(result?.reason ?? "", /closeout-consistency-blocked/);
274
- assert.match(result?.reason ?? "", /quality gate Q3 is still pending/);
305
+ assert.match(result?.reason ?? "", /latest milestone validation is "absent"/);
275
306
  });
276
307
  });
277
308
 
@@ -0,0 +1,88 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Regression coverage for run-uat browser tool availability checks.
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert/strict";
6
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
7
+ import { tmpdir } from "node:os";
8
+ import { join } from "node:path";
9
+
10
+ import { DISPATCH_RULES, type DispatchContext } from "../auto-dispatch.ts";
11
+ import type { GSDState } from "../types.ts";
12
+
13
+ type DispatchRuleEntry = (typeof DISPATCH_RULES)[number];
14
+
15
+ function runUatRule(): DispatchRuleEntry {
16
+ const rule = DISPATCH_RULES.find((entry) => entry.name === "run-uat (post-completion)");
17
+ assert.ok(rule, "run-uat dispatch rule must exist");
18
+ return rule;
19
+ }
20
+
21
+ function makeState(): GSDState {
22
+ return {
23
+ activeMilestone: { id: "M001", title: "Browser UAT" },
24
+ activeSlice: { id: "S02", title: "Next Slice" },
25
+ activeTask: null,
26
+ phase: "verifying",
27
+ recentDecisions: [],
28
+ blockers: [],
29
+ nextAction: "",
30
+ registry: [],
31
+ };
32
+ }
33
+
34
+ function scaffoldRunUatProject(basePath: string): void {
35
+ const milestoneDir = join(basePath, ".gsd", "milestones", "M001");
36
+ const sliceDir = join(milestoneDir, "slices", "S01");
37
+ mkdirSync(sliceDir, { recursive: true });
38
+
39
+ writeFileSync(join(milestoneDir, "M001-ROADMAP.md"), [
40
+ "# M001: Browser UAT",
41
+ "",
42
+ "## Slices",
43
+ "",
44
+ "- [x] **S01: Completed browser slice** `risk:low` `depends:[]`",
45
+ "- [ ] **S02: Next slice** `risk:low` `depends:[S01]`",
46
+ "",
47
+ ].join("\n"), "utf-8");
48
+
49
+ writeFileSync(join(sliceDir, "S01-SUMMARY.md"), "# S01 Summary\n\nDone.\n", "utf-8");
50
+ writeFileSync(join(sliceDir, "S01-UAT.md"), [
51
+ "# S01 UAT",
52
+ "",
53
+ "## UAT Type",
54
+ "- UAT mode: human-experience",
55
+ "",
56
+ "Open the app in a browser and verify the completed user flow.",
57
+ "",
58
+ ].join("\n"), "utf-8");
59
+ }
60
+
61
+ function makeContext(basePath: string, overrides: Partial<DispatchContext> = {}): DispatchContext {
62
+ return {
63
+ basePath,
64
+ mid: "M001",
65
+ midTitle: "Browser UAT",
66
+ state: makeState(),
67
+ prefs: undefined,
68
+ activeTools: ["read", "gsd_uat_exec", "gsd_uat_result_save"],
69
+ ...overrides,
70
+ };
71
+ }
72
+
73
+ test("run-uat browser preflight uses registered tools when the active surface is scoped", async (t) => {
74
+ const basePath = mkdtempSync(join(tmpdir(), "gsd-run-uat-browser-tools-"));
75
+ t.after(() => rmSync(basePath, { recursive: true, force: true }));
76
+ scaffoldRunUatProject(basePath);
77
+
78
+ const blocked = await runUatRule().match(makeContext(basePath));
79
+ assert.equal(blocked?.action, "stop");
80
+ assert.match(blocked?.action === "stop" ? blocked.reason : "", /run-uat tool surface has none/);
81
+
82
+ const dispatched = await runUatRule().match(makeContext(basePath, {
83
+ registeredTools: ["browser_navigate"],
84
+ }));
85
+ assert.equal(dispatched?.action, "dispatch");
86
+ assert.equal(dispatched?.action === "dispatch" ? dispatched.unitType : undefined, "run-uat");
87
+ assert.equal(dispatched?.action === "dispatch" ? dispatched.unitId : undefined, "M001/S01");
88
+ });