@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
@@ -9,8 +9,7 @@
9
9
  * This function performs DB writes only. The MCP wrapper in
10
10
  * bootstrap/db-tools.ts handles state-cache invalidation and STATE.md rebuild.
11
11
  */
12
- import { getSlice, getSliceTasks, isDbAvailable, transaction, updateSliceStatus, updateTaskStatus, } from "../gsd-db.js";
13
- import { isClosedStatus } from "../status-guards.js";
12
+ import { isDbAvailable, skipSliceCascade, } from "../gsd-db.js";
14
13
  /**
15
14
  * Mark a slice as "skipped" and cascade the skip to every non-closed task in
16
15
  * that slice. Runs as a single transaction so slice status and task statuses
@@ -39,40 +38,23 @@ export function handleSkipSlice(params) {
39
38
  if (!isDbAvailable()) {
40
39
  throw new Error("handleSkipSlice: GSD database is not available");
41
40
  }
42
- // ── Guards + DB writes inside a single transaction (prevents TOCTOU) ────
43
- let guardError = null;
44
- let guardCode = null;
45
- let wasAlreadySkipped = false;
46
- let tasksSkipped = 0;
47
- transaction(() => {
48
- const slice = getSlice(params.milestoneId, params.sliceId);
49
- if (!slice) {
50
- guardError = `Slice ${params.sliceId} not found in milestone ${params.milestoneId}`;
51
- guardCode = "slice_not_found";
52
- return;
41
+ // ── Atomic skip cascade (guards + writes in one transaction) ────────────
42
+ const outcome = skipSliceCascade(params.milestoneId, params.sliceId);
43
+ if (!outcome.ok) {
44
+ switch (outcome.reason) {
45
+ case "slice-not-found":
46
+ return {
47
+ ...base,
48
+ error: `Slice ${params.sliceId} not found in milestone ${params.milestoneId}`,
49
+ errorCode: "slice_not_found",
50
+ };
51
+ case "slice-already-complete":
52
+ return {
53
+ ...base,
54
+ error: `Slice ${params.sliceId} is already complete — cannot skip.`,
55
+ errorCode: "already_complete",
56
+ };
53
57
  }
54
- if (slice.status === "complete" || slice.status === "done") {
55
- guardError = `Slice ${params.sliceId} is already complete — cannot skip.`;
56
- guardCode = "already_complete";
57
- return;
58
- }
59
- wasAlreadySkipped = slice.status === "skipped";
60
- if (!wasAlreadySkipped) {
61
- updateSliceStatus(params.milestoneId, params.sliceId, "skipped");
62
- }
63
- // Cascade: mark every non-closed task as skipped so milestone completion
64
- // doesn't trip the deep-task guard (#4375). Closed tasks (complete/done/
65
- // skipped) are left untouched — we never downgrade.
66
- const tasks = getSliceTasks(params.milestoneId, params.sliceId);
67
- for (const task of tasks) {
68
- if (!isClosedStatus(task.status)) {
69
- updateTaskStatus(params.milestoneId, params.sliceId, task.id, "skipped");
70
- tasksSkipped++;
71
- }
72
- }
73
- });
74
- if (guardError) {
75
- return { ...base, error: guardError, errorCode: guardCode ?? undefined };
76
58
  }
77
- return { ...base, tasksSkipped, wasAlreadySkipped };
59
+ return { ...base, tasksSkipped: outcome.tasksSkipped, wasAlreadySkipped: outcome.wasAlreadySkipped };
78
60
  }
@@ -11,10 +11,11 @@
11
11
  * despite passing validation.
12
12
  */
13
13
  import { join } from "node:path";
14
- import { transaction, insertAssessment, getMilestoneSlices, getMilestone, getArtifact, } from "../gsd-db.js";
15
- import { gsdProjectionRoot, clearPathCache, resolveSliceFile } from "../paths.js";
14
+ import { transaction, insertAssessment, getMilestoneSlices, getMilestone, } from "../gsd-db.js";
15
+ import { gsdProjectionRoot, clearPathCache } from "../paths.js";
16
16
  import { resolveCanonicalMilestoneRoot } from "../worktree-manager.js";
17
- import { saveFile, clearParseCache, loadFile } from "../files.js";
17
+ import { resolveWorktreeProjectRoot } from "../worktree-root.js";
18
+ import { saveFile, clearParseCache } from "../files.js";
18
19
  import { invalidateStateCache } from "../state.js";
19
20
  import { VALIDATION_VERDICTS, isValidMilestoneVerdict } from "../verdict-parser.js";
20
21
  import { insertMilestoneValidationGates } from "../milestone-validation-gates.js";
@@ -22,7 +23,7 @@ import { logWarning } from "../workflow-logger.js";
22
23
  import { UokGateRunner } from "../uok/gate-runner.js";
23
24
  import { loadEffectiveGSDPreferences } from "../preferences.js";
24
25
  import { resolveUokFlags } from "../uok/flags.js";
25
- import { compactTextParts, hasBrowserEvidenceText, hasBrowserRequiredText } from "../browser-evidence.js";
26
+ import { applyBrowserEvidenceGate, browserEvidenceGateRequiresAttention, } from "../milestone-validation-evidence.js";
26
27
  function isVerificationNotApplicable(value) {
27
28
  const v = (value ?? "").toLowerCase().trim().replace(/[.\s]+$/, "");
28
29
  if (!v || v === "none")
@@ -44,80 +45,6 @@ function getRequiredVerificationClasses(milestoneId) {
44
45
  required.push("UAT");
45
46
  return required;
46
47
  }
47
- function hasRuntimeExecutableUatEvidenceText(text) {
48
- if (!/\buatType:\s*runtime-executable\b/i.test(text))
49
- return false;
50
- if (!/\bverdict:\s*PASS\b/i.test(text))
51
- return false;
52
- return /^\|\s*[^|\n]+\s*\|\s*runtime\s*\|\s*PASS\s*\|[^|\n]*\bgsd_uat_exec\b/mi.test(text);
53
- }
54
- async function browserEvidenceGateRequiresAttention(params, basePath) {
55
- if (params.verdict !== "pass")
56
- return false;
57
- const milestone = getMilestone(params.milestoneId);
58
- const slices = getMilestoneSlices(params.milestoneId);
59
- const requirementText = compactTextParts([
60
- milestone?.vision,
61
- milestone?.success_criteria,
62
- milestone?.verification_uat,
63
- params.successCriteriaChecklist,
64
- params.verificationClasses,
65
- ...slices.flatMap((slice) => [
66
- slice.demo,
67
- slice.goal,
68
- slice.success_criteria,
69
- ]),
70
- ]);
71
- if (!hasBrowserRequiredText(requirementText))
72
- return false;
73
- // Collect per-slice evidence so the runtime bypass is checked independently
74
- // for each slice. Concatenating all slices before checking would allow runtime
75
- // evidence from one slice to cover another slice's browser requirements.
76
- const sliceEvidencePairs = [];
77
- for (const slice of slices) {
78
- const chunks = [];
79
- const artifactPath = `milestones/${params.milestoneId}/slices/${slice.id}/${slice.id}-ASSESSMENT.md`;
80
- const artifact = getArtifact(artifactPath);
81
- if (artifact?.full_content)
82
- chunks.push(artifact.full_content);
83
- const assessmentPath = resolveSliceFile(basePath, params.milestoneId, slice.id, "ASSESSMENT");
84
- const assessmentContent = assessmentPath ? await loadFile(assessmentPath) : null;
85
- if (assessmentContent)
86
- chunks.push(assessmentContent);
87
- sliceEvidencePairs.push({
88
- sliceRequirementText: compactTextParts([slice.demo, slice.goal, slice.success_criteria]),
89
- evidenceText: chunks.join("\n\n"),
90
- });
91
- }
92
- const persistedEvidence = sliceEvidencePairs.map((s) => s.evidenceText).join("\n\n");
93
- // Runtime bypass: each slice whose own requirement text has browser-observable
94
- // criteria must have its own runtime-executable UAT evidence. When no individual
95
- // slice has slice-level browser requirements (e.g., they come from milestone-level
96
- // fields only), fall back to checking whether any slice has runtime evidence.
97
- const browserRequiringSlices = sliceEvidencePairs.filter((s) => hasBrowserRequiredText(s.sliceRequirementText));
98
- const runtimeBypasses = browserRequiringSlices.length > 0
99
- ? browserRequiringSlices.every((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText))
100
- : sliceEvidencePairs.some((s) => hasRuntimeExecutableUatEvidenceText(s.evidenceText));
101
- if (runtimeBypasses)
102
- return false;
103
- const validationEvidence = compactTextParts([
104
- params.successCriteriaChecklist,
105
- params.verificationClasses,
106
- params.verdictRationale,
107
- params.remediationPlan,
108
- ]);
109
- return !hasBrowserEvidenceText(`${persistedEvidence}\n\n${validationEvidence}`);
110
- }
111
- function applyBrowserEvidenceGate(params) {
112
- const note = "Browser evidence gate: Browser-observable acceptance criteria were detected, but no persisted ASSESSMENT or validation evidence recorded browser actions with assertions. Downgraded from pass to needs-attention.";
113
- return {
114
- ...params,
115
- verdict: "needs-attention",
116
- verdictRationale: params.verdictRationale.trim()
117
- ? `${params.verdictRationale.trim()}\n\n${note}`
118
- : note,
119
- };
120
- }
121
48
  function renderValidationMarkdown(params) {
122
49
  let md = `---
123
50
  verdict: ${params.verdict}
@@ -214,6 +141,16 @@ export async function handleValidateMilestone(params, basePath, opts) {
214
141
  let projectionStale = false;
215
142
  try {
216
143
  await saveFile(validationPath, validationMd);
144
+ const projectRoot = resolveWorktreeProjectRoot(basePath);
145
+ if (projectRoot !== artifactBasePath) {
146
+ const projectValidationPath = join(gsdProjectionRoot(projectRoot), "milestones", effectiveParams.milestoneId, `${effectiveParams.milestoneId}-VALIDATION.md`);
147
+ try {
148
+ await saveFile(projectValidationPath, validationMd);
149
+ }
150
+ catch (mirrorErr) {
151
+ logWarning("projection", `validate_milestone project-root VALIDATION mirror failed for ${effectiveParams.milestoneId}`, { error: mirrorErr.message });
152
+ }
153
+ }
217
154
  }
218
155
  catch (renderErr) {
219
156
  projectionStale = true;
@@ -2,6 +2,7 @@
2
2
  // File Purpose: Central UAT mode policy for dispatch, tool presentation, and result validation.
3
3
  import { extractUatType } from "./files.js";
4
4
  import { hasBrowserRequiredText } from "./browser-evidence.js";
5
+ import { parseMcpToolName } from "./mcp-tool-name.js";
5
6
  export const UAT_TYPES = [
6
7
  "artifact-driven",
7
8
  "browser-executable",
@@ -80,26 +81,31 @@ export function shouldDispatchUatForContent(content, prefs) {
80
81
  export function uatTypeIncludesBrowser(uatType) {
81
82
  return isUatType(uatType) && UAT_MODE_POLICIES[uatType].browserTools;
82
83
  }
83
- function canonicalPresentedToolName(toolName) {
84
- if (!toolName.startsWith("mcp__"))
85
- return toolName;
86
- const toolSeparator = toolName.indexOf("__", "mcp__".length);
87
- return toolSeparator >= 0 ? toolName.slice(toolSeparator + 2) : toolName;
88
- }
89
84
  export function isUatBrowserToolName(toolName) {
90
- return canonicalPresentedToolName(toolName).startsWith("browser_");
85
+ const parsed = parseMcpToolName(toolName);
86
+ const canonicalName = parsed?.toolName ?? toolName;
87
+ if (canonicalName.startsWith("browser_"))
88
+ return true;
89
+ return parsed?.toolName === "*" && parsed.serverName.toLowerCase().includes("browser");
91
90
  }
92
91
  export function hasUatBrowserToolSurface(activeTools) {
93
92
  return Array.isArray(activeTools) && activeTools.some(isUatBrowserToolName);
94
93
  }
94
+ export function resolveUatBrowserToolSurface(options) {
95
+ const surfaces = [options.activeTools, options.registeredTools].filter(Array.isArray);
96
+ if (surfaces.length === 0)
97
+ return undefined;
98
+ return [...new Set(surfaces.flat())];
99
+ }
95
100
  export function getUatBrowserToolSupportError(options) {
96
101
  if (!uatTypeIncludesBrowser(options.uatType))
97
102
  return null;
98
- if (!Array.isArray(options.activeTools))
103
+ const toolSurface = resolveUatBrowserToolSurface(options);
104
+ if (!toolSurface)
99
105
  return null;
100
- if (hasUatBrowserToolSurface(options.activeTools))
106
+ if (hasUatBrowserToolSurface(toolSurface))
101
107
  return null;
102
- return `Cannot dispatch browser-backed run-uat for ${options.milestoneId}/${options.sliceId}: UAT mode "${options.uatType}" requires browser tools, but the active tool surface has none. Enable browser tools or change the UAT to a runtime-executable Playwright command, then rerun /gsd auto.`;
108
+ return `Cannot dispatch browser-backed run-uat for ${options.milestoneId}/${options.sliceId}: UAT mode "${options.uatType}" requires browser tools, but the run-uat tool surface has none. Enable browser tools or change the UAT to a runtime-executable Playwright command, then rerun /gsd auto.`;
103
109
  }
104
110
  export function isPartialEligibleUatType(uatType) {
105
111
  return !!uatType && UAT_MODE_POLICIES[uatType].partialEligible;
@@ -13,7 +13,7 @@ function isNonEmptyString(value) {
13
13
  function mergeBlockedTools(current, canonical) {
14
14
  const merged = new Map();
15
15
  for (const entry of [...(current ?? []), ...canonical]) {
16
- merged.set(canonicalWorkflowToolName(parseMcpToolName(entry.name)?.tool ?? entry.name), entry);
16
+ merged.set(canonicalWorkflowToolName(parseMcpToolName(entry.name)?.toolName ?? entry.name), entry);
17
17
  }
18
18
  return [...merged.values()];
19
19
  }
@@ -204,20 +204,15 @@ function quoteToolNames(toolNames) {
204
204
  return toolNames.map((toolName) => `"${toolName}"`).join(", ");
205
205
  }
206
206
  function validateCanonicalPresentation(params) {
207
- const aliasHints = {
208
- gsd_save_summary: "gsd_summary_save",
209
- gsd_complete_task: "gsd_task_complete",
210
- gsd_complete_slice: "gsd_slice_complete",
211
- gsd_milestone_complete: "gsd_complete_milestone",
212
- };
213
207
  const errors = [];
214
208
  for (const toolName of params.presentation.presentedTools) {
215
- const baseName = parseMcpToolName(toolName)?.tool ?? toolName;
216
- const canonical = aliasHints[baseName];
217
- if (canonical)
209
+ const baseName = parseMcpToolName(toolName)?.toolName ?? toolName;
210
+ const canonical = canonicalWorkflowToolName(baseName);
211
+ if (canonical !== baseName) {
218
212
  errors.push(`presentation tool "${toolName}" uses an alias; use canonical "${canonical}"`);
213
+ }
219
214
  }
220
- const presentedCanonical = new Set(params.presentation.presentedTools.map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.tool ?? toolName)));
215
+ const presentedCanonical = new Set(params.presentation.presentedTools.map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.toolName ?? toolName)));
221
216
  const missingRequiredTools = RUN_UAT_WORKFLOW_TOOL_NAMES.filter((requiredTool) => !presentedCanonical.has(requiredTool));
222
217
  if (missingRequiredTools.length === 1) {
223
218
  errors.push(`presentation is missing required UAT tool "${missingRequiredTools[0]}"`);
@@ -227,10 +222,10 @@ function validateCanonicalPresentation(params) {
227
222
  }
228
223
  const forbiddenCanonical = new Set(RUN_UAT_FORBIDDEN_TOOL_NAMES
229
224
  .filter((toolName) => !toolName.includes("*"))
230
- .map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.tool ?? toolName)));
225
+ .map((toolName) => canonicalWorkflowToolName(parseMcpToolName(toolName)?.toolName ?? toolName)));
231
226
  const forbiddenPresentedTools = [];
232
227
  for (const toolName of params.presentation.presentedTools) {
233
- const canonical = canonicalWorkflowToolName(parseMcpToolName(toolName)?.tool ?? toolName);
228
+ const canonical = canonicalWorkflowToolName(parseMcpToolName(toolName)?.toolName ?? toolName);
234
229
  if (toolName === "mcp__gsd-workflow__*" || forbiddenCanonical.has(canonical)) {
235
230
  forbiddenPresentedTools.push(toolName);
236
231
  }
@@ -241,7 +236,7 @@ function validateCanonicalPresentation(params) {
241
236
  else if (forbiddenPresentedTools.length > 1) {
242
237
  errors.push(`presentation includes forbidden run-uat tools ${quoteToolNames(forbiddenPresentedTools)}`);
243
238
  }
244
- const blockedCanonical = new Set(params.presentation.blockedTools.map((entry) => canonicalWorkflowToolName(parseMcpToolName(entry.name)?.tool ?? entry.name)));
239
+ const blockedCanonical = new Set(params.presentation.blockedTools.map((entry) => canonicalWorkflowToolName(parseMcpToolName(entry.name)?.toolName ?? entry.name)));
245
240
  const missingBlockedTools = ["gsd_exec", "gsd_summary_save", "gsd_save_gate_result"].filter((blockedTool) => !blockedCanonical.has(blockedTool));
246
241
  if (missingBlockedTools.length === 1) {
247
242
  errors.push(`presentation must record "${missingBlockedTools[0]}" as blocked during run-uat`);
@@ -11,7 +11,7 @@ import { deriveState } from "./state.js";
11
11
  import { invalidateAllCaches } from "./cache.js";
12
12
  import { gsdRoot, resolveTasksDir, resolveSlicePath, resolveTaskFile, buildTaskFileName, buildSliceFileName } from "./paths.js";
13
13
  import { sendDesktopNotification } from "./notifications.js";
14
- import { getTask, getSlice, getSliceTasks, updateTaskStatus, updateSliceStatus } from "./gsd-db.js";
14
+ import { getTask, getSlice, getSliceTasks, updateTaskStatus, resetSliceCascade } from "./gsd-db.js";
15
15
  import { renderPlanCheckboxes, renderRoadmapCheckboxes } from "./markdown-renderer.js";
16
16
  /**
17
17
  * Undo the last completed unit: revert git commits,
@@ -275,20 +275,21 @@ export async function handleResetSlice(args, ctx, _pi, basePath) {
275
275
  `Run /gsd reset-slice ${rawId} --force to confirm.`, "warning");
276
276
  return;
277
277
  }
278
- // Reset all tasks
279
- let tasksReset = 0;
278
+ // Reset all task statuses to "pending" and the slice to "active" in one
279
+ // atomic commit (DB is source of truth). Previously a per-task updateTaskStatus
280
+ // loop + a separate updateSliceStatus, which could leave a partial reset if
281
+ // interrupted mid-loop.
282
+ resetSliceCascade(mid, sid);
283
+ // Delete task summary files — projection cleanup, separate from the DB reset.
284
+ const tasksReset = tasks.length;
280
285
  let summariesDeleted = 0;
281
286
  for (const t of tasks) {
282
- updateTaskStatus(mid, sid, t.id, "pending");
283
- tasksReset++;
284
287
  const summaryPath = resolveTaskFile(basePath, mid, sid, t.id, "SUMMARY");
285
288
  if (summaryPath && existsSync(summaryPath)) {
286
289
  unlinkSync(summaryPath);
287
290
  summariesDeleted++;
288
291
  }
289
292
  }
290
- // Reset slice status
291
- updateSliceStatus(mid, sid, "active");
292
293
  // Delete slice summary and UAT files
293
294
  let sliceFilesDeleted = 0;
294
295
  const slicePath = resolveSlicePath(basePath, mid, sid);
@@ -135,37 +135,56 @@ export async function composeUnitContext(unitType, opts) {
135
135
  const manifest = resolveManifest(unitType);
136
136
  if (!manifest)
137
137
  return { prepend: "", inline: "" };
138
- // Single-source `unitType`: the manifest is resolved against the
138
+ const composed = await composeDeclaredUnitContext({
139
+ unitType,
140
+ artifacts: {
141
+ inline: manifest.artifacts.inline,
142
+ excerpt: manifest.artifacts.excerpt,
143
+ onDemand: manifest.artifacts.onDemand,
144
+ computed: manifest.artifacts.computed ?? [],
145
+ prepend: manifest.prepend ?? [],
146
+ },
147
+ }, opts);
148
+ return {
149
+ prepend: composed.prepend,
150
+ inline: composed.inline,
151
+ };
152
+ }
153
+ export async function composeContractedUnitContext(contract, opts) {
154
+ return composeDeclaredUnitContext(contract, opts);
155
+ }
156
+ async function composeDeclaredUnitContext(contract, opts) {
157
+ // Single-source `unitType`: contract/manifest selection comes from the
139
158
  // function arg, but computed builders read it from `base.unitType`.
140
- // If those ever diverge (caller passes one type to composeUnitContext
141
- // but a different one in opts.base), the composer would silently
142
- // mix one unit's manifest with another unit's computed context.
143
- // Normalize here so the composer dispatches a consistent identity
144
- // through to every builder.
159
+ // Normalize here so every builder sees the same Unit identity.
145
160
  const normalizedOpts = {
146
161
  ...opts,
147
- base: { ...opts.base, unitType },
162
+ base: { ...opts.base, unitType: contract.unitType },
148
163
  };
149
- const prependBlocks = await runComputed(manifest.prepend ?? [], normalizedOpts);
164
+ const prependBlocks = await runComputedBlocks(contract.artifacts.prepend, normalizedOpts, "prepend");
150
165
  const inlineBlocks = [];
151
- for (const key of manifest.artifacts.inline) {
166
+ for (const key of contract.artifacts.inline) {
152
167
  if (!normalizedOpts.resolveArtifact)
153
168
  break;
154
169
  const body = await normalizedOpts.resolveArtifact(key);
155
- if (body && body.length > 0)
156
- inlineBlocks.push(body);
170
+ if (body && body.length > 0) {
171
+ inlineBlocks.push({ key, mode: "inline", body });
172
+ }
157
173
  }
158
- for (const key of manifest.artifacts.excerpt) {
174
+ for (const key of contract.artifacts.excerpt) {
159
175
  if (!normalizedOpts.resolveExcerpt)
160
176
  break;
161
177
  const body = await normalizedOpts.resolveExcerpt(key);
162
- if (body && body.length > 0)
163
- inlineBlocks.push(body);
178
+ if (body && body.length > 0) {
179
+ inlineBlocks.push({ key, mode: "excerpt", body });
180
+ }
164
181
  }
165
- inlineBlocks.push(...await runComputed(manifest.artifacts.computed ?? [], normalizedOpts));
182
+ inlineBlocks.push(...await runComputedBlocks(contract.artifacts.computed, normalizedOpts, "computed"));
166
183
  return {
167
- prepend: prependBlocks.join(SECTION_SEPARATOR),
168
- inline: inlineBlocks.join(SECTION_SEPARATOR),
184
+ prepend: prependBlocks.map((block) => block.body).join(SECTION_SEPARATOR),
185
+ inline: inlineBlocks.map((block) => block.body).join(SECTION_SEPARATOR),
186
+ blocks: [...prependBlocks, ...inlineBlocks],
187
+ onDemand: contract.artifacts.onDemand,
169
188
  };
170
189
  }
171
190
  /**
@@ -173,7 +192,7 @@ export async function composeUnitContext(unitType, opts) {
173
192
  * Missing registry entries (manifest declares the id but caller didn't
174
193
  * register it) are skipped silently — see composeUnitContext rationale.
175
194
  */
176
- async function runComputed(ids, opts) {
195
+ async function runComputedBlocks(ids, opts, mode) {
177
196
  if (ids.length === 0 || !opts.computed)
178
197
  return [];
179
198
  const registry = opts.computed;
@@ -183,8 +202,9 @@ async function runComputed(ids, opts) {
183
202
  if (!entry)
184
203
  continue;
185
204
  const body = await entry.build(entry.inputs, opts.base);
186
- if (body && body.length > 0)
187
- out.push(body);
205
+ if (body && body.length > 0) {
206
+ out.push({ key: id, mode, body });
207
+ }
188
208
  }
189
209
  return out;
190
210
  }
@@ -4,7 +4,8 @@ import { atomicWriteSync } from "./atomic-write.js";
4
4
  import { gsdRoot, relSliceFile, relTaskFile, resolveSliceFile, resolveTaskFile, } from "./paths.js";
5
5
  import { loadFile, parseTaskPlanMustHaves, countMustHavesMentionedInSummary } from "./files.js";
6
6
  import { parseUnitId } from "./unit-id.js";
7
- import { getTask, isDbAvailable, refreshOpenDatabaseFromDisk } from "./gsd-db.js";
7
+ import { getTask, isDbAvailable } from "./gsd-db.js";
8
+ import { refreshWorkflowDatabaseFromDisk } from "./db-workspace.js";
8
9
  import { isClosedStatus } from "./status-guards.js";
9
10
  // Per-record advisory lock — prevents read-modify-write races between
10
11
  // concurrent writers updating disjoint fields of the same runtime record.
@@ -169,7 +170,7 @@ export async function inspectExecuteTaskDurability(basePath, unitId) {
169
170
  const nextActionAdvanced = !new RegExp(`Execute ${tid}\\b`).test(stateContent);
170
171
  let dbComplete = false;
171
172
  if (isDbAvailable()) {
172
- refreshOpenDatabaseFromDisk();
173
+ refreshWorkflowDatabaseFromDisk();
173
174
  const task = getTask(mid, sid, tid);
174
175
  dbComplete = !!task && isClosedStatus(task.status);
175
176
  }
@@ -60,6 +60,7 @@ export const UNIT_TOOL_CONTRACTS = {
60
60
  "gsd_milestone_generate_id",
61
61
  ],
62
62
  requiredWorkflowTools: [
63
+ "ask_user_questions",
63
64
  "gsd_summary_save",
64
65
  "gsd_requirement_save",
65
66
  "gsd_requirement_update",
@@ -69,7 +70,7 @@ export const UNIT_TOOL_CONTRACTS = {
69
70
  },
70
71
  "discuss-slice": {
71
72
  allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
72
- requiredWorkflowTools: ["gsd_summary_save"],
73
+ requiredWorkflowTools: ["ask_user_questions", "gsd_summary_save"],
73
74
  },
74
75
  "validate-milestone": {
75
76
  allowedGsdTools: ["gsd_milestone_status", "gsd_validate_milestone", "gsd_reassess_roadmap", "subagent"],
@@ -177,6 +177,29 @@ export function isAwaitingApprovalBoundary(messages) {
177
177
  return true;
178
178
  return hasApprovalQuestion(text);
179
179
  }
180
+ /** True when an assistant message already has an in-flight ask_user_questions tool call. */
181
+ export function messageHasPendingAskUserQuestionsTool(message) {
182
+ if (!message || typeof message !== "object")
183
+ return false;
184
+ const content = message.content;
185
+ if (!Array.isArray(content))
186
+ return false;
187
+ return content.some((block) => {
188
+ if (!block || typeof block !== "object")
189
+ return false;
190
+ // Claude Code marks completion by attaching externalResult, not by setting state.
191
+ // Streaming blocks often carry no state; serverToolUse is the claude-code-cli MCP path.
192
+ const tool = block;
193
+ if (tool.type !== "toolCall" && tool.type !== "serverToolUse")
194
+ return false;
195
+ const name = String(tool.name ?? "").toLowerCase();
196
+ if (!name.includes("ask_user_questions"))
197
+ return false;
198
+ if (tool.externalResult !== undefined)
199
+ return false;
200
+ return tool.state !== "completed" && tool.state !== "done";
201
+ });
202
+ }
180
203
  export function shouldPauseForUserApprovalQuestion(unitType, messages) {
181
204
  if (!unitType || !USER_APPROVAL_UNIT_TYPES.has(unitType))
182
205
  return false;
@@ -3,6 +3,7 @@
3
3
  import { existsSync } from "node:fs";
4
4
  import { getAutoWorktreePath, isInAutoWorktree } from "./auto-worktree.js";
5
5
  import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
6
+ import { refreshWorkflowDatabaseFromDisk } from "./db-workspace.js";
6
7
  import { getIsolationMode } from "./preferences.js";
7
8
  import { deriveState } from "./state.js";
8
9
  import { detectWorktreeName } from "./worktree.js";
@@ -72,6 +73,7 @@ export function formatValidationBlockedMessage(state, attemptedCommand = "") {
72
73
  }
73
74
  export async function getValidationBlockMessageForBase(base, attemptedCommand = "") {
74
75
  await ensureDbOpen(base);
76
+ refreshWorkflowDatabaseFromDisk();
75
77
  let state = await deriveState(base);
76
78
  if (state.activeMilestone &&
77
79
  getIsolationMode(base) === "worktree" &&
@@ -0,0 +1,80 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Web-app detection and Playwright/UAT guidance for planning and slice closeout.
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import { resolve } from "node:path";
5
+ import { detectWebApp } from "../browser-tools/web-app-detect.js";
6
+ export { detectWebApp };
7
+ function readPackageJson(projectRoot) {
8
+ const packageJsonPath = resolve(projectRoot, "package.json");
9
+ if (!existsSync(packageJsonPath))
10
+ return null;
11
+ try {
12
+ const parsed = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
13
+ return parsed && typeof parsed === "object" ? parsed : null;
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
19
+ export function hasPlaywrightTestDependency(projectRoot) {
20
+ const pkg = readPackageJson(projectRoot);
21
+ if (!pkg)
22
+ return false;
23
+ const names = [
24
+ ...Object.keys(pkg.dependencies ?? {}),
25
+ ...Object.keys(pkg.devDependencies ?? {}),
26
+ ];
27
+ return names.some((name) => name === "playwright" || name === "@playwright/test");
28
+ }
29
+ export function findPlaywrightTestScript(projectRoot) {
30
+ const pkg = readPackageJson(projectRoot);
31
+ if (!pkg?.scripts)
32
+ return null;
33
+ for (const [name, value] of Object.entries(pkg.scripts)) {
34
+ if (typeof value !== "string")
35
+ continue;
36
+ if (/\bplaywright\s+test\b/.test(value)) {
37
+ return `npm run ${name}`;
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+ /**
43
+ * Markdown block injected into plan/complete-slice prompts when the project
44
+ * looks browser-facing. Returns null for CLI/library-only repos.
45
+ */
46
+ export function buildWebAppUatGuidanceBlock(projectRoot) {
47
+ if (!detectWebApp(projectRoot))
48
+ return null;
49
+ const playwrightScript = findPlaywrightTestScript(projectRoot);
50
+ const hasPlaywright = hasPlaywrightTestDependency(projectRoot) || playwrightScript !== null;
51
+ const lines = [
52
+ "### Web App UAT (detected)",
53
+ "",
54
+ "This project looks browser-facing. GSD exposes Playwright-backed `browser_*` tools by default for run-uat.",
55
+ "",
56
+ "**UAT modes (pick one per slice — do not use `artifact-driven` for browser steps):**",
57
+ "- `browser-executable` — navigate to `http://localhost:…`, click, screenshot, assert via `browser_*` tools during run-uat",
58
+ "- `runtime-executable` — run an automated browser test command via `gsd_uat_exec` (for example `npx playwright test`)",
59
+ "- `mixed` / `live-runtime` — combine runtime startup checks with interactive browser verification",
60
+ "",
61
+ "**Planning / closeout rules:**",
62
+ "- Preconditions must name the dev-server command and URL (for example `npm run dev` → `http://localhost:3000`)",
63
+ "- Slice Verification and UAT test cases must not say \"open in browser\" under `artifact-driven` — complete-slice rejects that",
64
+ "- Milestone `Verification Classes` → UAT row must describe browser-observable acceptance, not \"manual spot check\" alone",
65
+ ];
66
+ if (hasPlaywright) {
67
+ lines.push("", "**Playwright:** dependency detected.");
68
+ if (playwrightScript) {
69
+ lines.push(`- Prefer slice verification and runtime-executable UAT referencing \`${playwrightScript}\` or a focused \`npx playwright test <spec>\` command`);
70
+ }
71
+ else {
72
+ lines.push("- Prefer runtime-executable UAT with `npx playwright test` (or a focused spec path) when UI behavior is covered by specs");
73
+ }
74
+ lines.push("- Name concrete spec paths in slice Verification (for example `e2e/smoke.spec.ts`)");
75
+ }
76
+ else {
77
+ lines.push("", "**Playwright scaffolding (first UI slice):** no `playwright` / `@playwright/test` dependency yet.", "- Add a planning task that installs Playwright, adds `playwright.config.ts`, and creates a minimal smoke spec (for example `e2e/smoke.spec.ts`)", "- Task `verify` should run `npx playwright test` (or the focused spec) with a safe, simple command", "- Until specs exist, use `browser-executable` UAT with localhost preconditions and interactive `browser_*` checks at slice closeout");
78
+ }
79
+ return lines.join("\n");
80
+ }