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

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 (375) 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/claude-code-cli/stream-adapter.js +84 -228
  7. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
  8. package/dist/resources/extensions/github-sync/templates.js +3 -3
  9. package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
  10. package/dist/resources/extensions/gsd/auto/loop.js +74 -56
  11. package/dist/resources/extensions/gsd/auto/orchestrator.js +109 -11
  12. package/dist/resources/extensions/gsd/auto/phases.js +28 -3
  13. package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
  14. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  15. package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
  16. package/dist/resources/extensions/gsd/auto-dispatch.js +6 -5
  17. package/dist/resources/extensions/gsd/auto-model-selection.js +8 -0
  18. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
  19. package/dist/resources/extensions/gsd/auto-prompts.js +81 -8
  20. package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
  21. package/dist/resources/extensions/gsd/auto-runtime-state.js +14 -0
  22. package/dist/resources/extensions/gsd/auto-start.js +12 -23
  23. package/dist/resources/extensions/gsd/auto-timers.js +16 -2
  24. package/dist/resources/extensions/gsd/auto-tool-tracking.js +32 -0
  25. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +4 -29
  26. package/dist/resources/extensions/gsd/auto-verification.js +7 -7
  27. package/dist/resources/extensions/gsd/auto-worktree.js +21 -19
  28. package/dist/resources/extensions/gsd/auto.js +11 -7
  29. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
  30. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +11 -37
  31. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
  32. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +100 -138
  33. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +63 -4
  34. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
  35. package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
  36. package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
  37. package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
  38. package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
  39. package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
  40. package/dist/resources/extensions/gsd/commands-ship.js +2 -2
  41. package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
  42. package/dist/resources/extensions/gsd/db-workspace.js +103 -0
  43. package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
  44. package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
  45. package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  46. package/dist/resources/extensions/gsd/doctor.js +16 -9
  47. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  48. package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
  49. package/dist/resources/extensions/gsd/gsd-db.js +12 -0
  50. package/dist/resources/extensions/gsd/guided-flow.js +34 -468
  51. package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
  52. package/dist/resources/extensions/gsd/markdown-renderer.js +2 -1
  53. package/dist/resources/extensions/gsd/mcp-filter.js +2 -1
  54. package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
  55. package/dist/resources/extensions/gsd/md-importer.js +4 -3
  56. package/dist/resources/extensions/gsd/migrate/safety.js +2 -2
  57. package/dist/resources/extensions/gsd/migration-auto-check.js +3 -2
  58. package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
  59. package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
  60. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
  61. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
  62. package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
  63. package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
  64. package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
  65. package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
  66. package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
  67. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
  68. package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
  69. package/dist/resources/extensions/gsd/preferences.js +147 -29
  70. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  71. package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
  72. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
  73. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  74. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  75. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  76. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  77. package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
  78. package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
  79. package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
  80. package/dist/resources/extensions/gsd/question-transport.js +86 -0
  81. package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
  82. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
  83. package/dist/resources/extensions/gsd/state.js +13 -5
  84. package/dist/resources/extensions/gsd/templates/plan.md +7 -0
  85. package/dist/resources/extensions/gsd/templates/project.md +1 -0
  86. package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
  87. package/dist/resources/extensions/gsd/templates/uat.md +5 -1
  88. package/dist/resources/extensions/gsd/tool-contract.js +52 -8
  89. package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
  90. package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
  91. package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
  92. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
  93. package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
  94. package/dist/resources/extensions/gsd/uat-policy.js +16 -10
  95. package/dist/resources/extensions/gsd/uat-run.js +9 -14
  96. package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
  97. package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
  98. package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
  99. package/dist/resources/extensions/gsd/user-input-boundary.js +23 -0
  100. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  101. package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
  102. package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
  103. package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
  104. package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
  105. package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
  106. package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
  107. package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
  108. package/dist/resources/extensions/shared/interview-ui.js +2 -2
  109. package/dist/resources/shared/claude-runtime-floor.js +182 -0
  110. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  111. package/dist/update-cmd.js +20 -0
  112. package/dist/web/standalone/.next/BUILD_ID +1 -1
  113. package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
  114. package/dist/web/standalone/.next/build-manifest.json +3 -3
  115. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  116. package/dist/web/standalone/.next/react-loadable-manifest.json +8 -8
  117. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  118. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  126. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/index.html +1 -1
  134. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
  141. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  142. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  145. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  146. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  147. package/dist/web/standalone/.next/static/chunks/2659.b7b129ee6a769448.js +1 -0
  148. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
  149. package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
  150. package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
  151. package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
  152. package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
  153. package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
  154. package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
  155. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  156. package/dist/web-mode.d.ts +2 -0
  157. package/dist/web-mode.js +20 -8
  158. package/package.json +2 -1
  159. package/packages/cloud-mcp-gateway/package.json +2 -2
  160. package/packages/contracts/package.json +1 -1
  161. package/packages/daemon/package.json +4 -4
  162. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
  163. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  164. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
  165. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  166. package/packages/gsd-agent-core/package.json +5 -5
  167. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  168. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +106 -40
  169. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  170. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
  171. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
  172. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
  173. package/packages/gsd-agent-modes/package.json +7 -7
  174. package/packages/mcp-server/dist/server.d.ts +10 -0
  175. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  176. package/packages/mcp-server/dist/server.js +8 -0
  177. package/packages/mcp-server/dist/server.js.map +1 -1
  178. package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
  179. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  180. package/packages/mcp-server/dist/workflow-tools.js +2 -1
  181. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  182. package/packages/mcp-server/package.json +3 -3
  183. package/packages/native/package.json +1 -1
  184. package/packages/pi-agent-core/package.json +1 -1
  185. package/packages/pi-ai/dist/models.generated.d.ts +8 -93
  186. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  187. package/packages/pi-ai/dist/models.generated.js +35 -120
  188. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  189. package/packages/pi-ai/package.json +1 -1
  190. package/packages/pi-coding-agent/package.json +7 -7
  191. package/packages/pi-tui/dist/components/input.js +1 -1
  192. package/packages/pi-tui/dist/components/input.js.map +1 -1
  193. package/packages/pi-tui/dist/keys.d.ts.map +1 -1
  194. package/packages/pi-tui/dist/keys.js +39 -30
  195. package/packages/pi-tui/dist/keys.js.map +1 -1
  196. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  197. package/packages/pi-tui/dist/stdin-buffer.js +22 -0
  198. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  199. package/packages/pi-tui/package.json +2 -2
  200. package/packages/rpc-client/package.json +2 -2
  201. package/pkg/package.json +1 -1
  202. package/src/resources/extensions/ask-user-questions.ts +87 -24
  203. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +108 -281
  204. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +240 -0
  205. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
  206. package/src/resources/extensions/github-sync/templates.ts +3 -3
  207. package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
  208. package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
  209. package/src/resources/extensions/gsd/auto/contracts.ts +32 -2
  210. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
  211. package/src/resources/extensions/gsd/auto/loop.ts +83 -61
  212. package/src/resources/extensions/gsd/auto/orchestrator.ts +125 -12
  213. package/src/resources/extensions/gsd/auto/phases.ts +35 -3
  214. package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
  215. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  216. package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
  217. package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
  218. package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
  219. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -3
  220. package/src/resources/extensions/gsd/auto-prompts.ts +107 -9
  221. package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
  222. package/src/resources/extensions/gsd/auto-runtime-state.ts +26 -0
  223. package/src/resources/extensions/gsd/auto-start.ts +17 -20
  224. package/src/resources/extensions/gsd/auto-timers.ts +16 -2
  225. package/src/resources/extensions/gsd/auto-tool-tracking.ts +35 -0
  226. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +9 -30
  227. package/src/resources/extensions/gsd/auto-verification.ts +7 -8
  228. package/src/resources/extensions/gsd/auto-worktree.ts +33 -26
  229. package/src/resources/extensions/gsd/auto.ts +15 -8
  230. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
  231. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +10 -37
  232. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
  233. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +116 -151
  234. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +107 -3
  235. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
  236. package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
  237. package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
  238. package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
  239. package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
  240. package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
  241. package/src/resources/extensions/gsd/commands-ship.ts +2 -2
  242. package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
  243. package/src/resources/extensions/gsd/db-workspace.ts +170 -0
  244. package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
  245. package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
  246. package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  247. package/src/resources/extensions/gsd/doctor.ts +15 -5
  248. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  249. package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
  250. package/src/resources/extensions/gsd/gsd-db.ts +12 -0
  251. package/src/resources/extensions/gsd/guided-flow.ts +47 -558
  252. package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
  253. package/src/resources/extensions/gsd/markdown-renderer.ts +2 -1
  254. package/src/resources/extensions/gsd/mcp-filter.ts +2 -1
  255. package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
  256. package/src/resources/extensions/gsd/md-importer.ts +3 -3
  257. package/src/resources/extensions/gsd/migrate/safety.ts +2 -2
  258. package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
  259. package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
  260. package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
  261. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
  262. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
  263. package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
  264. package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
  265. package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
  266. package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
  267. package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
  268. package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
  269. package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
  270. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  271. package/src/resources/extensions/gsd/preferences.ts +173 -28
  272. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  273. package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
  274. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
  275. package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  276. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  277. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  278. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  279. package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
  280. package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
  281. package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
  282. package/src/resources/extensions/gsd/question-transport.ts +138 -0
  283. package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
  284. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
  285. package/src/resources/extensions/gsd/state.ts +15 -5
  286. package/src/resources/extensions/gsd/templates/plan.md +7 -0
  287. package/src/resources/extensions/gsd/templates/project.md +1 -0
  288. package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
  289. package/src/resources/extensions/gsd/templates/uat.md +5 -1
  290. package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
  291. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
  292. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +321 -5
  293. package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
  294. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
  295. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +133 -4
  296. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
  297. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
  298. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  299. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
  300. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
  301. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
  302. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
  303. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
  304. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
  305. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
  306. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
  307. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
  308. package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
  309. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +58 -0
  310. package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
  311. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
  312. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
  313. package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
  314. package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
  315. package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
  316. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
  317. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  318. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
  319. package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
  320. package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
  321. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +46 -0
  322. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
  323. package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
  324. package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
  325. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +94 -0
  326. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
  327. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
  328. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
  329. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +101 -1
  330. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
  331. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +2 -1
  332. package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
  333. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
  334. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
  335. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
  336. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +86 -1
  337. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
  338. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
  339. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
  340. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
  341. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +21 -0
  342. package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
  343. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
  344. package/src/resources/extensions/gsd/tests/write-gate.test.ts +79 -0
  345. package/src/resources/extensions/gsd/tool-contract.ts +86 -8
  346. package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
  347. package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
  348. package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
  349. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
  350. package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
  351. package/src/resources/extensions/gsd/uat-policy.ts +19 -10
  352. package/src/resources/extensions/gsd/uat-run.ts +10 -14
  353. package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
  354. package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
  355. package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
  356. package/src/resources/extensions/gsd/user-input-boundary.ts +18 -0
  357. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  358. package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
  359. package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
  360. package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
  361. package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
  362. package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
  363. package/src/resources/extensions/gsd/worktree-lifecycle.ts +7 -16
  364. package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
  365. package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
  366. package/src/resources/extensions/shared/interview-ui.ts +15 -2
  367. package/src/resources/shared/claude-runtime-floor.ts +248 -0
  368. package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
  369. package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
  370. package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
  371. package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
  372. package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
  373. package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
  374. /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → 3PtrU9qGPEXwNLWkIyiqk}/_buildManifest.js +0 -0
  375. /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → 3PtrU9qGPEXwNLWkIyiqk}/_ssgManifest.js +0 -0
@@ -0,0 +1,41 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Process-level pull request policy for GSD-generated PRs.
3
+
4
+ import { createDraftPR } from "./git-service.js";
5
+ import {
6
+ buildPrEvidence,
7
+ type PrEvidence,
8
+ type PrEvidenceInput,
9
+ } from "./pr-evidence.js";
10
+
11
+ export interface DraftPullRequestOptions {
12
+ head: string;
13
+ base: string;
14
+ }
15
+
16
+ export interface DraftPullRequestDeps {
17
+ createDraftPR: (
18
+ basePath: string,
19
+ milestoneId: string,
20
+ title: string,
21
+ body: string,
22
+ opts: DraftPullRequestOptions,
23
+ ) => string | null;
24
+ }
25
+
26
+ export function buildPullRequestEvidence(input: PrEvidenceInput): PrEvidence {
27
+ return buildPrEvidence({
28
+ ...input,
29
+ aiAssisted: false,
30
+ });
31
+ }
32
+
33
+ export function createDraftPullRequestFromEvidence(
34
+ basePath: string,
35
+ milestoneId: string,
36
+ evidence: PrEvidence,
37
+ options: DraftPullRequestOptions,
38
+ deps: DraftPullRequestDeps = { createDraftPR },
39
+ ): string | null {
40
+ return deps.createDraftPR(basePath, milestoneId, evidence.title, evidence.body, options);
41
+ }
@@ -0,0 +1,140 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Canonical quality-gate closure from durable DB and artifact evidence.
3
+
4
+ import { existsSync, readFileSync } from "node:fs";
5
+
6
+ import { extractSection } from "./files.js";
7
+ import { getGateDefinition } from "./gate-registry.js";
8
+ import { getMilestoneSlices, getPendingGates, saveGateResult } from "./gsd-db.js";
9
+ import { resolveSliceFile, resolveTaskFile } from "./paths.js";
10
+ import type { GateId, GateRow, GateVerdict } from "./types.js";
11
+
12
+ export interface QualityGateClosureOptions {
13
+ artifactBasePath?: string;
14
+ milestoneValidationPassed?: boolean;
15
+ }
16
+
17
+ export interface QualityGateClosureResult {
18
+ repaired: Array<{ gateId: GateId; sliceId: string; taskId?: string; verdict: GateVerdict }>;
19
+ unresolved: GateRow[];
20
+ }
21
+
22
+ interface GateEvidence {
23
+ verdict: GateVerdict;
24
+ rationale: string;
25
+ findings: string;
26
+ }
27
+
28
+ const GATE_SECTION_HEADINGS: Partial<Record<GateId, string[]>> = {
29
+ Q3: ["Threat Surface", "Abuse Surface"],
30
+ Q4: ["Requirement Impact", "Broken Promises"],
31
+ Q5: ["Failure Modes"],
32
+ Q6: ["Load Profile"],
33
+ Q7: ["Negative Tests"],
34
+ Q8: ["Operational Readiness"],
35
+ };
36
+
37
+ function readFile(path: string | null): string | null {
38
+ if (!path || !existsSync(path)) return null;
39
+ return readFileSync(path, "utf-8");
40
+ }
41
+
42
+ function firstSection(content: string | null, gateId: GateId): string | null {
43
+ if (!content) return null;
44
+ for (const heading of GATE_SECTION_HEADINGS[gateId] ?? []) {
45
+ const section = extractSection(content, heading);
46
+ if (section) return section;
47
+ }
48
+ return null;
49
+ }
50
+
51
+ function evidenceArtifactContent(row: GateRow, basePath: string): string | null {
52
+ const def = getGateDefinition(row.gate_id);
53
+ switch (def?.ownerTurn) {
54
+ case "gate-evaluate":
55
+ return readFile(resolveSliceFile(basePath, row.milestone_id, row.slice_id, "PLAN"));
56
+ case "execute-task":
57
+ return readFile(resolveTaskFile(basePath, row.milestone_id, row.slice_id, row.task_id, "SUMMARY"));
58
+ case "complete-slice":
59
+ return readFile(resolveSliceFile(basePath, row.milestone_id, row.slice_id, "SUMMARY"));
60
+ default:
61
+ return null;
62
+ }
63
+ }
64
+
65
+ function closureEvidence(row: GateRow, options: QualityGateClosureOptions): GateEvidence | null {
66
+ const def = getGateDefinition(row.gate_id);
67
+ if (!def) return null;
68
+
69
+ if (def.ownerTurn === "validate-milestone" && options.milestoneValidationPassed) {
70
+ return {
71
+ verdict: "pass",
72
+ rationale: `${def.promptSection} covered by passing milestone validation`,
73
+ findings: "",
74
+ };
75
+ }
76
+
77
+ if (!options.artifactBasePath) return null;
78
+
79
+ const section = firstSection(evidenceArtifactContent(row, options.artifactBasePath), row.gate_id);
80
+ if (section) {
81
+ return {
82
+ verdict: "pass",
83
+ rationale: `${def.promptSection} evidence found in durable artifact`,
84
+ findings: section,
85
+ };
86
+ }
87
+
88
+ if (!options.milestoneValidationPassed) return null;
89
+ return {
90
+ verdict: "omitted",
91
+ rationale: `${def.promptSection} has no durable artifact section; milestone validation passed`,
92
+ findings: "",
93
+ };
94
+ }
95
+
96
+ function closeGate(row: GateRow, evidence: GateEvidence): void {
97
+ saveGateResult({
98
+ milestoneId: row.milestone_id,
99
+ sliceId: row.slice_id,
100
+ gateId: row.gate_id,
101
+ taskId: row.task_id,
102
+ verdict: evidence.verdict,
103
+ rationale: evidence.rationale,
104
+ findings: evidence.findings,
105
+ });
106
+ }
107
+
108
+ export function closeQualityGatesFromEvidence(
109
+ milestoneId: string,
110
+ options: QualityGateClosureOptions = {},
111
+ ): QualityGateClosureResult {
112
+ const repaired: QualityGateClosureResult["repaired"] = [];
113
+ const unresolved: GateRow[] = [];
114
+
115
+ for (const slice of getMilestoneSlices(milestoneId)) {
116
+ const sliceId = slice.id;
117
+ for (const row of getPendingGates(milestoneId, sliceId)) {
118
+ if (!getGateDefinition(row.gate_id)) {
119
+ unresolved.push(row);
120
+ continue;
121
+ }
122
+
123
+ const evidence = closureEvidence(row, options);
124
+ if (!evidence) {
125
+ unresolved.push(row);
126
+ continue;
127
+ }
128
+
129
+ closeGate(row, evidence);
130
+ repaired.push({
131
+ gateId: row.gate_id,
132
+ sliceId: row.slice_id,
133
+ ...(row.task_id ? { taskId: row.task_id } : {}),
134
+ verdict: evidence.verdict,
135
+ });
136
+ }
137
+ }
138
+
139
+ return { repaired, unresolved };
140
+ }
@@ -0,0 +1,138 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Resolve how workflow units should ask the user for input.
3
+
4
+ import { parseMcpToolName, toMcpToolName } from "./mcp-tool-name.js";
5
+
6
+ export type StructuredQuestionsFlag = "true" | "false";
7
+
8
+ export interface QuestionTransportOptions {
9
+ activeTools: string[];
10
+ authMode?: "apiKey" | "oauth" | "externalCli" | "none";
11
+ baseUrl?: string;
12
+ env?: NodeJS.ProcessEnv;
13
+ }
14
+
15
+ export interface QuestionTransportResolution {
16
+ structuredQuestionsAvailable: StructuredQuestionsFlag;
17
+ questionToolAvailable: boolean;
18
+ usesWorkflowMcp: boolean;
19
+ reason: "question-tool-available" | "question-tool-missing" | "workflow-mcp-disabled";
20
+ }
21
+
22
+ export interface WorkflowQuestionToolSurfaceOptions {
23
+ workflowServerName?: string;
24
+ workflowExplicitlyBlocked?: boolean;
25
+ workflowMcpTools: string[];
26
+ exactWorkflowMcpTools: string[];
27
+ env?: NodeJS.ProcessEnv;
28
+ }
29
+
30
+ export interface WorkflowQuestionToolSurfaceResolution extends QuestionTransportResolution {
31
+ questionToolName?: string;
32
+ workflowQuestionsEnabled: boolean;
33
+ disallowedTools: string[];
34
+ }
35
+
36
+ function isWorkflowMcpServerName(serverName: string): boolean {
37
+ const normalized = serverName.toLowerCase();
38
+ return normalized === "gsd" || normalized.includes("workflow");
39
+ }
40
+
41
+ export function usesWorkflowMcpTransport(
42
+ authMode: QuestionTransportOptions["authMode"],
43
+ baseUrl: string | undefined,
44
+ ): boolean {
45
+ return authMode === "externalCli" && typeof baseUrl === "string" && baseUrl.startsWith("local://");
46
+ }
47
+
48
+ export function hasAskUserQuestionsTool(activeTools: string[]): boolean {
49
+ return activeTools.some((toolName) => {
50
+ if (toolName === "ask_user_questions") return true;
51
+ const mcp = parseMcpToolName(toolName);
52
+ if (!mcp) return false;
53
+ if (mcp.toolName === "ask_user_questions") return true;
54
+ return mcp.toolName === "*" && isWorkflowMcpServerName(mcp.serverName);
55
+ });
56
+ }
57
+
58
+ function workflowMcpStructuredQuestionsEnabled(env: NodeJS.ProcessEnv = process.env): boolean {
59
+ const value = env.GSD_WORKFLOW_MCP_STRUCTURED_QUESTIONS?.trim().toLowerCase();
60
+ return value !== "0" && value !== "false" && value !== "off";
61
+ }
62
+
63
+ export function resolveQuestionTransport(
64
+ options: QuestionTransportOptions,
65
+ ): QuestionTransportResolution {
66
+ const questionToolAvailable = hasAskUserQuestionsTool(options.activeTools);
67
+ const usesWorkflowMcp = usesWorkflowMcpTransport(options.authMode, options.baseUrl);
68
+
69
+ if (!questionToolAvailable) {
70
+ return {
71
+ structuredQuestionsAvailable: "false",
72
+ questionToolAvailable,
73
+ usesWorkflowMcp,
74
+ reason: "question-tool-missing",
75
+ };
76
+ }
77
+
78
+ if (options.authMode === "externalCli" && !workflowMcpStructuredQuestionsEnabled(options.env)) {
79
+ return {
80
+ structuredQuestionsAvailable: "false",
81
+ questionToolAvailable,
82
+ usesWorkflowMcp,
83
+ reason: "workflow-mcp-disabled",
84
+ };
85
+ }
86
+
87
+ return {
88
+ structuredQuestionsAvailable: "true",
89
+ questionToolAvailable,
90
+ usesWorkflowMcp,
91
+ reason: "question-tool-available",
92
+ };
93
+ }
94
+
95
+ export function supportsStructuredQuestions(
96
+ activeTools: string[],
97
+ options: Omit<QuestionTransportOptions, "activeTools"> = {},
98
+ ): boolean {
99
+ return resolveQuestionTransport({
100
+ ...options,
101
+ activeTools,
102
+ }).structuredQuestionsAvailable === "true";
103
+ }
104
+
105
+ export function resolveWorkflowQuestionToolSurface(
106
+ options: WorkflowQuestionToolSurfaceOptions,
107
+ ): WorkflowQuestionToolSurfaceResolution {
108
+ const questionToolName = options.workflowServerName && !options.workflowExplicitlyBlocked
109
+ ? toMcpToolName(options.workflowServerName, "ask_user_questions")
110
+ : undefined;
111
+ const activeTools = [
112
+ ...options.exactWorkflowMcpTools,
113
+ ...options.workflowMcpTools,
114
+ ...(questionToolName ? [questionToolName] : []),
115
+ ];
116
+ const transport = resolveQuestionTransport({
117
+ activeTools,
118
+ authMode: "externalCli",
119
+ baseUrl: "local://claude-code",
120
+ env: options.env,
121
+ });
122
+ const exactQuestionToolAllowed =
123
+ !!questionToolName && options.exactWorkflowMcpTools.includes(questionToolName);
124
+ const workflowQuestionsEnabled =
125
+ transport.structuredQuestionsAvailable === "true" &&
126
+ (options.workflowMcpTools.length > 0 || exactQuestionToolAllowed);
127
+ const disallowedTools =
128
+ options.workflowServerName && transport.questionToolAvailable && !workflowQuestionsEnabled
129
+ ? [toMcpToolName(options.workflowServerName, "ask_user_questions")]
130
+ : [];
131
+
132
+ return {
133
+ ...transport,
134
+ questionToolName,
135
+ workflowQuestionsEnabled,
136
+ disallowedTools,
137
+ };
138
+ }
@@ -189,9 +189,15 @@ export function parseRoadmapSlices(content: string): RoadmapSliceEntry[] {
189
189
  const risk = (riskMatch ? riskMatch[1] : "low") as RiskLevel;
190
190
 
191
191
  const depsMatch = rest.match(/`depends:\[([^\]]*)\]`/);
192
- const depends = depsMatch && depsMatch[1]!.trim()
193
- ? expandDependencies(depsMatch[1]!.split(",").map(s => s.trim()))
192
+ // Recovery fallback: double-bracket form `[[id]]` from serialized bracket-wrapped IDs
193
+ const fallbackDepsMatch = depsMatch ? null : rest.match(/`depends:\[(\[(?:[^\]]*)\](?:,\[(?:[^\]]*)\])*)\]`/);
194
+ const rawDepContent = (depsMatch ?? fallbackDepsMatch)?.[1] ?? "";
195
+ const SLICE_ID_RE = /^[A-Za-z0-9][A-Za-z0-9-]*$/;
196
+ const RANGE_RE = /^[A-Za-z]+\d+(?:-|\.\.)[A-Za-z]+\d+$/;
197
+ const rawDepParts = rawDepContent.trim()
198
+ ? rawDepContent.replace(/\[|\]/g, "").split(",").map(s => s.trim()).filter(s => SLICE_ID_RE.test(s) || RANGE_RE.test(s))
194
199
  : [];
200
+ const depends = expandDependencies(rawDepParts);
195
201
 
196
202
  // ADR-011: the renderer writes a `[sketch]` badge for sketch slices.
197
203
  // Parse it back so the is_sketch flag survives a markdown → DB re-import
@@ -30,7 +30,8 @@ import { isAbsolute, join, dirname, resolve } from "node:path";
30
30
  import { fileURLToPath } from "node:url";
31
31
  import { gsdRoot } from "./paths.js";
32
32
  import { createWorktree, worktreePath, removeWorktree } from "./worktree-manager.js";
33
- import { autoWorktreeBranch, runWorktreePostCreateHook, syncGsdStateToWorktree } from "./auto-worktree.js";
33
+ import { autoWorktreeBranch, runWorktreePostCreateHook, syncGsdStateToWorktreeByScope } from "./auto-worktree.js";
34
+ import { createWorkspace, scopeMilestone } from "./workspace.js";
34
35
  import {
35
36
  writeSessionStatus,
36
37
  removeSessionStatus,
@@ -163,7 +164,10 @@ function createSliceWorktree(basePath: string, milestoneId: string, sliceId: str
163
164
  if (hookError) {
164
165
  throw new Error(`slice worktree post-create hook failed (${wtName}): ${hookError}`);
165
166
  }
166
- syncGsdStateToWorktree(basePath, wtPath);
167
+ syncGsdStateToWorktreeByScope(
168
+ scopeMilestone(createWorkspace(basePath), milestoneId),
169
+ scopeMilestone(createWorkspace(wtPath), milestoneId),
170
+ );
167
171
 
168
172
  if (!existsSync(join(wtPath, ".gsd"))) {
169
173
  throw new Error(`slice worktree preflight failed (${wtName}): missing .gsd in worktree`);
@@ -52,7 +52,6 @@ import { isTerminalMilestoneSummaryContent } from './milestone-summary-classifie
52
52
 
53
53
  import {
54
54
  isDbAvailable,
55
- wasDbOpenAttempted,
56
55
  getAllMilestones,
57
56
  getMilestone,
58
57
  getMilestoneSlices,
@@ -63,9 +62,14 @@ import {
63
62
  getLatestAssessmentByScope,
64
63
  getPendingGateCountForTurn,
65
64
  } from './gsd-db.js';
65
+ import { wasWorkflowDatabaseOpenAttempted } from './db-workspace.js';
66
66
  import { formatCompletePhaseNextAction, countUnmappedActiveRequirements } from './requirements-backlog.js';
67
67
  import type { MilestoneRow } from './db-milestone-artifact-rows.js';
68
68
  import type { SliceRow, TaskRow } from './db-task-slice-rows.js';
69
+ import {
70
+ classifyMilestoneReadiness,
71
+ readinessNeedsDiscussion,
72
+ } from './milestone-readiness.js';
69
73
 
70
74
  function formatNeedsAttentionBlocker(milestoneId: string): string {
71
75
  return [
@@ -395,7 +399,7 @@ export async function deriveState(
395
399
  stopDbTimer({ phase: result.phase, milestone: result.activeMilestone?.id });
396
400
  _telemetry.dbDeriveCount++;
397
401
  } else {
398
- if (wasDbOpenAttempted()) {
402
+ if (wasWorkflowDatabaseOpenAttempted()) {
399
403
  logWarning("state", "DB unavailable — refusing implicit markdown state derivation");
400
404
  }
401
405
  result = {
@@ -507,6 +511,12 @@ async function buildRegistryAndFindActive(
507
511
  const title = stripMilestonePrefix(m.title) || m.id;
508
512
  const hasContext = !!resolveMilestoneFile(basePath, m.id, "CONTEXT");
509
513
  const hasDraftContext = !hasContext && !!resolveMilestoneFile(basePath, m.id, "CONTEXT-DRAFT");
514
+ const readiness = classifyMilestoneReadiness({
515
+ status: m.status,
516
+ hasContext,
517
+ hasDraftContext,
518
+ sliceCount: slices.length,
519
+ });
510
520
 
511
521
  if (!activeMilestoneFound) {
512
522
  const deps = m.depends_on;
@@ -517,9 +527,9 @@ async function buildRegistryAndFindActive(
517
527
  continue;
518
528
  }
519
529
 
520
- if (m.status === 'queued' && slices.length === 0 && !hasContext) {
530
+ if (readiness.kind === 'queued-shell') {
521
531
  if (!firstDeferredQueuedShell) {
522
- firstDeferredQueuedShell = { id: m.id, title, deps, hasDraftContext };
532
+ firstDeferredQueuedShell = { id: m.id, title, deps, hasDraftContext: readiness.hasDraftContext };
523
533
  }
524
534
  registry.push({ id: m.id, title, status: 'pending', ...(deps.length > 0 ? { dependsOn: deps } : {}) });
525
535
  continue;
@@ -533,7 +543,7 @@ async function buildRegistryAndFindActive(
533
543
  continue;
534
544
  }
535
545
 
536
- if ((m.status === 'needs-discussion' && !hasContext) || hasDraftContext) activeMilestoneHasDraft = true;
546
+ if (readinessNeedsDiscussion(readiness)) activeMilestoneHasDraft = true;
537
547
 
538
548
  activeMilestone = { id: m.id, title };
539
549
  activeMilestoneSlices = slices;
@@ -46,6 +46,13 @@
46
46
  For simple projects or scripts:
47
47
  - Executable verification commands (bash assertions, curl checks, etc.) are sufficient
48
48
 
49
+ For browser-facing web apps (React, Next, Vue, Vite, static HTML, etc.):
50
+ - Prefer `npx playwright test <spec>` in Verification when `@playwright/test` exists
51
+ - If Playwright is not set up yet, the first UI slice should add `playwright.config.ts`,
52
+ a minimal smoke spec (for example `e2e/smoke.spec.ts`), and a safe verify command
53
+ - Slice closeout UAT must declare `browser-executable` or `runtime-executable` — not
54
+ `artifact-driven` — when checks navigate to localhost or exercise the live UI
55
+
49
56
  If the project has no test framework and the work is non-trivial,
50
57
  the first task should set one up. A test runner costs 2 minutes
51
58
  and pays for itself immediately.
@@ -20,6 +20,7 @@
20
20
 
21
21
  - **Complexity:** {{simple | complex}}
22
22
  - **Why:** {{one-line rationale citing the signals that decided it}}
23
+ - **Web stack:** {{browser-facing framework or "not a web UI" — e.g. Next.js + Playwright, static HTML, N/A for CLI/API-only}}
23
24
 
24
25
  ## Current State
25
26
 
@@ -42,7 +42,7 @@
42
42
  - Contract verification: {{tests / shell verifiers / fixtures / artifact checks}}
43
43
  - Integration verification: {{real subsystem interaction that must be exercised, or none}}
44
44
  - Operational verification: {{service lifecycle / restart / reconnect / supervision / deploy-install behavior, or none}}
45
- - UAT / human verification: {{what needs real human judgment, or none}}
45
+ - UAT / human verification: {{what needs real human judgment, or none — for web apps prefer browser-executable / runtime-executable Playwright checks over deferring UI proof to humans}}
46
46
 
47
47
  ## Milestone Definition of Done
48
48
 
@@ -5,9 +5,13 @@
5
5
 
6
6
  ## UAT Type
7
7
 
8
- - UAT mode: {{artifact-driven | live-runtime | human-experience | mixed}}
8
+ - UAT mode: {{artifact-driven | browser-executable | runtime-executable | live-runtime | human-experience | mixed}}
9
9
  - Why this mode is sufficient: {{reason}}
10
10
 
11
+ <!-- Web apps: never use artifact-driven when steps open a browser, navigate to localhost,
12
+ or capture screenshots. Use browser-executable (browser_* tools) or runtime-executable
13
+ (npx playwright test). Name dev-server preconditions below. -->
14
+
11
15
  ## Preconditions
12
16
 
13
17
  {{whatMustBeTrueBeforeTesting — server running, data seeded, etc.}}
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Regression tests for ask_user_questions renderResult when Claude Code MCP
3
+ * omits structuredContent and the chat controller passes details as undefined
4
+ * or an empty object.
5
+ */
6
+
7
+ import assert from "node:assert/strict";
8
+ import { test } from "node:test";
9
+ import askUserQuestionsExtension from "../../ask-user-questions.ts";
10
+
11
+ const fakeTheme = {
12
+ fg: (_color: string, text: string) => text,
13
+ bold: (text: string) => text,
14
+ };
15
+
16
+ function getAskUserQuestionsTool() {
17
+ const tools: any[] = [];
18
+ askUserQuestionsExtension({ registerTool: (tool: any) => tools.push(tool) } as any);
19
+ const tool = tools.find((t) => t.name === "ask_user_questions");
20
+ assert.ok(tool, "ask_user_questions should be registered");
21
+ return tool;
22
+ }
23
+
24
+ function renderText(tool: any, result: unknown, args?: unknown): string {
25
+ const rendered = tool.renderResult(result, {}, fakeTheme, { args });
26
+ return String((rendered as any).content ?? (rendered as any).text ?? rendered);
27
+ }
28
+
29
+ const depthQuestion = {
30
+ id: "depth_check",
31
+ header: "Depth Check",
32
+ question: "Did I capture the depth right?",
33
+ options: [
34
+ { label: "Yes, you got it", description: "Proceed" },
35
+ { label: "Not quite - let me clarify", description: "Clarify" },
36
+ ],
37
+ };
38
+
39
+ test("ask_user_questions renderResult shows answers when details is undefined (MCP text-only wire)", () => {
40
+ const tool = getAskUserQuestionsTool();
41
+ const contentText = JSON.stringify({
42
+ answers: { depth_check: { answers: ["Yes, you got it"] } },
43
+ });
44
+ const text = renderText(
45
+ tool,
46
+ {
47
+ content: [{ type: "text", text: contentText }],
48
+ details: undefined,
49
+ isError: false,
50
+ },
51
+ { questions: [depthQuestion] },
52
+ );
53
+
54
+ assert.match(text, /✓/);
55
+ assert.match(text, /Depth Check/);
56
+ assert.match(text, /Yes, you got it/);
57
+ assert.doesNotMatch(text, /Cancelled/i);
58
+ });
59
+
60
+ test("ask_user_questions renderResult shows answers when details is empty object (#cc-elicitation)", () => {
61
+ const tool = getAskUserQuestionsTool();
62
+ const contentText = JSON.stringify({
63
+ answers: { depth_check: { answers: ["Yes, you got it"] } },
64
+ });
65
+ const text = renderText(
66
+ tool,
67
+ {
68
+ content: [{ type: "text", text: contentText }],
69
+ details: {},
70
+ isError: false,
71
+ },
72
+ { questions: [depthQuestion] },
73
+ );
74
+
75
+ assert.match(text, /Yes, you got it/);
76
+ assert.doesNotMatch(text, /Cancelled/i);
77
+ });
78
+
79
+ test("ask_user_questions renderResult still shows Cancelled for explicit cancel payload", () => {
80
+ const tool = getAskUserQuestionsTool();
81
+ const text = renderText(
82
+ tool,
83
+ {
84
+ content: [{ type: "text", text: "ask_user_questions was cancelled before receiving a response" }],
85
+ details: { questions: [depthQuestion], response: null, cancelled: true },
86
+ isError: false,
87
+ },
88
+ { questions: [depthQuestion] },
89
+ );
90
+
91
+ assert.match(text, /Cancelled/i);
92
+ });
@@ -29,11 +29,16 @@ import {
29
29
  _refreshLastCommitForTests,
30
30
  _getLastCommitForTests,
31
31
  _getLastCommitFetchedAtForTests,
32
+ formatToolSurfaceSnapshot,
32
33
  formatRuntimeHealthSignal,
33
34
  shouldRenderRoadmapProgress,
34
35
  } from "../auto-dashboard.ts";
35
36
  import { getAutoDashboardData } from "../auto.ts";
36
- import { autoSession } from "../auto-runtime-state.ts";
37
+ import {
38
+ autoSession,
39
+ clearAutoToolSurfaceSnapshot,
40
+ recordAutoToolSurfaceSnapshot,
41
+ } from "../auto-runtime-state.ts";
37
42
  import { formatRtkSavingsLabel } from "../../shared/rtk-session-stats.ts";
38
43
  import {
39
44
  openDatabase,
@@ -530,6 +535,29 @@ test("getAutoDashboardData returns RTK savings in the dashboard payload", () =>
530
535
  }
531
536
  });
532
537
 
538
+ test("getAutoDashboardData exposes typed tool-surface snapshots", () => {
539
+ autoSession.reset();
540
+ clearAutoToolSurfaceSnapshot();
541
+ autoSession.active = true;
542
+ recordAutoToolSurfaceSnapshot({
543
+ source: "provider-adjustment",
544
+ unitType: "run-uat",
545
+ modelFacingToolNames: ["read"],
546
+ registeredToolNames: ["read", "browser_navigate"],
547
+ scopedToolNames: ["read", "browser_navigate"],
548
+ presentedToolNames: ["browser_navigate"],
549
+ capturedAt: 456,
550
+ });
551
+
552
+ const data = getAutoDashboardData();
553
+
554
+ assert.equal(data.toolSurface?.source, "provider-adjustment");
555
+ assert.equal(formatToolSurfaceSnapshot(data.toolSurface), "run-uat: model 1 / registered 2 / scoped 2 / presented 1");
556
+
557
+ autoSession.reset();
558
+ clearAutoToolSurfaceSnapshot();
559
+ });
560
+
533
561
  test("RTK savings label formats the dashboard footer text", () => {
534
562
  assert.equal(formatRtkSavingsLabel(null), null);
535
563
  assert.equal(