@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,98 @@
1
+ import type { PreferenceDiagnostic } from "./preferences-types.js";
2
+ import {
3
+ loadGlobalGSDPreferences,
4
+ loadProjectGSDPreferences,
5
+ } from "./preferences.js";
6
+
7
+ interface PreferenceNotificationContext {
8
+ ui: {
9
+ notify(message: string, type?: "info" | "warning" | "error" | "success"): void;
10
+ };
11
+ }
12
+
13
+ interface PreferenceDiagnosticNotificationOptions {
14
+ surface?: string;
15
+ }
16
+
17
+ const notifiedPreferenceDiagnostics = new Set<string>();
18
+
19
+ export function collectPreferenceDiagnostics(basePath?: string): PreferenceDiagnostic[] {
20
+ const diagnostics = [
21
+ ...(loadGlobalGSDPreferences()?.diagnostics ?? []),
22
+ ...(loadProjectGSDPreferences(basePath)?.diagnostics ?? []),
23
+ ];
24
+
25
+ const seen = new Set<string>();
26
+ const unique: PreferenceDiagnostic[] = [];
27
+ for (const diagnostic of diagnostics) {
28
+ const signature = preferenceDiagnosticSignature(diagnostic);
29
+ if (seen.has(signature)) continue;
30
+ seen.add(signature);
31
+ unique.push(diagnostic);
32
+ }
33
+ return unique;
34
+ }
35
+
36
+ export function formatPreferenceDiagnostic(diagnostic: PreferenceDiagnostic): string {
37
+ const scope = diagnostic.scope === "global" ? "global" : "project";
38
+ const level = diagnostic.severity === "error" ? "error" : "warning";
39
+ const heading = diagnostic.kind === "parse"
40
+ ? `GSD ${scope} preferences ${level}: ${diagnostic.path} could not be parsed.`
41
+ : `GSD ${scope} preferences ${level}: ${diagnostic.path} contains invalid settings.`;
42
+ const detail = formatPreferenceDiagnosticDetail(diagnostic);
43
+ const impact = diagnostic.ignored
44
+ ? "Preferences from this file were ignored; auto-mode may be using defaults."
45
+ : "Invalid settings were ignored or sanitized; auto-mode may be using defaults for them.";
46
+ return `${heading}\n${detail}\n${impact}\nRun /gsd doctor for details.`;
47
+ }
48
+
49
+ export function formatPreferenceDiagnosticDetail(diagnostic: PreferenceDiagnostic): string {
50
+ if (diagnostic.line !== undefined && diagnostic.column !== undefined) {
51
+ return `YAML error at line ${diagnostic.line}, column ${diagnostic.column}: ${diagnostic.message}`;
52
+ }
53
+ return diagnostic.message;
54
+ }
55
+
56
+ export function notifyPreferenceDiagnostics(
57
+ ctx: PreferenceNotificationContext,
58
+ basePath?: string,
59
+ options?: PreferenceDiagnosticNotificationOptions,
60
+ ): number {
61
+ let notified = 0;
62
+ for (const diagnostic of collectPreferenceDiagnostics(basePath)) {
63
+ const signature = preferenceDiagnosticNotificationSignature(diagnostic, options?.surface);
64
+ if (notifiedPreferenceDiagnostics.has(signature)) continue;
65
+ notifiedPreferenceDiagnostics.add(signature);
66
+ ctx.ui.notify(
67
+ formatPreferenceDiagnostic(diagnostic),
68
+ diagnostic.severity === "error" ? "error" : "warning",
69
+ );
70
+ notified++;
71
+ }
72
+ return notified;
73
+ }
74
+
75
+ export function _resetPreferenceDiagnosticNotificationsForTests(): void {
76
+ notifiedPreferenceDiagnostics.clear();
77
+ }
78
+
79
+ function preferenceDiagnosticSignature(diagnostic: PreferenceDiagnostic): string {
80
+ return [
81
+ diagnostic.path,
82
+ diagnostic.scope,
83
+ diagnostic.severity,
84
+ diagnostic.kind,
85
+ diagnostic.message,
86
+ diagnostic.line ?? "",
87
+ diagnostic.column ?? "",
88
+ diagnostic.ignored === true ? "ignored" : "",
89
+ diagnostic.sanitized === true ? "sanitized" : "",
90
+ ].join("\u0000");
91
+ }
92
+
93
+ function preferenceDiagnosticNotificationSignature(
94
+ diagnostic: PreferenceDiagnostic,
95
+ surface = "default",
96
+ ): string {
97
+ return `${surface}\u0000${preferenceDiagnosticSignature(diagnostic)}`;
98
+ }
@@ -594,8 +594,24 @@ export interface LoadedGSDPreferences {
594
594
  path: string;
595
595
  scope: "global" | "project";
596
596
  preferences: GSDPreferences;
597
+ /** True when the file exists but its contents were ignored before merging. */
598
+ ignored?: boolean;
597
599
  /** Validation warnings (unknown keys, type mismatches, deprecations). Empty when preferences are clean. */
598
600
  warnings?: string[];
601
+ /** Structured parse/validation diagnostics for user-visible reporting. */
602
+ diagnostics?: PreferenceDiagnostic[];
603
+ }
604
+
605
+ export interface PreferenceDiagnostic {
606
+ path: string;
607
+ scope: "global" | "project";
608
+ severity: "error" | "warning";
609
+ kind: "parse" | "validation";
610
+ message: string;
611
+ line?: number;
612
+ column?: number;
613
+ ignored?: boolean;
614
+ sanitized?: boolean;
599
615
  }
600
616
 
601
617
  export interface SkillResolution {
@@ -29,6 +29,7 @@ import {
29
29
  type WorkflowMode,
30
30
  type GSDPreferences,
31
31
  type LoadedGSDPreferences,
32
+ type PreferenceDiagnostic,
32
33
  type SkillResolution,
33
34
  type SkillDiscoveryMode,
34
35
  formatSkillRef,
@@ -59,6 +60,7 @@ export type {
59
60
  ClaudeCodeMcpConfig,
60
61
  GSDPreferences,
61
62
  LoadedGSDPreferences,
63
+ PreferenceDiagnostic,
62
64
  SkillResolution,
63
65
  SkillResolutionReport,
64
66
  } from "./preferences-types.js";
@@ -173,14 +175,18 @@ export function normalizePreferencesShape(
173
175
  // ─── Loading ────────────────────────────────────────────────────────────────
174
176
 
175
177
  export function loadGlobalGSDPreferences(): LoadedGSDPreferences | null {
176
- return loadPreferencesFile(globalPreferencesPath(), "global")
177
- ?? loadPreferencesFile(legacyGlobalPreferencesPathLowercase(), "global")
178
- ?? loadPreferencesFile(legacyGlobalPreferencesPath(), "global");
178
+ return loadFirstUsablePreferencesFile([
179
+ globalPreferencesPath(),
180
+ legacyGlobalPreferencesPathLowercase(),
181
+ legacyGlobalPreferencesPath(),
182
+ ], "global");
179
183
  }
180
184
 
181
185
  export function loadProjectGSDPreferences(basePath?: string): LoadedGSDPreferences | null {
182
- return loadPreferencesFile(projectPreferencesPath(basePath), "project")
183
- ?? loadPreferencesFile(legacyProjectPreferencesPathLowercase(basePath), "project");
186
+ return loadFirstUsablePreferencesFile([
187
+ projectPreferencesPath(basePath),
188
+ legacyProjectPreferencesPathLowercase(basePath),
189
+ ], "project");
184
190
  }
185
191
 
186
192
  export function loadEffectiveGSDPreferences(
@@ -189,25 +195,25 @@ export function loadEffectiveGSDPreferences(
189
195
  ): LoadedGSDPreferences | null {
190
196
  const globalPreferences = loadGlobalGSDPreferences();
191
197
  const projectPreferences = loadProjectGSDPreferences(basePath);
192
- const projectHasPlanningDepth = projectPreferences?.preferences.planning_depth !== undefined;
198
+ const effectiveGlobalPreferences = globalPreferences?.ignored ? null : globalPreferences;
199
+ const effectiveProjectPreferences = projectPreferences?.ignored ? null : projectPreferences;
200
+ const projectHasPlanningDepth = effectiveProjectPreferences?.preferences.planning_depth !== undefined;
193
201
 
194
- if (!globalPreferences && !projectPreferences) return null;
202
+ if (!effectiveGlobalPreferences && !effectiveProjectPreferences) return null;
195
203
 
196
204
  let result: LoadedGSDPreferences;
197
- if (!globalPreferences) {
198
- result = projectPreferences!;
199
- } else if (!projectPreferences) {
200
- result = globalPreferences;
205
+ if (!effectiveGlobalPreferences) {
206
+ result = effectiveProjectPreferences!;
207
+ } else if (!effectiveProjectPreferences) {
208
+ result = mergePreferenceMetadata(effectiveGlobalPreferences, projectPreferences);
201
209
  } else {
202
- const mergedWarnings = [
203
- ...(globalPreferences.warnings ?? []),
204
- ...(projectPreferences.warnings ?? []),
205
- ];
210
+ const metadata = mergePreferenceMetadata(effectiveGlobalPreferences, effectiveProjectPreferences);
206
211
  result = {
207
- path: projectPreferences.path,
212
+ path: effectiveProjectPreferences.path,
208
213
  scope: "project",
209
- preferences: mergePreferences(globalPreferences.preferences, projectPreferences.preferences),
210
- ...(mergedWarnings.length > 0 ? { warnings: mergedWarnings } : {}),
214
+ preferences: mergePreferences(effectiveGlobalPreferences.preferences, effectiveProjectPreferences.preferences),
215
+ ...(metadata.warnings ? { warnings: metadata.warnings } : {}),
216
+ ...(metadata.diagnostics ? { diagnostics: metadata.diagnostics } : {}),
211
217
  };
212
218
  }
213
219
 
@@ -240,6 +246,43 @@ export function loadEffectiveGSDPreferences(
240
246
  return result;
241
247
  }
242
248
 
249
+ function mergePreferenceMetadata(
250
+ primary: LoadedGSDPreferences,
251
+ secondary: LoadedGSDPreferences | null,
252
+ ): LoadedGSDPreferences {
253
+ const mergedWarnings = [
254
+ ...(primary.warnings ?? []),
255
+ ...(secondary?.warnings ?? []),
256
+ ];
257
+ const mergedDiagnostics = [
258
+ ...(primary.diagnostics ?? []),
259
+ ...(secondary?.diagnostics ?? []),
260
+ ];
261
+ return {
262
+ ...primary,
263
+ ...(mergedWarnings.length > 0 ? { warnings: mergedWarnings } : {}),
264
+ ...(mergedDiagnostics.length > 0 ? { diagnostics: mergedDiagnostics } : {}),
265
+ };
266
+ }
267
+
268
+ function loadFirstUsablePreferencesFile(
269
+ paths: string[],
270
+ scope: "global" | "project",
271
+ ): LoadedGSDPreferences | null {
272
+ let ignoredPreferences: LoadedGSDPreferences | null = null;
273
+
274
+ for (const path of paths) {
275
+ const loaded = loadPreferencesFile(path, scope);
276
+ if (!loaded) continue;
277
+ if (!loaded.ignored) return mergePreferenceMetadata(loaded, ignoredPreferences);
278
+ ignoredPreferences = ignoredPreferences
279
+ ? mergePreferenceMetadata(ignoredPreferences, loaded)
280
+ : loaded;
281
+ }
282
+
283
+ return ignoredPreferences;
284
+ }
285
+
243
286
  function stripInheritedPlanningDepth(
244
287
  loaded: LoadedGSDPreferences,
245
288
  projectHasPlanningDepth: boolean,
@@ -260,17 +303,40 @@ function loadPreferencesFile(path: string, scope: "global" | "project"): LoadedG
260
303
  if (!existsSync(path)) return null;
261
304
 
262
305
  const raw = readFileSync(path, "utf-8");
263
- const preferences = parsePreferencesMarkdown(raw);
264
- if (!preferences) return null;
306
+ const parsed = parsePreferencesMarkdownWithDiagnostics(raw);
307
+ if (!parsed.preferences && parsed.diagnostics.length === 0) return null;
265
308
 
309
+ const ignored = parsed.diagnostics.some((diagnostic) => diagnostic.ignored === true);
310
+ const preferences = parsed.preferences ?? {};
266
311
  const validation = validatePreferences(preferences);
267
312
  const allWarnings = [...validation.warnings, ...validation.errors];
313
+ const diagnostics: PreferenceDiagnostic[] = [
314
+ ...parsed.diagnostics.map((diagnostic) => ({ ...diagnostic, path, scope })),
315
+ ...validation.errors.map((message): PreferenceDiagnostic => ({
316
+ path,
317
+ scope,
318
+ severity: "error",
319
+ kind: "validation",
320
+ message,
321
+ sanitized: true,
322
+ })),
323
+ ...validation.warnings.map((message): PreferenceDiagnostic => ({
324
+ path,
325
+ scope,
326
+ severity: "warning",
327
+ kind: "validation",
328
+ message,
329
+ sanitized: true,
330
+ })),
331
+ ];
268
332
 
269
333
  return {
270
334
  path,
271
335
  scope,
272
336
  preferences: validation.preferences,
337
+ ...(ignored ? { ignored: true } : {}),
273
338
  ...(allWarnings.length > 0 ? { warnings: allWarnings } : {}),
339
+ ...(diagnostics.length > 0 ? { diagnostics } : {}),
274
340
  };
275
341
  }
276
342
 
@@ -286,20 +352,44 @@ export function _resetParseWarningFlag(): void {
286
352
 
287
353
  /** @internal Exported for testing only */
288
354
  export function parsePreferencesMarkdown(content: string): GSDPreferences | null {
355
+ return parsePreferencesMarkdownWithDiagnostics(content).preferences;
356
+ }
357
+
358
+ type PreferenceParseDiagnostic = Omit<PreferenceDiagnostic, "path" | "scope">;
359
+
360
+ interface PreferenceParseResult {
361
+ preferences: GSDPreferences | null;
362
+ diagnostics: PreferenceParseDiagnostic[];
363
+ }
364
+
365
+ function parsePreferencesMarkdownWithDiagnostics(content: string): PreferenceParseResult {
289
366
  // Use indexOf instead of [\s\S]*? regex to avoid backtracking (#468)
290
367
  const startMarker = content.startsWith('---\r\n') ? '---\r\n' : '---\n';
291
368
  if (content.startsWith(startMarker)) {
292
369
  const searchStart = startMarker.length;
293
370
  const endIdx = content.indexOf('\n---', searchStart);
294
- if (endIdx === -1) return null;
371
+ if (endIdx === -1) {
372
+ return {
373
+ preferences: null,
374
+ diagnostics: [{
375
+ severity: "error",
376
+ kind: "parse",
377
+ message: "preferences frontmatter is missing a closing --- delimiter",
378
+ ignored: true,
379
+ }],
380
+ };
381
+ }
295
382
  const block = content.slice(searchStart, endIdx);
296
- return parseFrontmatterBlock(block.replace(/\r/g, ''));
383
+ return parseFrontmatterBlockWithDiagnostics(block.replace(/\r/g, ''), 1);
297
384
  }
298
385
 
299
386
  // Fallback: heading+list format (e.g. "## Git\n- isolation: none") (#2036)
300
387
  // GSD agents may write preferences files without frontmatter delimiters.
301
388
  if (/^##\s+\w/m.test(content)) {
302
- return parseHeadingListFormat(content);
389
+ return {
390
+ preferences: parseHeadingListFormat(content),
391
+ diagnostics: [],
392
+ };
303
393
  }
304
394
 
305
395
  // Warn when a non-empty file exists but lacks frontmatter delimiters (#2036).
@@ -310,27 +400,82 @@ export function parsePreferencesMarkdown(content: string): GSDPreferences | null
310
400
  "Wrap your preferences in --- fences. See https://github.com/open-gsd/gsd-pi/issues/2036",
311
401
  );
312
402
  }
313
- return null;
403
+ return {
404
+ preferences: null,
405
+ diagnostics: content.trim().length > 0
406
+ ? [{
407
+ severity: "error",
408
+ kind: "parse",
409
+ message: "preferences file has unrecognized format; expected YAML frontmatter delimiters (---) or markdown preference sections",
410
+ ignored: true,
411
+ }]
412
+ : [],
413
+ };
314
414
  }
315
415
 
316
416
  let _warnedFrontmatterParse = false;
317
- function parseFrontmatterBlock(frontmatter: string): GSDPreferences {
417
+ function parseFrontmatterBlockWithDiagnostics(
418
+ frontmatter: string,
419
+ lineOffset: number,
420
+ ): { preferences: GSDPreferences; diagnostics: PreferenceParseDiagnostic[] } {
318
421
  try {
319
422
  const parsed = parseYaml(frontmatter);
320
423
  if (typeof parsed !== 'object' || parsed === null) {
321
- return {} as GSDPreferences;
424
+ return {
425
+ preferences: {} as GSDPreferences,
426
+ diagnostics: [{
427
+ severity: "error",
428
+ kind: "validation",
429
+ message: "preferences frontmatter must be a YAML object",
430
+ ignored: true,
431
+ }],
432
+ };
322
433
  }
323
- return normalizeParsedPreferences(parsed as GSDPreferences);
434
+ return {
435
+ preferences: normalizeParsedPreferences(parsed as GSDPreferences),
436
+ diagnostics: [],
437
+ };
324
438
  } catch (e) {
325
439
  // Warn at most once per session to avoid flooding TUI (#3376)
326
440
  if (!_warnedFrontmatterParse) {
327
441
  _warnedFrontmatterParse = true;
328
442
  logWarning("guided", `YAML parse error in preferences frontmatter (suppressing further): ${(e as Error).message}`);
329
443
  }
330
- return {} as GSDPreferences;
444
+ const location = extractYamlErrorLocation(e, lineOffset);
445
+ return {
446
+ preferences: {} as GSDPreferences,
447
+ diagnostics: [{
448
+ severity: "error",
449
+ kind: "parse",
450
+ message: cleanYamlErrorMessage(e),
451
+ ...(location.line !== undefined ? { line: location.line } : {}),
452
+ ...(location.column !== undefined ? { column: location.column } : {}),
453
+ ignored: true,
454
+ }],
455
+ };
331
456
  }
332
457
  }
333
458
 
459
+ function cleanYamlErrorMessage(error: unknown): string {
460
+ const message = error instanceof Error ? error.message : String(error);
461
+ const firstLine = message.split("\n")[0]?.trim() ?? "unknown YAML parse error";
462
+ return firstLine.replace(/\s+at line \d+, column \d+:?$/, "");
463
+ }
464
+
465
+ function extractYamlErrorLocation(
466
+ error: unknown,
467
+ lineOffset: number,
468
+ ): { line?: number; column?: number } {
469
+ const linePos = (error as { linePos?: Array<{ line?: unknown; col?: unknown }> })?.linePos;
470
+ const first = Array.isArray(linePos) ? linePos[0] : undefined;
471
+ const line = typeof first?.line === "number" ? first.line + lineOffset : undefined;
472
+ const column = typeof first?.col === "number" ? first.col : undefined;
473
+ return {
474
+ ...(line !== undefined ? { line } : {}),
475
+ ...(column !== undefined ? { column } : {}),
476
+ };
477
+ }
478
+
334
479
  function normalizeParsedPreferences(preferences: GSDPreferences): GSDPreferences {
335
480
  const remoteQuestions = preferences.remote_questions;
336
481
  if (remoteQuestions && typeof remoteQuestions === "object" && typeof remoteQuestions.channel_id === "number") {
@@ -37,6 +37,7 @@ Use `subagent` only when useful: reviewer, security, or tester. Apply findings b
37
37
  9. If requirement status changed, call `gsd_requirement_update`; do not write `.gsd/REQUIREMENTS.md` directly.
38
38
  10. Prepare `gsd_slice_complete` content with camelCase fields `milestoneId`, `sliceId`, `sliceTitle`, `oneLiner`, `narrative`, `verification`, and `uatContent`.
39
39
  11. Draft concrete UAT with preconditions, steps, expected outcomes, edge cases, and UAT Type.
40
+ **Web apps:** when inlined Web App UAT guidance is present, declare `browser-executable` or `runtime-executable` (not `artifact-driven`) for localhost/browser/screenshot steps; include dev-server preconditions and name Playwright specs when they exist.
40
41
  12. Review the inlined task-summary excerpts for DECISIONS.md/KNOWLEDGE.md-worthy decisions and gotchas. Read full `*-SUMMARY.md` only if needed. Capture with `capture_thought`; do not append knowledge files.
41
42
  13. When verification passes, call `gsd_slice_complete`. The DB-backed tool is the canonical write path. Do **not** manually write `{{sliceSummaryPath}}`. Do **not** manually write `{{sliceUatPath}}`. Do not edit roadmap checkboxes.
42
43
  14. Do not run git commands.
@@ -32,6 +32,8 @@ You execute. The inlined task plan is authoritative. Verify referenced files and
32
32
  - Prior task summaries:
33
33
  {{priorTaskLines}}
34
34
 
35
+ {{onDemandContext}}
36
+
35
37
  ## Execution Rules
36
38
 
37
39
  1. Tersely narrate transitions, decisions, and verification outcomes between tool-call clusters.
@@ -36,6 +36,8 @@ After the opening answer, classify project shape as **`simple`** or **`complex`*
36
36
 
37
37
  Persist the verdict through `gsd_summary_save` with `artifact_type: "PROJECT"` into `## Project Shape`; downstream `discuss-requirements`, `discuss-milestone`, and `discuss-slice` read the rendered projection.
38
38
 
39
+ When the project is browser-facing (web app, SPA, static site with UI, Next/React/Vue, etc.), also record **`Web stack:`** under `## Project Shape` (framework + whether Playwright or browser UAT is expected). Downstream planning uses this to choose `browser-executable` / `runtime-executable` UAT instead of deferring UI proof to humans.
40
+
39
41
  ### Before deeper rounds
40
42
 
41
43
  Ground your questions in the **Preparation Context snapshot above** (stack, structure, greenfield/brownfield and framework signals) plus any prior `.planning/` or `.gsd/` artifacts — those are authoritative. **Do not survey the codebase** with `rg`/`find`/`scout` before asking; read a specific file only when a question's answer genuinely hinges on it.
@@ -103,7 +105,7 @@ Once the user confirms depth:
103
105
 
104
106
  1. Use the **Project** output template (inlined above).
105
107
  2. Call `gsd_summary_save` with `artifact_type: "PROJECT"` and full project markdown as `content`; omit `milestone_id`. The tool persists the DB-backed PROJECT artifact and renders `.gsd/PROJECT.md`. Preserve the user's terms and framing.
106
- 3. The `## Project Shape` section MUST contain `**Complexity:** simple` or `**Complexity:** complex` (matching the verdict you announced) plus a one-line `**Why:**` rationale. Downstream stages read this line.
108
+ 3. The `## Project Shape` section MUST contain `**Complexity:** simple` or `**Complexity:** complex` (matching the verdict you announced) plus a one-line `**Why:**` rationale. For browser-facing projects, also include `**Web stack:**` (framework and expected browser/Playwright UAT approach). Downstream stages read these lines.
107
109
  4. The `## Capability Contract` section MUST reference `.gsd/REQUIREMENTS.md` — that file does not yet exist; the next stage (`discuss-requirements`) will produce it.
108
110
  5. The `## Milestone Sequence` MUST list at least M001 with title and one-liner. Subsequent milestones may be listed as known intents; they will be elaborated in their own discuss-milestone stages.
109
111
  6. Do NOT use `artifact_type: "CONTEXT"` and do NOT pass `milestone_id: "PROJECT"`; that creates a fake milestone named PROJECT.
@@ -47,6 +47,8 @@ If milestone research is inlined, trust it and skip redundant exploration. If fi
47
47
 
48
48
  Narrate decomposition reasoning in complete sentences: grouping, risk order, verification strategy.
49
49
 
50
+ **Web apps:** when inlined Web App UAT guidance is present, set milestone `Verification Classes` → UAT to browser-observable acceptance (Playwright spec or `browser_*` checks). Order an early slice to add Playwright smoke scaffolding when the dependency is missing.
51
+
50
52
  Then:
51
53
  1. Use the **Roadmap** output template from the inlined context above
52
54
  2. {{skillActivation}}
@@ -41,6 +41,7 @@ If slice research is inlined, trust its architectural findings, but verify every
41
41
  3. Use the inlined Output Template sections already present in this prompt. Do not read template files from disk.
42
42
  4. {{skillActivation}} Record expected executor skills in each task plan's `skills_used` frontmatter.
43
43
  5. Define slice verification before tasks. Non-trivial slices need real tests or executable assertions; boundary contracts need contract-exercising checks. Tests must not read .gitignore/gitignored paths such as `.gsd/`, `.planning/`, or `.audits/`.
44
+ **Web apps:** when inlined Web App UAT guidance is present, follow it — add Playwright smoke scaffolding on the first UI slice if missing, name localhost preconditions, and plan verification commands that match browser-capable UAT modes at slice closeout.
44
45
  6. Include Threat Surface (Q3), Requirement Impact (Q4), proof level, observability, integration closure, Failure Modes (Q5), Load Profile (Q6), and Negative Tests (Q7) only where applicable.
45
46
  7. Right-size tasks. Simple slices can be one task; split only when context, ownership, or verification boundaries justify it.
46
47
  8. Task `verify` commands must be safe, simple commands. Do not use shell pipes, redirects, semicolons, backticks, command substitution, output trimming, or grep regex alternation with `|`. If multiple checks are needed, create a small test file and run it with `node --test` or a package test script, or use separate simple commands joined only with `&&`. For absence checks, verify a pattern does not exist with `! grep -q 'pattern' file` or `! rg -q 'pattern' file`; do not use `grep -c` or `rg -c` to assert zero matches because count commands exit 1 when they find zero matches, and the verification gate treats that as failure.
@@ -63,6 +63,7 @@ Then:
63
63
  - `{{taskPlanTemplatePath}}`
64
64
  2. {{skillActivation}} Record the installed skills you expect executors to use in each task plan's `skills_used` frontmatter.
65
65
  3. Define slice-level verification: the objective stopping condition. Plan real test files with real assertions; for simple slices, executable commands are fine.
66
+ **Web apps:** when inlined Web App UAT guidance is present, follow it for Playwright scaffolding and browser-capable verification commands.
66
67
  4. For non-trivial slices, plan observability / proof level / integration closure, threat surface, and requirement impact. Omit entirely for simple slices.
67
68
  5. Decompose the slice into tasks that fit one context window each. Every task passed to `gsd_plan_slice` must use the exact keys `taskId`, `title`, `description`, `estimate`, `files`, `verify`, `inputs`, `expectedOutput`, and optional `observabilityImpact`. Put Why / Do / Done-when detail in `description`. `files`, `inputs`, and `expectedOutput` must be JSON arrays of strings, even for one path (for example, `"expectedOutput": ["src/index.ts"]`, never `"expectedOutput": "src/index.ts"`). `expectedOutput` is path-only: list only files the task creates or overwrites, and use `[]` for pure verification tasks.
68
69
  6. **Persist planning state through `gsd_plan_slice`.** Call it with the full payload. The tool writes to the DB and renders `{{outputPath}}` and `{{slicePath}}/tasks/T##-PLAN.md` automatically. Do NOT rely on direct `PLAN.md` writes.
@@ -158,7 +158,7 @@ Fix root causes, not symptoms. If applying temporary mitigation, label it and pr
158
158
  - State uncertainty plainly: "Not sure this handles X - testing it." No performed confidence, no hedging paragraphs.
159
159
  - All user-visible narration must be grammatical English. Do not emit compressed planner notes like "Need inspect X". If it fits a commit comment or standup note, it is acceptable.
160
160
  - When debugging, stay curious. Problems are puzzles. Say what's interesting about the failure before reaching for fixes.
161
- - After completing a task, give a brief summary and 2-4 numbered next-step options; last option is always "Other". Omit the list for strict output formats.
161
+ - After completing a task, give a brief summary and 2-4 numbered next-step options; last option is always "Other". Omit the list for strict output formats, or when the active workflow prompt already ends with its own explicit "Next steps:" handoff block — in that case follow the workflow's handoff and do not add a second list.
162
162
 
163
163
  If any next step is destructive/outward-facing, present it via `ask_user_questions` and wait for the user's answer before execution. Do not execute a next-step item from a prior plain-text numbered list without fresh confirmation.
164
164
 
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Provider Payload Policy - ordered shaping of provider request payloads.
3
+ *
4
+ * The order is intentional:
5
+ * 1. observation budgeting masks old tool results in auto-mode,
6
+ * 2. display truncation caps tool-result text for every mode,
7
+ * 3. the protected Source Context Block is appended after truncation,
8
+ * 4. supported models receive the configured service tier.
9
+ */
10
+
11
+ import type { ContextManagementConfig } from "./preferences-types.js";
12
+ import type { ServiceTierSetting } from "./service-tier.js";
13
+
14
+ import {
15
+ createObservationMask,
16
+ createResponsesInputObservationMask,
17
+ truncateContextResultMessages,
18
+ truncateResponsesInputResultItems,
19
+ } from "./context-masker.js";
20
+ import { getSourceObservationStore, isAutoActive } from "./auto-runtime-state.js";
21
+ import { loadEffectiveGSDPreferences } from "./preferences.js";
22
+ import { getEffectiveServiceTier, supportsServiceTier } from "./service-tier.js";
23
+ import { injectSourceContextBlockIntoPayload } from "./source-observations.js";
24
+
25
+ const DEFAULT_OBSERVATION_MASK_TURNS = 8;
26
+ const DEFAULT_TOOL_RESULT_MAX_CHARS = 800;
27
+
28
+ type MessagePayload = Parameters<ReturnType<typeof createObservationMask>>[0];
29
+ type ResponsesInputPayload = Parameters<ReturnType<typeof createResponsesInputObservationMask>>[0];
30
+
31
+ export interface ProviderPayloadPolicyDeps {
32
+ isAutoActive(): boolean;
33
+ loadContextManagementConfig(): ContextManagementConfig | undefined;
34
+ renderSourceContextBlock(): string | null;
35
+ getEffectiveServiceTier(): ServiceTierSetting;
36
+ supportsServiceTier(modelId: string): boolean;
37
+ }
38
+
39
+ export interface ProviderPayloadPolicyInput {
40
+ payload: Record<string, unknown>;
41
+ modelId?: string;
42
+ deps?: Partial<ProviderPayloadPolicyDeps>;
43
+ }
44
+
45
+ export const DEFAULT_PROVIDER_PAYLOAD_POLICY_DEPS: ProviderPayloadPolicyDeps = {
46
+ isAutoActive,
47
+ loadContextManagementConfig: () => loadEffectiveGSDPreferences()?.preferences.context_management,
48
+ renderSourceContextBlock: () => getSourceObservationStore().renderActiveBlock(),
49
+ getEffectiveServiceTier,
50
+ supportsServiceTier,
51
+ };
52
+
53
+ export function applyProviderPayloadPolicy({
54
+ payload,
55
+ modelId,
56
+ deps: overrides,
57
+ }: ProviderPayloadPolicyInput): Record<string, unknown> {
58
+ const deps = { ...DEFAULT_PROVIDER_PAYLOAD_POLICY_DEPS, ...overrides };
59
+
60
+ try {
61
+ applyContextManagement(payload, deps);
62
+ } catch {
63
+ // Provider payload shaping should not block a request when optional
64
+ // context management preferences or adapters fail.
65
+ }
66
+
67
+ try {
68
+ applySourceContextBlock(payload, deps);
69
+ } catch {
70
+ // Source observations are opportunistic; execution can continue without
71
+ // an injected block.
72
+ }
73
+
74
+ applyServiceTier(payload, modelId, deps);
75
+ return payload;
76
+ }
77
+
78
+ function applyContextManagement(
79
+ payload: Record<string, unknown>,
80
+ deps: ProviderPayloadPolicyDeps,
81
+ ): void {
82
+ const config = deps.loadContextManagementConfig();
83
+ applyObservationBudget(payload, config, deps.isAutoActive());
84
+ applyDisplayTruncation(payload, config);
85
+ }
86
+
87
+ function applyObservationBudget(
88
+ payload: Record<string, unknown>,
89
+ config: ContextManagementConfig | undefined,
90
+ autoActive: boolean,
91
+ ): void {
92
+ if (!autoActive || config?.observation_masking === false) return;
93
+
94
+ const keepTurns = config?.observation_mask_turns ?? DEFAULT_OBSERVATION_MASK_TURNS;
95
+ if (Array.isArray(payload.messages)) {
96
+ payload.messages = createObservationMask(keepTurns)(payload.messages as MessagePayload);
97
+ }
98
+ if (Array.isArray(payload.input)) {
99
+ payload.input = createResponsesInputObservationMask(keepTurns)(payload.input as ResponsesInputPayload);
100
+ }
101
+ }
102
+
103
+ function applyDisplayTruncation(
104
+ payload: Record<string, unknown>,
105
+ config: ContextManagementConfig | undefined,
106
+ ): void {
107
+ const maxChars = config?.tool_result_max_chars ?? DEFAULT_TOOL_RESULT_MAX_CHARS;
108
+
109
+ if (Array.isArray(payload.messages)) {
110
+ payload.messages = truncateContextResultMessages(payload.messages as MessagePayload, maxChars);
111
+ }
112
+ if (Array.isArray(payload.input)) {
113
+ payload.input = truncateResponsesInputResultItems(payload.input as ResponsesInputPayload, maxChars);
114
+ }
115
+ }
116
+
117
+ function applySourceContextBlock(
118
+ payload: Record<string, unknown>,
119
+ deps: ProviderPayloadPolicyDeps,
120
+ ): void {
121
+ if (!deps.isAutoActive()) return;
122
+
123
+ const sourceContextBlock = deps.renderSourceContextBlock();
124
+ if (!sourceContextBlock) return;
125
+
126
+ Object.assign(payload, injectSourceContextBlockIntoPayload(payload, sourceContextBlock));
127
+ }
128
+
129
+ function applyServiceTier(
130
+ payload: Record<string, unknown>,
131
+ modelId: string | undefined,
132
+ deps: ProviderPayloadPolicyDeps,
133
+ ): void {
134
+ if (!modelId) return;
135
+
136
+ const tier = deps.getEffectiveServiceTier();
137
+ if (!tier || !deps.supportsServiceTier(modelId)) return;
138
+
139
+ payload.service_tier = tier;
140
+ }