@opengsd/gsd-pi 1.1.1-dev.b2556262 → 1.2.0-dev.4813ead6

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 (500) 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/project-sessions.js +4 -2
  5. package/dist/resources/.managed-resources-content-hash +1 -1
  6. package/dist/resources/extensions/ask-user-questions.js +78 -23
  7. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +101 -237
  8. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
  9. package/dist/resources/extensions/github-sync/templates.js +3 -3
  10. package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
  11. package/dist/resources/extensions/gsd/auto/contracts.js +8 -1
  12. package/dist/resources/extensions/gsd/auto/loop.js +74 -56
  13. package/dist/resources/extensions/gsd/auto/orchestrator.js +763 -63
  14. package/dist/resources/extensions/gsd/auto/phases.js +28 -3
  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 +4 -3
  21. package/dist/resources/extensions/gsd/auto-prompts.js +191 -9
  22. package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
  23. package/dist/resources/extensions/gsd/auto-runtime-state.js +17 -0
  24. package/dist/resources/extensions/gsd/auto-start.js +12 -23
  25. package/dist/resources/extensions/gsd/auto-timers.js +16 -2
  26. package/dist/resources/extensions/gsd/auto-tool-tracking.js +37 -0
  27. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +33 -29
  28. package/dist/resources/extensions/gsd/auto-verification.js +7 -7
  29. package/dist/resources/extensions/gsd/auto-worktree.js +45 -36
  30. package/dist/resources/extensions/gsd/auto.js +73 -471
  31. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
  32. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +11 -37
  33. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
  34. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +103 -138
  35. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +63 -4
  36. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
  37. package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
  38. package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
  39. package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
  40. package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
  41. package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
  42. package/dist/resources/extensions/gsd/commands-ship.js +2 -2
  43. package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
  44. package/dist/resources/extensions/gsd/db-workspace.js +103 -0
  45. package/dist/resources/extensions/gsd/debug-logger.js +10 -0
  46. package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
  47. package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
  48. package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  49. package/dist/resources/extensions/gsd/doctor-proactive.js +7 -2
  50. package/dist/resources/extensions/gsd/doctor.js +16 -9
  51. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  52. package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
  53. package/dist/resources/extensions/gsd/gsd-db.js +12 -0
  54. package/dist/resources/extensions/gsd/guided-flow.js +36 -470
  55. package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
  56. package/dist/resources/extensions/gsd/markdown-renderer.js +33 -33
  57. package/dist/resources/extensions/gsd/mcp-filter.js +8 -1
  58. package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
  59. package/dist/resources/extensions/gsd/md-importer.js +4 -3
  60. package/dist/resources/extensions/gsd/migrate/safety.js +2 -2
  61. package/dist/resources/extensions/gsd/migration-auto-check.js +3 -2
  62. package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
  63. package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
  64. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
  65. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
  66. package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
  67. package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
  68. package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
  69. package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
  70. package/dist/resources/extensions/gsd/native-git-bridge.js +45 -0
  71. package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
  72. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
  73. package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
  74. package/dist/resources/extensions/gsd/preferences.js +147 -29
  75. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  76. package/dist/resources/extensions/gsd/prompts/discuss.md +6 -7
  77. package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
  78. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
  79. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +6 -6
  80. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
  81. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
  82. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  83. package/dist/resources/extensions/gsd/prompts/plan-slice.md +2 -1
  84. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  85. package/dist/resources/extensions/gsd/prompts/research-milestone.md +2 -2
  86. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  87. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +5 -3
  88. package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
  89. package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
  90. package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
  91. package/dist/resources/extensions/gsd/question-transport.js +86 -0
  92. package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
  93. package/dist/resources/extensions/gsd/schemas/parsers.js +6 -1
  94. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
  95. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +21 -1
  96. package/dist/resources/extensions/gsd/state.js +13 -5
  97. package/dist/resources/extensions/gsd/templates/plan.md +7 -0
  98. package/dist/resources/extensions/gsd/templates/project.md +1 -0
  99. package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
  100. package/dist/resources/extensions/gsd/templates/uat.md +5 -1
  101. package/dist/resources/extensions/gsd/tool-contract.js +52 -8
  102. package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
  103. package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
  104. package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
  105. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
  106. package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
  107. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +169 -20
  108. package/dist/resources/extensions/gsd/uat-policy.js +16 -10
  109. package/dist/resources/extensions/gsd/uat-run.js +9 -14
  110. package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
  111. package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
  112. package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
  113. package/dist/resources/extensions/gsd/user-input-boundary.js +65 -4
  114. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  115. package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
  116. package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
  117. package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
  118. package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
  119. package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
  120. package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
  121. package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
  122. package/dist/resources/extensions/shared/interview-ui.js +2 -2
  123. package/dist/resources/shared/claude-runtime-floor.js +182 -0
  124. package/dist/tsconfig.extensions.tsbuildinfo +1 -0
  125. package/dist/update-cmd.js +20 -0
  126. package/dist/web/standalone/.next/BUILD_ID +1 -1
  127. package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
  128. package/dist/web/standalone/.next/build-manifest.json +3 -3
  129. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  130. package/dist/web/standalone/.next/react-loadable-manifest.json +8 -8
  131. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  132. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  140. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  145. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  146. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  147. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  148. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  149. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  150. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  151. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  152. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  153. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  154. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  155. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  156. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  157. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  159. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  160. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  161. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  162. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  163. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  164. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  165. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  166. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  167. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  168. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  169. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  172. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  173. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  174. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  175. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  176. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  177. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  178. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  179. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  180. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  182. package/dist/web/standalone/.next/server/app/index.html +1 -1
  183. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  184. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  185. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  186. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  187. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  188. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  189. package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
  190. package/dist/web/standalone/.next/server/chunks/5047.js +2 -0
  191. package/dist/web/standalone/.next/server/chunks/5124.js +1 -0
  192. package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
  193. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  194. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  196. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  197. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  198. package/dist/web/standalone/.next/static/chunks/2659.b7b129ee6a769448.js +1 -0
  199. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
  200. package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
  201. package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
  202. package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
  203. package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
  204. package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
  205. package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
  206. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  207. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  208. package/dist/web/standalone/node_modules/postcss/lib/container.js +26 -18
  209. package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +47 -14
  210. package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
  211. package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
  212. package/dist/web/standalone/node_modules/postcss/lib/input.js +54 -29
  213. package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +47 -37
  214. package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +26 -9
  215. package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +57 -55
  216. package/dist/web/standalone/node_modules/postcss/lib/node.js +99 -31
  217. package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
  218. package/dist/web/standalone/node_modules/postcss/lib/parser.js +10 -9
  219. package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
  220. package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +30 -11
  221. package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
  222. package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
  223. package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
  224. package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +69 -28
  225. package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +6 -2
  226. package/dist/web/standalone/node_modules/postcss/package.json +48 -48
  227. package/dist/web-mode.d.ts +2 -0
  228. package/dist/web-mode.js +20 -8
  229. package/package.json +17 -11
  230. package/packages/cloud-mcp-gateway/package.json +2 -2
  231. package/packages/contracts/package.json +1 -1
  232. package/packages/daemon/package.json +4 -4
  233. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
  234. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  235. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
  236. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  237. package/packages/gsd-agent-core/package.json +5 -5
  238. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  239. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +3 -0
  240. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  241. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +1 -1
  242. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  243. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  244. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +106 -40
  245. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  246. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
  247. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
  248. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
  249. package/packages/gsd-agent-modes/package.json +7 -7
  250. package/packages/mcp-server/dist/server.d.ts +10 -0
  251. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  252. package/packages/mcp-server/dist/server.js +8 -0
  253. package/packages/mcp-server/dist/server.js.map +1 -1
  254. package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
  255. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  256. package/packages/mcp-server/dist/workflow-tools.js +2 -1
  257. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  258. package/packages/mcp-server/package.json +3 -3
  259. package/packages/native/package.json +1 -1
  260. package/packages/pi-agent-core/package.json +1 -1
  261. package/packages/pi-ai/dist/image-models.generated.d.ts +30 -0
  262. package/packages/pi-ai/dist/image-models.generated.d.ts.map +1 -1
  263. package/packages/pi-ai/dist/image-models.generated.js +30 -0
  264. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  265. package/packages/pi-ai/dist/models.generated.d.ts +8 -127
  266. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  267. package/packages/pi-ai/dist/models.generated.js +47 -166
  268. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  269. package/packages/pi-ai/package.json +1 -1
  270. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/auth-storage.js +11 -3
  272. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  273. package/packages/pi-coding-agent/package.json +7 -7
  274. package/packages/pi-tui/dist/components/input.js +1 -1
  275. package/packages/pi-tui/dist/components/input.js.map +1 -1
  276. package/packages/pi-tui/dist/keys.d.ts.map +1 -1
  277. package/packages/pi-tui/dist/keys.js +39 -30
  278. package/packages/pi-tui/dist/keys.js.map +1 -1
  279. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  280. package/packages/pi-tui/dist/stdin-buffer.js +22 -0
  281. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  282. package/packages/pi-tui/package.json +2 -2
  283. package/packages/rpc-client/package.json +2 -2
  284. package/pkg/package.json +1 -1
  285. package/scripts/install/deps.js +10 -0
  286. package/scripts/link-workspace-packages.cjs +7 -40
  287. package/src/resources/extensions/ask-user-questions.ts +87 -24
  288. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +126 -289
  289. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +242 -2
  290. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
  291. package/src/resources/extensions/github-sync/templates.ts +3 -3
  292. package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
  293. package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
  294. package/src/resources/extensions/gsd/auto/contracts.ts +40 -121
  295. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
  296. package/src/resources/extensions/gsd/auto/loop.ts +83 -61
  297. package/src/resources/extensions/gsd/auto/orchestrator.ts +913 -64
  298. package/src/resources/extensions/gsd/auto/phases.ts +35 -3
  299. package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
  300. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  301. package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
  302. package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
  303. package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
  304. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -3
  305. package/src/resources/extensions/gsd/auto-prompts.ts +220 -9
  306. package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
  307. package/src/resources/extensions/gsd/auto-runtime-state.ts +30 -0
  308. package/src/resources/extensions/gsd/auto-start.ts +17 -20
  309. package/src/resources/extensions/gsd/auto-timers.ts +16 -2
  310. package/src/resources/extensions/gsd/auto-tool-tracking.ts +40 -0
  311. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +42 -30
  312. package/src/resources/extensions/gsd/auto-verification.ts +7 -8
  313. package/src/resources/extensions/gsd/auto-worktree.ts +57 -42
  314. package/src/resources/extensions/gsd/auto.ts +96 -508
  315. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
  316. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +10 -37
  317. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
  318. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +120 -151
  319. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +107 -3
  320. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
  321. package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
  322. package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
  323. package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
  324. package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
  325. package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
  326. package/src/resources/extensions/gsd/commands-ship.ts +2 -2
  327. package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
  328. package/src/resources/extensions/gsd/db-workspace.ts +170 -0
  329. package/src/resources/extensions/gsd/debug-logger.ts +11 -0
  330. package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
  331. package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
  332. package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  333. package/src/resources/extensions/gsd/doctor-proactive.ts +8 -2
  334. package/src/resources/extensions/gsd/doctor.ts +15 -5
  335. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  336. package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
  337. package/src/resources/extensions/gsd/gsd-db.ts +12 -0
  338. package/src/resources/extensions/gsd/guided-flow.ts +49 -560
  339. package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
  340. package/src/resources/extensions/gsd/markdown-renderer.ts +40 -20
  341. package/src/resources/extensions/gsd/mcp-filter.ts +9 -1
  342. package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
  343. package/src/resources/extensions/gsd/md-importer.ts +3 -3
  344. package/src/resources/extensions/gsd/migrate/safety.ts +2 -2
  345. package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
  346. package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
  347. package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
  348. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
  349. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
  350. package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
  351. package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
  352. package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
  353. package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
  354. package/src/resources/extensions/gsd/native-git-bridge.ts +48 -0
  355. package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
  356. package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
  357. package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
  358. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  359. package/src/resources/extensions/gsd/preferences.ts +173 -28
  360. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  361. package/src/resources/extensions/gsd/prompts/discuss.md +6 -7
  362. package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
  363. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
  364. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +6 -6
  365. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
  366. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
  367. package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  368. package/src/resources/extensions/gsd/prompts/plan-slice.md +2 -1
  369. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  370. package/src/resources/extensions/gsd/prompts/research-milestone.md +2 -2
  371. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  372. package/src/resources/extensions/gsd/prompts/validate-milestone.md +5 -3
  373. package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
  374. package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
  375. package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
  376. package/src/resources/extensions/gsd/question-transport.ts +138 -0
  377. package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
  378. package/src/resources/extensions/gsd/schemas/parsers.ts +6 -1
  379. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
  380. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +31 -10
  381. package/src/resources/extensions/gsd/state.ts +15 -5
  382. package/src/resources/extensions/gsd/templates/plan.md +7 -0
  383. package/src/resources/extensions/gsd/templates/project.md +1 -0
  384. package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
  385. package/src/resources/extensions/gsd/templates/uat.md +5 -1
  386. package/src/resources/extensions/gsd/tests/artifact-db-drift-memo.test.ts +66 -0
  387. package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
  388. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
  389. package/src/resources/extensions/gsd/tests/auto-dispatch-baseline-harness.test.ts +53 -0
  390. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +321 -5
  391. package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
  392. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
  393. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +709 -845
  394. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +38 -10
  395. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
  396. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
  397. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  398. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
  399. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
  400. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +15 -0
  401. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
  402. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
  403. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
  404. package/src/resources/extensions/gsd/tests/execute-summary-save-empty-project.test.ts +64 -1
  405. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
  406. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
  407. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
  408. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
  409. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +157 -0
  410. package/src/resources/extensions/gsd/tests/markdown-renderer-parse-cache.test.ts +75 -0
  411. package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
  412. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +58 -0
  413. package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
  414. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
  415. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
  416. package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
  417. package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
  418. package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
  419. package/src/resources/extensions/gsd/tests/native-merge-regular.test.ts +139 -0
  420. package/src/resources/extensions/gsd/tests/orchestrator-legacy-parity.test.ts +127 -0
  421. package/src/resources/extensions/gsd/tests/parse-project-milestone-bridge.test.ts +77 -0
  422. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
  423. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +6 -2
  424. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
  425. package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
  426. package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
  427. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +75 -2
  428. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
  429. package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
  430. package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
  431. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +94 -0
  432. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +65 -0
  433. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
  434. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
  435. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
  436. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +101 -1
  437. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
  438. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +21 -6
  439. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +38 -0
  440. package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
  441. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
  442. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
  443. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
  444. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +147 -0
  445. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
  446. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
  447. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
  448. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
  449. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +21 -0
  450. package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
  451. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +24 -0
  452. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
  453. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -3
  454. package/src/resources/extensions/gsd/tests/write-gate.test.ts +79 -0
  455. package/src/resources/extensions/gsd/tool-contract.ts +86 -8
  456. package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
  457. package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
  458. package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
  459. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
  460. package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
  461. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +183 -21
  462. package/src/resources/extensions/gsd/uat-policy.ts +19 -10
  463. package/src/resources/extensions/gsd/uat-run.ts +10 -14
  464. package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
  465. package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
  466. package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
  467. package/src/resources/extensions/gsd/user-input-boundary.ts +55 -5
  468. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  469. package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
  470. package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
  471. package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
  472. package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
  473. package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
  474. package/src/resources/extensions/gsd/worktree-lifecycle.ts +7 -16
  475. package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
  476. package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
  477. package/src/resources/extensions/shared/interview-ui.ts +15 -2
  478. package/src/resources/shared/claude-runtime-floor.ts +248 -0
  479. package/dist/web/standalone/.next/server/chunks/678.js +0 -2
  480. package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
  481. package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
  482. package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
  483. package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
  484. package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
  485. package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
  486. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +0 -21
  487. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +0 -1
  488. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +0 -213
  489. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +0 -1
  490. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts +0 -28
  491. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts.map +0 -1
  492. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js +0 -249
  493. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js.map +0 -1
  494. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts +0 -19
  495. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts.map +0 -1
  496. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js +0 -797
  497. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js.map +0 -1
  498. package/scripts/ensure-workspace-builds.cjs +0 -129
  499. /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → tkLHUSzPA2kMmWz4DmGwI}/_buildManifest.js +0 -0
  500. /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → tkLHUSzPA2kMmWz4DmGwI}/_ssgManifest.js +0 -0
@@ -26,6 +26,7 @@ import {
26
26
  renderPreferencesForSystemPrompt,
27
27
  _resetParseWarningFlag,
28
28
  } from "../preferences.ts";
29
+ import { collectPreferenceDiagnostics, formatPreferenceDiagnostic } from "../preferences-diagnostics.ts";
29
30
  import { formatConfiguredModel, toPersistedModelId } from "../commands-prefs-wizard.ts";
30
31
  import { _resetLogs, peekLogs } from "../workflow-logger.ts";
31
32
  import type { GSDPreferences, GSDModelConfigV2, GSDPhaseModelConfig } from "../preferences.ts";
@@ -819,6 +820,188 @@ bad: [
819
820
  _resetLogs();
820
821
  });
821
822
 
823
+ test("malformed global preferences load with a structured parse diagnostic", (t) => {
824
+ const originalGsdHome = process.env.GSD_HOME;
825
+ const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-diagnostic-home-"));
826
+ t.after(() => {
827
+ if (originalGsdHome === undefined) delete process.env.GSD_HOME;
828
+ else process.env.GSD_HOME = originalGsdHome;
829
+ rmSync(tempGsdHome, { recursive: true, force: true });
830
+ _resetParseWarningFlag();
831
+ _resetLogs();
832
+ });
833
+
834
+ process.env.GSD_HOME = tempGsdHome;
835
+ _resetParseWarningFlag();
836
+ _resetLogs();
837
+ writeFileSync(
838
+ join(tempGsdHome, "PREFERENCES.md"),
839
+ [
840
+ "---",
841
+ "version: 1",
842
+ "models:",
843
+ " validation:",
844
+ " openrouter/deepseek/deepseek-v4-pro",
845
+ " thinking: high",
846
+ "---",
847
+ "",
848
+ ].join("\n"),
849
+ "utf-8",
850
+ );
851
+
852
+ const loaded = loadGlobalGSDPreferences();
853
+ assert.notEqual(loaded, null);
854
+ assert.deepEqual(loaded!.preferences, {});
855
+ const diagnostic = loaded!.diagnostics?.[0];
856
+ assert.equal(diagnostic?.kind, "parse");
857
+ assert.equal(diagnostic?.severity, "error");
858
+ assert.equal(diagnostic?.line, 5);
859
+ assert.equal(diagnostic?.column, 5);
860
+ assert.equal(diagnostic?.ignored, true);
861
+ assert.match(diagnostic?.message ?? "", /Implicit keys need/);
862
+
863
+ const formatted = formatPreferenceDiagnostic(diagnostic!);
864
+ assert.match(formatted, /GSD global preferences error/);
865
+ assert.match(formatted, /line 5, column 5/);
866
+ assert.match(formatted, /Preferences from this file were ignored/);
867
+ });
868
+
869
+ test("project preference validation errors load with structured diagnostics", (t) => {
870
+ const originalCwd = process.cwd();
871
+ const originalGsdHome = process.env.GSD_HOME;
872
+ const tempProject = mkdtempSync(join(tmpdir(), "gsd-prefs-validation-project-"));
873
+ const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-validation-home-"));
874
+ t.after(() => {
875
+ process.chdir(originalCwd);
876
+ if (originalGsdHome === undefined) delete process.env.GSD_HOME;
877
+ else process.env.GSD_HOME = originalGsdHome;
878
+ rmSync(tempProject, { recursive: true, force: true });
879
+ rmSync(tempGsdHome, { recursive: true, force: true });
880
+ });
881
+
882
+ mkdirSync(join(tempProject, ".gsd"), { recursive: true });
883
+ process.env.GSD_HOME = tempGsdHome;
884
+ process.chdir(tempProject);
885
+ writeFileSync(
886
+ join(tempProject, ".gsd", "PREFERENCES.md"),
887
+ "---\nversion: 3\n---\n",
888
+ "utf-8",
889
+ );
890
+
891
+ const loaded = loadProjectGSDPreferences(tempProject);
892
+ assert.notEqual(loaded, null);
893
+ assert.equal(loaded!.preferences.version, undefined);
894
+ const diagnostic = loaded!.diagnostics?.find((item) => item.kind === "validation");
895
+ assert.equal(diagnostic?.scope, "project");
896
+ assert.equal(diagnostic?.severity, "error");
897
+ assert.equal(diagnostic?.sanitized, true);
898
+ assert.match(diagnostic?.message ?? "", /unsupported version 3/);
899
+
900
+ const collected = collectPreferenceDiagnostics(tempProject);
901
+ assert.ok(
902
+ collected.some((item) => item.path === loaded!.path && item.message.includes("unsupported version 3")),
903
+ "collector should include project validation diagnostics",
904
+ );
905
+ });
906
+
907
+ test("malformed project preferences do not override effective global wrapper", (t) => {
908
+ const originalCwd = process.cwd();
909
+ const originalGsdHome = process.env.GSD_HOME;
910
+ const tempProject = mkdtempSync(join(tmpdir(), "gsd-prefs-effective-project-"));
911
+ const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-effective-home-"));
912
+ t.after(() => {
913
+ process.chdir(originalCwd);
914
+ if (originalGsdHome === undefined) delete process.env.GSD_HOME;
915
+ else process.env.GSD_HOME = originalGsdHome;
916
+ rmSync(tempProject, { recursive: true, force: true });
917
+ rmSync(tempGsdHome, { recursive: true, force: true });
918
+ _resetParseWarningFlag();
919
+ _resetLogs();
920
+ });
921
+
922
+ mkdirSync(join(tempProject, ".gsd"), { recursive: true });
923
+ process.env.GSD_HOME = tempGsdHome;
924
+ process.chdir(tempProject);
925
+ _resetParseWarningFlag();
926
+ _resetLogs();
927
+
928
+ const globalPath = getGlobalGSDPreferencesPath();
929
+ const projectPath = getProjectGSDPreferencesPath(tempProject);
930
+ writeFileSync(globalPath, "---\nlanguage: Spanish\n---\n", "utf-8");
931
+ writeFileSync(
932
+ projectPath,
933
+ [
934
+ "---",
935
+ "version: 1",
936
+ "models:",
937
+ " validation:",
938
+ " openrouter/deepseek/deepseek-v4-pro",
939
+ " thinking: high",
940
+ "---",
941
+ "",
942
+ ].join("\n"),
943
+ "utf-8",
944
+ );
945
+
946
+ const projectPrefs = loadProjectGSDPreferences(tempProject);
947
+ assert.equal(projectPrefs?.ignored, true);
948
+
949
+ const loaded = loadEffectiveGSDPreferences(tempProject);
950
+ assert.notEqual(loaded, null);
951
+ assert.equal(loaded!.path, globalPath);
952
+ assert.equal(loaded!.scope, "global");
953
+ assert.equal(loaded!.preferences.language, "Spanish");
954
+ assert.ok(
955
+ loaded!.diagnostics?.some((item) => item.path === projectPath && item.kind === "parse"),
956
+ "effective global preferences should carry malformed project diagnostics",
957
+ );
958
+ });
959
+
960
+ test("malformed global preferences: loadEffectiveGSDPreferences returns null without project file", (t) => {
961
+ const originalCwd = process.cwd();
962
+ const originalGsdHome = process.env.GSD_HOME;
963
+ const tempProject = mkdtempSync(join(tmpdir(), "gsd-prefs-effective-malformed-global-"));
964
+ const tempGsdHome = mkdtempSync(join(tmpdir(), "gsd-prefs-effective-malformed-home-"));
965
+ t.after(() => {
966
+ process.chdir(originalCwd);
967
+ if (originalGsdHome === undefined) delete process.env.GSD_HOME;
968
+ else process.env.GSD_HOME = originalGsdHome;
969
+ rmSync(tempProject, { recursive: true, force: true });
970
+ rmSync(tempGsdHome, { recursive: true, force: true });
971
+ _resetParseWarningFlag();
972
+ _resetLogs();
973
+ });
974
+
975
+ process.env.GSD_HOME = tempGsdHome;
976
+ process.chdir(tempProject);
977
+ _resetParseWarningFlag();
978
+ _resetLogs();
979
+
980
+ const globalPath = getGlobalGSDPreferencesPath();
981
+ writeFileSync(
982
+ globalPath,
983
+ [
984
+ "---",
985
+ "version: 1",
986
+ "models:",
987
+ " validation:",
988
+ " openrouter/deepseek/deepseek-v4-pro",
989
+ " thinking: high",
990
+ "---",
991
+ "",
992
+ ].join("\n"),
993
+ "utf-8",
994
+ );
995
+
996
+ const globalPrefs = loadGlobalGSDPreferences();
997
+ assert.equal(globalPrefs?.ignored, true, "malformed global should be marked ignored");
998
+
999
+ // Symmetric with malformed project + no global: effective result should be null,
1000
+ // not an effective object with ignored:true leaking through.
1001
+ const loaded = loadEffectiveGSDPreferences(tempProject);
1002
+ assert.equal(loaded, null, "effective preferences should be null when only global file is malformed");
1003
+ });
1004
+
822
1005
  // ── Experimental preferences ─────────────────────────────────────────────────
823
1006
 
824
1007
  test("experimental.rtk: true is accepted and stored", () => {
@@ -4,6 +4,7 @@ import { readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import {
6
6
  RUN_UAT_BROWSER_TOOL_NAMES,
7
+ resolveToolPresentationPlan,
7
8
  buildRunUatResultPresentation,
8
9
  buildRunUatPresentationForType,
9
10
  RUN_UAT_READ_ONLY_TOOL_NAMES,
@@ -179,6 +180,33 @@ test("browser-executable UAT presentation uses direct browser tools", () => {
179
180
  assert.ok(!presentation.presentedTools.some((toolName) => toolName.startsWith("mcp__gsd-browser__")));
180
181
  });
181
182
 
183
+ test("run-uat presentation plans carry typed tool-surface snapshots", () => {
184
+ const plan = resolveToolPresentationPlan({
185
+ phase: "run-uat",
186
+ surface: "mcp",
187
+ workflowMcpServerName: "gsd-workflow",
188
+ availableToolNames: [
189
+ "gsd_uat_exec",
190
+ "gsd_uat_result_save",
191
+ "read",
192
+ ],
193
+ includeBrowserTools: [],
194
+ });
195
+
196
+ assert.equal(plan.toolSurface.source, "presentation-plan");
197
+ assert.equal(plan.toolSurface.phase, "run-uat");
198
+ assert.deepEqual(plan.toolSurface.scopedToolNames, [
199
+ "gsd_uat_exec",
200
+ "gsd_uat_result_save",
201
+ "read",
202
+ ]);
203
+ assert.deepEqual(plan.toolSurface.presentedToolNames, [
204
+ "mcp__gsd-workflow__gsd_uat_exec",
205
+ "mcp__gsd-workflow__gsd_uat_result_save",
206
+ "read",
207
+ ]);
208
+ });
209
+
182
210
  test("live-runtime and mixed UAT presentations also surface browser tools", () => {
183
211
  // Regression (M001/S03): the run-uat prompt tells live-runtime and mixed to
184
212
  // drive a browser, so the runner must actually receive the browser tools and
@@ -517,6 +545,24 @@ test("plan-slice prompt clarifies gsd_plan_slice handles task persistence", () =
517
545
  assert.match(prompt, /gsd_plan_slice` handles task persistence/i);
518
546
  });
519
547
 
548
+ test("plan-slice prompt references web app UAT guidance when planning browser work", () => {
549
+ const prompt = readPrompt("plan-slice");
550
+ assert.match(prompt, /Web App UAT guidance/i);
551
+ assert.match(prompt, /Playwright smoke scaffolding/i);
552
+ });
553
+
554
+ test("complete-slice prompt references web app UAT mode rules", () => {
555
+ const prompt = readPrompt("complete-slice");
556
+ assert.match(prompt, /Web App UAT guidance/i);
557
+ assert.match(prompt, /browser-executable|runtime-executable/i);
558
+ });
559
+
560
+ test("plan-milestone prompt seeds web verification strategy", () => {
561
+ const prompt = readPrompt("plan-milestone");
562
+ assert.match(prompt, /Web apps/i);
563
+ assert.match(prompt, /Playwright|browser_\*/i);
564
+ });
565
+
520
566
  test("replan-slice prompt uses gsd_replan_slice as canonical DB-backed tool", () => {
521
567
  const prompt = readPrompt("replan-slice");
522
568
  assert.match(prompt, /gsd_replan_slice/);
@@ -564,6 +610,33 @@ test("validate-milestone prompt dispatches parallel reviewers", () => {
564
610
  assert.match(prompt, /assessment evidence/i);
565
611
  });
566
612
 
613
+ // ─── ADR-029: forward preloaded evidence to validate reviewers ────────
614
+ test("validate-milestone forwards preloaded evidence to reviewers and keeps full reads on-demand", () => {
615
+ const prompt = readPrompt("validate-milestone");
616
+ // Orchestrator is told to embed the preloaded evidence into reviewer tasks.
617
+ assert.match(prompt, /[Ee]mbed the relevant preloaded evidence/);
618
+ // Each reviewer is told to use the preloaded evidence, not re-read from disk.
619
+ const useCount = (prompt.match(/do not re-read them from disk/g) ?? []).length;
620
+ assert.ok(useCount >= 3, `expected all three reviewers to use preloaded evidence, found ${useCount}`);
621
+ // Full reads are explicitly the on-demand exception, not the routine path.
622
+ assert.match(prompt, /only if (its|the) preloaded (excerpt|evidence) is missing, truncated, or inconsistent/i);
623
+ });
624
+
625
+ // ─── ADR-029: research-milestone grounds instead of surveying ─────────
626
+ test("research-milestone prompt grounds in preloaded context instead of open-ended survey", () => {
627
+ const prompt = readPrompt("research-milestone");
628
+ // Grounded-research invariant present.
629
+ assert.match(prompt, /do not re-survey/i);
630
+ assert.match(prompt, /Codebase Snapshot and Project Classification/);
631
+ // The old open-ended survey license is gone (no "use `scout` to build a broad map").
632
+ assert.doesNotMatch(prompt, /use `scout` to build a broad map/);
633
+ // resolve_library/docs lookups remain permitted (bounded, external).
634
+ assert.match(prompt, /resolve_library/);
635
+ // Incremental save enables resume after interruption.
636
+ assert.match(prompt, /Save \*\*incrementally\*\*/);
637
+ assert.match(prompt, /Resume — Prior Partial Research/);
638
+ });
639
+
567
640
  // ─── Prompt migration: replan-slice → gsd_replan_slice ────────────────
568
641
 
569
642
  test("replan-slice prompt names gsd_replan_slice as the tool to use", () => {
@@ -700,8 +773,8 @@ test("guided-discuss prompts require 3-or-4 options plus Other-let-me-discuss in
700
773
  );
701
774
  assert.match(
702
775
  prompt,
703
- /grounded in (the |your |)investigation/i,
704
- `${name} must require options grounded in prior investigation`,
776
+ /grounded in (the |your |)(investigation|preloaded context)/i,
777
+ `${name} must require options grounded in the preloaded context / prior investigation`,
705
778
  );
706
779
  }
707
780
  });
@@ -740,6 +740,15 @@ test("MAX_TRANSIENT_AUTO_RESUMES is at least 8 for sustained overload resilience
740
740
  );
741
741
  });
742
742
 
743
+ // ── OpenAI-completions mid-stream cut (#577) ─────────────────────────────────
744
+
745
+ test("classifyError: 'Stream ended without finish_reason' is transient network (#577)", () => {
746
+ const result = classifyError("Stream ended without finish_reason");
747
+ assert.ok(isTransient(result), "Stream ended without finish_reason must be transient");
748
+ assert.equal(result.kind, "network");
749
+ assert.ok("retryAfterMs" in result && result.retryAfterMs > 0);
750
+ });
751
+
743
752
  // ── Stream idle timeout / partial response (#4558) ──────────────────────────
744
753
 
745
754
  test("classifyError: 'Stream idle timeout - partial response received' is transient network", () => {
@@ -0,0 +1,165 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+
4
+ import type { ContextManagementConfig } from "../preferences-types.js";
5
+ import type { ProviderPayloadPolicyDeps } from "../provider-payload-policy.js";
6
+
7
+ import { applyProviderPayloadPolicy } from "../provider-payload-policy.js";
8
+
9
+ function createDeps(
10
+ overrides: Partial<ProviderPayloadPolicyDeps> & {
11
+ context?: ContextManagementConfig | undefined;
12
+ autoActive?: boolean;
13
+ sourceContextBlock?: string | null;
14
+ } = {},
15
+ ): ProviderPayloadPolicyDeps {
16
+ return {
17
+ isAutoActive: () => overrides.autoActive ?? false,
18
+ loadContextManagementConfig: () => overrides.context,
19
+ renderSourceContextBlock: () => overrides.sourceContextBlock ?? null,
20
+ getEffectiveServiceTier: () => undefined,
21
+ supportsServiceTier: () => false,
22
+ ...overrides,
23
+ };
24
+ }
25
+
26
+ function textFromMessage(message: { content?: unknown }): string {
27
+ const content = message.content;
28
+ if (typeof content === "string") return content;
29
+ if (!Array.isArray(content)) return "";
30
+ const text = content.find((block): block is { text: string } => {
31
+ return Boolean(block && typeof block === "object" && "text" in block && typeof block.text === "string");
32
+ });
33
+ return text?.text ?? "";
34
+ }
35
+
36
+ test("provider payload policy truncates tool results outside auto-mode without masking", () => {
37
+ const messageText = "m".repeat(50);
38
+ const responsesOutput = "r".repeat(50);
39
+ const payload = {
40
+ messages: [
41
+ { role: "user", content: [{ type: "text", text: "keep me" }] },
42
+ { role: "toolResult", content: [{ type: "text", text: messageText }] },
43
+ ],
44
+ input: [
45
+ { role: "user", content: [{ type: "input_text", text: "keep me" }] },
46
+ { type: "function_call_output", call_id: "call_test", output: responsesOutput },
47
+ ],
48
+ };
49
+
50
+ applyProviderPayloadPolicy({
51
+ payload,
52
+ deps: createDeps({ context: { observation_mask_turns: 1, tool_result_max_chars: 10 } }),
53
+ });
54
+
55
+ const truncatedMessage = textFromMessage(payload.messages[1]);
56
+ const truncatedResponsesOutput = String(payload.input[1]?.output ?? "");
57
+ assert.match(truncatedMessage, /\[truncated\]/);
58
+ assert.match(truncatedResponsesOutput, /\[truncated\]/);
59
+ assert.doesNotMatch(truncatedMessage, /result masked/);
60
+ assert.doesNotMatch(truncatedResponsesOutput, /result masked/);
61
+ });
62
+
63
+ test("provider payload policy appends source context after masking and truncation", () => {
64
+ const sourceContextBlock = "## Source Context Block\n\n" + "full source text ".repeat(20);
65
+ const payload = {
66
+ messages: [
67
+ { role: "user", content: [{ type: "text", text: "old turn" }] },
68
+ { role: "toolResult", content: [{ type: "text", text: "old result ".repeat(20) }] },
69
+ { role: "assistant", content: [{ type: "text", text: "ok" }] },
70
+ { role: "user", content: [{ type: "text", text: "new turn" }] },
71
+ { role: "toolResult", content: [{ type: "text", text: "new result ".repeat(20) }] },
72
+ ],
73
+ };
74
+
75
+ applyProviderPayloadPolicy({
76
+ payload,
77
+ deps: createDeps({
78
+ autoActive: true,
79
+ context: { observation_mask_turns: 1, tool_result_max_chars: 80 },
80
+ sourceContextBlock,
81
+ }),
82
+ });
83
+
84
+ const oldResult = textFromMessage(payload.messages[1]);
85
+ const newResult = textFromMessage(payload.messages[4]);
86
+ const appendedContext = textFromMessage(payload.messages[payload.messages.length - 1]);
87
+
88
+ assert.match(oldResult, /result masked/);
89
+ assert.match(newResult, /\[truncated\]/);
90
+ assert.equal(appendedContext, sourceContextBlock);
91
+ assert.doesNotMatch(appendedContext, /\[truncated\]/);
92
+ });
93
+
94
+ test("provider payload policy applies ordering to Responses input payloads", () => {
95
+ const sourceContextBlock = "## Source Context Block\n\n" + "responses source text ".repeat(20);
96
+ const payload = {
97
+ input: [
98
+ { role: "user", content: [{ type: "input_text", text: "old turn" }] },
99
+ { type: "function_call_output", call_id: "call_old", output: "old result ".repeat(20) },
100
+ { type: "message", role: "assistant", content: [{ type: "output_text", text: "ok" }] },
101
+ { role: "user", content: [{ type: "input_text", text: "new turn" }] },
102
+ { type: "function_call_output", call_id: "call_new", output: "new result ".repeat(20) },
103
+ ],
104
+ };
105
+
106
+ applyProviderPayloadPolicy({
107
+ payload,
108
+ deps: createDeps({
109
+ autoActive: true,
110
+ context: { observation_mask_turns: 1, tool_result_max_chars: 80 },
111
+ sourceContextBlock,
112
+ }),
113
+ });
114
+
115
+ assert.match(String(payload.input[1]?.output ?? ""), /result masked/);
116
+ assert.match(String(payload.input[4]?.output ?? ""), /\[truncated\]/);
117
+ assert.equal(textFromMessage(payload.input[payload.input.length - 1]), sourceContextBlock);
118
+ });
119
+
120
+ test("provider payload policy replaces existing source context blocks", () => {
121
+ const payload = {
122
+ messages: [
123
+ { role: "user", content: [{ type: "text", text: "keep me" }] },
124
+ { role: "user", content: [{ type: "text", text: "## Source Context Block\n\nstale" }] },
125
+ ],
126
+ };
127
+
128
+ applyProviderPayloadPolicy({
129
+ payload,
130
+ deps: createDeps({
131
+ autoActive: true,
132
+ sourceContextBlock: "## Source Context Block\n\nfresh",
133
+ }),
134
+ });
135
+
136
+ const sourceMessages = payload.messages.filter((message) => {
137
+ return textFromMessage(message).startsWith("## Source Context Block");
138
+ });
139
+ assert.equal(sourceMessages.length, 1);
140
+ assert.equal(textFromMessage(sourceMessages[0]), "## Source Context Block\n\nfresh");
141
+ });
142
+
143
+ test("provider payload policy sets service tier only for supported models", () => {
144
+ const unsupported = {};
145
+ applyProviderPayloadPolicy({
146
+ payload: unsupported,
147
+ modelId: "claude-opus-4-6",
148
+ deps: createDeps({
149
+ getEffectiveServiceTier: () => "priority",
150
+ supportsServiceTier: (modelId) => modelId === "gpt-5.4",
151
+ }),
152
+ });
153
+ assert.equal("service_tier" in unsupported, false);
154
+
155
+ const supported: Record<string, unknown> = {};
156
+ applyProviderPayloadPolicy({
157
+ payload: supported,
158
+ modelId: "gpt-5.4",
159
+ deps: createDeps({
160
+ getEffectiveServiceTier: () => "priority",
161
+ supportsServiceTier: (modelId) => modelId === "gpt-5.4",
162
+ }),
163
+ });
164
+ assert.equal(supported.service_tier, "priority");
165
+ });
@@ -0,0 +1,47 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Tests for process-level pull request policy.
3
+
4
+ import test from "node:test";
5
+ import assert from "node:assert/strict";
6
+
7
+ import {
8
+ buildPullRequestEvidence,
9
+ createDraftPullRequestFromEvidence,
10
+ } from "../pull-request-process.js";
11
+
12
+ test("buildPullRequestEvidence omits AI credit by policy", () => {
13
+ const evidence = buildPullRequestEvidence({
14
+ milestoneId: "M001",
15
+ milestoneTitle: "Git process",
16
+ aiAssisted: true,
17
+ });
18
+
19
+ assert.equal(evidence.title, "feat: Git process");
20
+ assert.ok(!evidence.body.includes("## AI Assistance Disclosure"));
21
+ assert.ok(!evidence.body.includes("AI assistance"));
22
+ });
23
+
24
+ test("createDraftPullRequestFromEvidence forwards exact evidence and branch options", () => {
25
+ const calls: unknown[][] = [];
26
+ const url = createDraftPullRequestFromEvidence(
27
+ "/repo",
28
+ "M001",
29
+ { title: "feat: Git process", body: "body" },
30
+ { head: "milestone/M001", base: "main" },
31
+ {
32
+ createDraftPR: (basePath, milestoneId, title, body, opts) => {
33
+ calls.push([basePath, milestoneId, title, body, opts]);
34
+ return "https://github.example/pr/1";
35
+ },
36
+ },
37
+ );
38
+
39
+ assert.equal(url, "https://github.example/pr/1");
40
+ assert.deepEqual(calls, [[
41
+ "/repo",
42
+ "M001",
43
+ "feat: Git process",
44
+ "body",
45
+ { head: "milestone/M001", base: "main" },
46
+ ]]);
47
+ });
@@ -18,6 +18,11 @@ import {
18
18
  } from "../bootstrap/write-gate.ts";
19
19
  import { classifyCommand } from "../safety/destructive-guard.ts";
20
20
  import { toRoundResultResponse } from "../../remote-questions/manager.ts";
21
+ import {
22
+ markInteractiveElicitationStart,
23
+ markInteractiveElicitationEnd,
24
+ clearInFlightTools,
25
+ } from "../auto-tool-tracking.ts";
21
26
 
22
27
  function makeTempDir(prefix: string): string {
23
28
  const dir = join(
@@ -708,3 +713,92 @@ test("register-hooks gates MCP ask_user_questions cancellation before requiremen
708
713
  assert.equal(requirementBlock?.block, true, "requirement save must be blocked while gate is pending");
709
714
  assert.match(requirementBlock?.reason ?? "", /has not been confirmed/);
710
715
  });
716
+
717
+ // ─── Foreground self-cancel regression (#cc-elicitation-self-cancel) ───
718
+ // Product-visible symptom: under claude-code-cli + gsd-MCP, ask_user_questions
719
+ // is routed as an SDK elicitation (the human boundary). The message_update hook
720
+ // would arm the approval-gate pause and emit the "waiting for your approval -
721
+ // pausing" notice, tearing down that elicitation and looping a re-ask. The fix
722
+ // makes message_update bail while an interactive elicitation is in flight, while
723
+ // still pausing for prose-only approvals (native-TUI provider, where the marker
724
+ // is always false). This drives the real registered hook end-to-end.
725
+ test("register-hooks message_update does NOT pause while an interactive elicitation is the human boundary, but still pauses otherwise", async (t) => {
726
+ const dir = makeTempDir("elicitation-pause-guard");
727
+ const originalCwd = process.cwd();
728
+ process.chdir(dir);
729
+ resetWriteGateState(dir);
730
+ clearPendingAutoStart(dir);
731
+ clearInFlightTools();
732
+
733
+ t.after(() => {
734
+ try {
735
+ resetWriteGateState(dir);
736
+ clearPendingAutoStart(dir);
737
+ clearInFlightTools();
738
+ } finally {
739
+ process.chdir(originalCwd);
740
+ rmSync(dir, { recursive: true, force: true });
741
+ }
742
+ });
743
+
744
+ const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<any> | any>>();
745
+ const pi = {
746
+ on(event: string, handler: (event: any, ctx?: any) => Promise<any> | any) {
747
+ const existing = handlers.get(event) ?? [];
748
+ existing.push(handler);
749
+ handlers.set(event, existing);
750
+ },
751
+ } as any;
752
+
753
+ const notices: Array<{ text: string; level: string }> = [];
754
+ const ctx = {
755
+ cwd: dir,
756
+ ui: { notify: (text: string, level: string) => notices.push({ text, level }) },
757
+ } as any;
758
+
759
+ registerHooks(pi, []);
760
+
761
+ // A discuss-milestone is the active unit, so the approval text would normally
762
+ // arm the pause/notice path.
763
+ setPendingAutoStart(dir, {
764
+ basePath: dir,
765
+ milestoneId: "M001",
766
+ ctx,
767
+ pi: { sendMessage: () => undefined } as any,
768
+ });
769
+
770
+ // The model's plain-text approval question — identical in both phases.
771
+ const approvalMessage = {
772
+ role: "assistant",
773
+ content: [
774
+ { type: "text", text: "Here is the milestone plan.\n\nDid I capture the project correctly?" },
775
+ ],
776
+ };
777
+
778
+ const fireMessageUpdate = async () => {
779
+ for (const handler of handlers.get("message_update") ?? []) {
780
+ await handler({ message: approvalMessage }, ctx);
781
+ }
782
+ };
783
+
784
+ // Phase 1 — FIX: an interactive elicitation is in flight (claude-code-cli
785
+ // foreground). The pause/notice MUST be suppressed.
786
+ markInteractiveElicitationStart();
787
+ await fireMessageUpdate();
788
+ assert.equal(
789
+ notices.some((n) => /waiting for your approval - pausing/.test(n.text)),
790
+ false,
791
+ "must NOT emit the approval-pause notice while the elicitation is the human boundary",
792
+ );
793
+ markInteractiveElicitationEnd();
794
+
795
+ // Phase 2 — control: no elicitation in flight (native-TUI provider or a
796
+ // prose-only approval). The same message MUST still pause.
797
+ notices.length = 0;
798
+ await fireMessageUpdate();
799
+ assert.equal(
800
+ notices.some((n) => /discuss-milestone M001 is waiting for your approval - pausing/.test(n.text)),
801
+ true,
802
+ "prose-only approval with no elicitation in flight must still arm the pause notice",
803
+ );
804
+ });