@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,77 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Classify milestone readiness from DB status, slices, and artifacts.
3
+ import { readFileSync } from "node:fs";
4
+ import { getMilestone, getMilestoneSlices, isDbAvailable } from "./gsd-db.js";
5
+ import { parseRoadmapSlices } from "./roadmap-slices.js";
6
+ import { logWarning } from "./workflow-logger.js";
7
+ export function classifyMilestoneReadiness(input) {
8
+ const hasContext = input.hasContext === true;
9
+ const hasDraftContext = !hasContext && input.hasDraftContext === true;
10
+ const hasSummary = input.hasSummary === true;
11
+ const sliceCount = input.sliceCount ?? 0;
12
+ const hasExecutablePlan = sliceCount > 0;
13
+ const status = input.status ?? null;
14
+ if (status === "complete" || hasSummary) {
15
+ return { kind: "terminal", hasContext, hasDraftContext, hasExecutablePlan };
16
+ }
17
+ if (status === "queued" && !hasContext && sliceCount === 0) {
18
+ return { kind: "queued-shell", hasContext, hasDraftContext, hasExecutablePlan };
19
+ }
20
+ if ((status === "needs-discussion" && !hasContext) || hasDraftContext) {
21
+ return { kind: "needs-discussion", hasContext, hasDraftContext, hasExecutablePlan };
22
+ }
23
+ if (hasExecutablePlan) {
24
+ return { kind: "executable-plan", hasContext, hasDraftContext, hasExecutablePlan };
25
+ }
26
+ return { kind: "planning-pending", hasContext, hasDraftContext, hasExecutablePlan };
27
+ }
28
+ export function readinessNeedsDiscussion(readiness) {
29
+ return readiness.kind === "needs-discussion" ||
30
+ (readiness.kind === "queued-shell" && readiness.hasDraftContext);
31
+ }
32
+ export function describeMilestoneReadinessPhase(phase) {
33
+ switch (phase) {
34
+ case "needs-discussion":
35
+ return {
36
+ label: "Discuss milestone draft",
37
+ description: "Milestone has a draft context — needs discussion before planning.",
38
+ };
39
+ case "pre-planning":
40
+ return {
41
+ label: "Research & plan milestone",
42
+ description: "Scout the landscape and create the roadmap.",
43
+ };
44
+ default:
45
+ return null;
46
+ }
47
+ }
48
+ function executablePlanSliceCount(milestoneId, roadmapFile) {
49
+ if (isDbAvailable()) {
50
+ return getMilestoneSlices(milestoneId).length;
51
+ }
52
+ if (!roadmapFile)
53
+ return 0;
54
+ try {
55
+ return parseRoadmapSlices(readFileSync(roadmapFile, "utf-8")).length;
56
+ }
57
+ catch (e) {
58
+ logWarning("guided", `failed to parse roadmap slices for ${milestoneId}: ${e.message}`);
59
+ return 0;
60
+ }
61
+ }
62
+ export function assessMilestoneHandoffReadiness(input) {
63
+ const milestone = isDbAvailable() ? getMilestone(input.milestoneId) : null;
64
+ return classifyMilestoneReadiness({
65
+ status: milestone?.status,
66
+ hasContext: input.contextFile != null,
67
+ sliceCount: executablePlanSliceCount(input.milestoneId, input.roadmapFile),
68
+ });
69
+ }
70
+ export function formatAcceptedDiscussHandoffMessage(milestoneId, readiness) {
71
+ if (readiness.hasExecutablePlan)
72
+ return `Milestone ${milestoneId} ready.`;
73
+ if (readiness.hasContext) {
74
+ return `Milestone ${milestoneId} context captured. Continuing the planning pipeline.`;
75
+ }
76
+ return `Milestone ${milestoneId} planning artifacts captured. Continuing the planning pipeline.`;
77
+ }
@@ -0,0 +1,50 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Milestone closeout settlement state across DB proof, artifacts, merge, and cleanup.
3
+ import { isInAutoWorktree } from "./auto-worktree.js";
4
+ import { formatCloseoutProofBlock, proveMilestoneCloseout, } from "./milestone-closeout-proof.js";
5
+ import { resolveCloseoutArtifactProjection } from "./artifact-projection.js";
6
+ function isActiveUnmergedWorktree(input) {
7
+ if (!input.milestoneId || input.milestoneMerged)
8
+ return false;
9
+ return isInAutoWorktree(input.basePath);
10
+ }
11
+ export function evaluateAllCompleteSettlement(input) {
12
+ if (input.statePhase !== "complete") {
13
+ return { ok: true, reason: "not-applicable" };
14
+ }
15
+ if (!isActiveUnmergedWorktree(input)) {
16
+ return { ok: true, reason: "settled" };
17
+ }
18
+ const milestoneId = input.milestoneId;
19
+ if (!milestoneId) {
20
+ return { ok: true, reason: "settled" };
21
+ }
22
+ const projection = resolveCloseoutArtifactProjection({
23
+ milestoneId,
24
+ basePath: input.basePath,
25
+ originalBasePath: input.originalBasePath,
26
+ });
27
+ const proof = proveMilestoneCloseout(milestoneId, {
28
+ refreshFromDisk: true,
29
+ summaryArtifactBasePath: projection.summaryArtifactBasePath,
30
+ });
31
+ if (!proof.ok) {
32
+ return {
33
+ ok: false,
34
+ reason: "closeout-blocked",
35
+ action: "pause",
36
+ message: `${formatCloseoutProofBlock(proof)} The milestone branch has not been merged to main.`,
37
+ nextAction: `Resolve closeout blockers, then retry \`/gsd dispatch complete-milestone ${milestoneId}\`.`,
38
+ milestoneId,
39
+ };
40
+ }
41
+ return {
42
+ ok: false,
43
+ reason: "merge-pending",
44
+ action: "pause",
45
+ message: `Milestone ${milestoneId} is complete, but its worktree branch has not been merged to main. ` +
46
+ `Retry with \`/gsd dispatch complete-milestone ${milestoneId}\` or merge manually.`,
47
+ nextAction: `Retry \`/gsd dispatch complete-milestone ${milestoneId}\` or merge manually.`,
48
+ milestoneId,
49
+ };
50
+ }
@@ -0,0 +1,73 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Forwarded validation evidence rules for milestone validation.
3
+ import { getArtifact, getMilestone, getMilestoneSlices } from "./gsd-db.js";
4
+ import { loadFile } from "./files.js";
5
+ import { resolveSliceFile } from "./paths.js";
6
+ import { compactTextParts, hasBrowserEvidenceText, hasBrowserRequiredText, } from "./browser-evidence.js";
7
+ export function hasRuntimeExecutableUatEvidenceText(text) {
8
+ if (!/\buatType:\s*runtime-executable\b/i.test(text))
9
+ return false;
10
+ if (!/\bverdict:\s*PASS\b/i.test(text))
11
+ return false;
12
+ return /^\|\s*[^|\n]+\s*\|\s*runtime\s*\|\s*PASS\s*\|[^|\n]*\bgsd_uat_exec\b/mi.test(text);
13
+ }
14
+ export async function browserEvidenceGateRequiresAttention(params, basePath) {
15
+ if (params.verdict !== "pass")
16
+ return false;
17
+ const milestone = getMilestone(params.milestoneId);
18
+ const slices = getMilestoneSlices(params.milestoneId);
19
+ const requirementText = compactTextParts([
20
+ milestone?.vision,
21
+ milestone?.success_criteria,
22
+ milestone?.verification_uat,
23
+ params.successCriteriaChecklist,
24
+ params.verificationClasses,
25
+ ...slices.flatMap((slice) => [
26
+ slice.demo,
27
+ slice.goal,
28
+ slice.success_criteria,
29
+ ]),
30
+ ]);
31
+ if (!hasBrowserRequiredText(requirementText))
32
+ return false;
33
+ const sliceEvidencePairs = [];
34
+ for (const slice of slices) {
35
+ const chunks = [];
36
+ const artifactPath = `milestones/${params.milestoneId}/slices/${slice.id}/${slice.id}-ASSESSMENT.md`;
37
+ const artifact = getArtifact(artifactPath);
38
+ if (artifact?.full_content)
39
+ chunks.push(artifact.full_content);
40
+ const assessmentPath = resolveSliceFile(basePath, params.milestoneId, slice.id, "ASSESSMENT");
41
+ const assessmentContent = assessmentPath ? await loadFile(assessmentPath) : null;
42
+ if (assessmentContent)
43
+ chunks.push(assessmentContent);
44
+ sliceEvidencePairs.push({
45
+ sliceRequirementText: compactTextParts([slice.demo, slice.goal, slice.success_criteria]),
46
+ evidenceText: chunks.join("\n\n"),
47
+ });
48
+ }
49
+ const browserRequiringSlices = sliceEvidencePairs.filter((slice) => hasBrowserRequiredText(slice.sliceRequirementText));
50
+ const runtimeBypasses = browserRequiringSlices.length > 0
51
+ ? browserRequiringSlices.every((slice) => hasRuntimeExecutableUatEvidenceText(slice.evidenceText))
52
+ : sliceEvidencePairs.some((slice) => hasRuntimeExecutableUatEvidenceText(slice.evidenceText));
53
+ if (runtimeBypasses)
54
+ return false;
55
+ const persistedEvidence = sliceEvidencePairs.map((slice) => slice.evidenceText).join("\n\n");
56
+ const validationEvidence = compactTextParts([
57
+ params.successCriteriaChecklist,
58
+ params.verificationClasses,
59
+ params.verdictRationale,
60
+ params.remediationPlan,
61
+ ]);
62
+ return !hasBrowserEvidenceText(`${persistedEvidence}\n\n${validationEvidence}`);
63
+ }
64
+ export function applyBrowserEvidenceGate(params) {
65
+ const note = "Browser evidence gate: Browser-observable acceptance criteria were detected, but no persisted ASSESSMENT or validation evidence recorded browser actions with assertions. Downgraded from pass to needs-attention.";
66
+ return {
67
+ ...params,
68
+ verdict: "needs-attention",
69
+ verdictRationale: params.verdictRationale.trim()
70
+ ? `${params.verdictRationale.trim()}\n\n${note}`
71
+ : note,
72
+ };
73
+ }
@@ -0,0 +1,57 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Resolve the authoritative milestone validation verdict across DB and disk projections.
3
+ import { existsSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { resolveExpectedArtifactPath } from "./auto-artifact-paths.js";
6
+ import { loadFile } from "./files.js";
7
+ import { getLatestAssessmentByScope, isDbAvailable } from "./gsd-db.js";
8
+ import { gsdProjectionRoot } from "./paths.js";
9
+ import { extractVerdict, isValidMilestoneVerdict, } from "./verdict-parser.js";
10
+ import { resolveCanonicalMilestoneRoot } from "./worktree-manager.js";
11
+ import { resolveWorktreeProjectRoot } from "./worktree-root.js";
12
+ function verdictFromContent(content) {
13
+ if (!content)
14
+ return undefined;
15
+ const verdict = extractVerdict(content);
16
+ return verdict && isValidMilestoneVerdict(verdict) ? verdict : undefined;
17
+ }
18
+ function verdictFromDb(milestoneId) {
19
+ if (!isDbAvailable())
20
+ return undefined;
21
+ const assessment = getLatestAssessmentByScope(milestoneId, "milestone-validation");
22
+ const status = typeof assessment?.status === "string" ? assessment.status : undefined;
23
+ return status && isValidMilestoneVerdict(status) ? status : undefined;
24
+ }
25
+ async function verdictFromValidationPath(path) {
26
+ if (!path || !existsSync(path))
27
+ return undefined;
28
+ return verdictFromContent(await loadFile(path));
29
+ }
30
+ /**
31
+ * Resolve the milestone validation verdict using the same authority order as
32
+ * DB-backed state derivation, with filesystem fallbacks that mirror
33
+ * `resolveExpectedArtifactPath` (canonical worktree projection, then project
34
+ * root). Manual `/gsd verdict` overrides persist to the DB first; a stale
35
+ * worktree-local VALIDATION.md must not re-block auto-mode after the override.
36
+ */
37
+ export async function resolveMilestoneValidationVerdict(basePath, milestoneId) {
38
+ const dbVerdict = verdictFromDb(milestoneId);
39
+ if (dbVerdict)
40
+ return dbVerdict;
41
+ const canonicalBase = resolveCanonicalMilestoneRoot(basePath, milestoneId);
42
+ const canonicalPath = resolveExpectedArtifactPath("validate-milestone", milestoneId, canonicalBase);
43
+ const canonicalVerdict = await verdictFromValidationPath(canonicalPath);
44
+ if (canonicalVerdict)
45
+ return canonicalVerdict;
46
+ const projectRoot = resolveWorktreeProjectRoot(basePath);
47
+ if (projectRoot !== canonicalBase) {
48
+ const projectPath = resolveExpectedArtifactPath("validate-milestone", milestoneId, projectRoot);
49
+ const projectVerdict = await verdictFromValidationPath(projectPath);
50
+ if (projectVerdict)
51
+ return projectVerdict;
52
+ }
53
+ // Last resort: direct canonical projection path even when resolveDir helpers
54
+ // have not materialized the milestone directory yet.
55
+ const directPath = join(gsdProjectionRoot(canonicalBase), "milestones", milestoneId, `${milestoneId}-VALIDATION.md`);
56
+ return verdictFromValidationPath(directPath);
57
+ }
@@ -4,11 +4,10 @@
4
4
  * Analyzes which milestones can safely run in parallel by checking
5
5
  * dependency satisfaction and file overlap across slice plans.
6
6
  */
7
- import { existsSync } from "node:fs";
8
7
  import { deriveState } from "./state.js";
9
- import { resolveGsdPathContract } from "./paths.js";
10
8
  import { findMilestoneIds } from "./guided-flow.js";
11
- import { isDbAvailable, getMilestoneSlices, getSliceTasks, openDatabase } from "./gsd-db.js";
9
+ import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
10
+ import { openExistingWorkflowDatabase } from "./db-workspace.js";
12
11
  // ─── File Collection ─────────────────────────────────────────────────────────
13
12
  /**
14
13
  * Collect all `filesLikelyTouched` across every slice plan in a milestone.
@@ -64,9 +63,7 @@ function detectFileOverlaps(fileSets) {
64
63
  */
65
64
  export async function analyzeParallelEligibility(basePath) {
66
65
  if (!isDbAvailable()) {
67
- const { projectDb } = resolveGsdPathContract(basePath);
68
- if (existsSync(projectDb))
69
- openDatabase(projectDb);
66
+ openExistingWorkflowDatabase(basePath);
70
67
  }
71
68
  const milestoneIds = findMilestoneIds(basePath);
72
69
  const state = await deriveState(basePath);
@@ -12,9 +12,10 @@ import { join, dirname } from "node:path";
12
12
  import { fileURLToPath } from "node:url";
13
13
  import { gsdRoot } from "./paths.js";
14
14
  import { createWorktree, worktreePath } from "./worktree-manager.js";
15
- import { autoWorktreeBranch, fastForwardReusedMilestoneBranchIfSafe, runWorktreePostCreateHook, syncGsdStateToWorktree } from "./auto-worktree.js";
15
+ import { autoWorktreeBranch, fastForwardReusedMilestoneBranchIfSafe, runWorktreePostCreateHook, syncGsdStateToWorktreeByScope } from "./auto-worktree.js";
16
16
  import { nativeBranchExists } from "./native-git-bridge.js";
17
17
  import { readIntegrationBranch } from "./git-service.js";
18
+ import { createWorkspace, scopeMilestone } from "./workspace.js";
18
19
  import { resolveParallelConfig } from "./preferences.js";
19
20
  import { writeSessionStatus, readAllSessionStatuses, readSessionStatus, removeSessionStatus, sendSignal, cleanupStaleSessions, } from "./session-status-io.js";
20
21
  import { analyzeParallelEligibility, } from "./parallel-eligibility.js";
@@ -448,7 +449,7 @@ export function _createMilestoneWorktree(basePath, milestoneId) {
448
449
  // Copy .gsd/ planning artifacts (milestones, CONTEXT, ROADMAP, etc.) from the
449
450
  // project root into the worktree. Without this, workers for newly-planned
450
451
  // milestones can't find their roadmap and exit immediately (#2184 Bug 4).
451
- syncGsdStateToWorktree(basePath, info.path);
452
+ syncGsdStateToWorktreeByScope(scopeMilestone(createWorkspace(basePath), milestoneId), scopeMilestone(createWorkspace(info.path), milestoneId));
452
453
  return info.path;
453
454
  }
454
455
  // ─── Worker Spawning ───────────────────────────────────────────────────
@@ -0,0 +1,67 @@
1
+ import { loadGlobalGSDPreferences, loadProjectGSDPreferences, } from "./preferences.js";
2
+ const notifiedPreferenceDiagnostics = new Set();
3
+ export function collectPreferenceDiagnostics(basePath) {
4
+ const diagnostics = [
5
+ ...(loadGlobalGSDPreferences()?.diagnostics ?? []),
6
+ ...(loadProjectGSDPreferences(basePath)?.diagnostics ?? []),
7
+ ];
8
+ const seen = new Set();
9
+ const unique = [];
10
+ for (const diagnostic of diagnostics) {
11
+ const signature = preferenceDiagnosticSignature(diagnostic);
12
+ if (seen.has(signature))
13
+ continue;
14
+ seen.add(signature);
15
+ unique.push(diagnostic);
16
+ }
17
+ return unique;
18
+ }
19
+ export function formatPreferenceDiagnostic(diagnostic) {
20
+ const scope = diagnostic.scope === "global" ? "global" : "project";
21
+ const level = diagnostic.severity === "error" ? "error" : "warning";
22
+ const heading = diagnostic.kind === "parse"
23
+ ? `GSD ${scope} preferences ${level}: ${diagnostic.path} could not be parsed.`
24
+ : `GSD ${scope} preferences ${level}: ${diagnostic.path} contains invalid settings.`;
25
+ const detail = formatPreferenceDiagnosticDetail(diagnostic);
26
+ const impact = diagnostic.ignored
27
+ ? "Preferences from this file were ignored; auto-mode may be using defaults."
28
+ : "Invalid settings were ignored or sanitized; auto-mode may be using defaults for them.";
29
+ return `${heading}\n${detail}\n${impact}\nRun /gsd doctor for details.`;
30
+ }
31
+ export function formatPreferenceDiagnosticDetail(diagnostic) {
32
+ if (diagnostic.line !== undefined && diagnostic.column !== undefined) {
33
+ return `YAML error at line ${diagnostic.line}, column ${diagnostic.column}: ${diagnostic.message}`;
34
+ }
35
+ return diagnostic.message;
36
+ }
37
+ export function notifyPreferenceDiagnostics(ctx, basePath, options) {
38
+ let notified = 0;
39
+ for (const diagnostic of collectPreferenceDiagnostics(basePath)) {
40
+ const signature = preferenceDiagnosticNotificationSignature(diagnostic, options?.surface);
41
+ if (notifiedPreferenceDiagnostics.has(signature))
42
+ continue;
43
+ notifiedPreferenceDiagnostics.add(signature);
44
+ ctx.ui.notify(formatPreferenceDiagnostic(diagnostic), diagnostic.severity === "error" ? "error" : "warning");
45
+ notified++;
46
+ }
47
+ return notified;
48
+ }
49
+ export function _resetPreferenceDiagnosticNotificationsForTests() {
50
+ notifiedPreferenceDiagnostics.clear();
51
+ }
52
+ function preferenceDiagnosticSignature(diagnostic) {
53
+ return [
54
+ diagnostic.path,
55
+ diagnostic.scope,
56
+ diagnostic.severity,
57
+ diagnostic.kind,
58
+ diagnostic.message,
59
+ diagnostic.line ?? "",
60
+ diagnostic.column ?? "",
61
+ diagnostic.ignored === true ? "ignored" : "",
62
+ diagnostic.sanitized === true ? "sanitized" : "",
63
+ ].join("\u0000");
64
+ }
65
+ function preferenceDiagnosticNotificationSignature(diagnostic, surface = "default") {
66
+ return `${surface}\u0000${preferenceDiagnosticSignature(diagnostic)}`;
67
+ }
@@ -98,37 +98,41 @@ export function normalizePreferencesShape(loaded) {
98
98
  }
99
99
  // ─── Loading ────────────────────────────────────────────────────────────────
100
100
  export function loadGlobalGSDPreferences() {
101
- return loadPreferencesFile(globalPreferencesPath(), "global")
102
- ?? loadPreferencesFile(legacyGlobalPreferencesPathLowercase(), "global")
103
- ?? loadPreferencesFile(legacyGlobalPreferencesPath(), "global");
101
+ return loadFirstUsablePreferencesFile([
102
+ globalPreferencesPath(),
103
+ legacyGlobalPreferencesPathLowercase(),
104
+ legacyGlobalPreferencesPath(),
105
+ ], "global");
104
106
  }
105
107
  export function loadProjectGSDPreferences(basePath) {
106
- return loadPreferencesFile(projectPreferencesPath(basePath), "project")
107
- ?? loadPreferencesFile(legacyProjectPreferencesPathLowercase(basePath), "project");
108
+ return loadFirstUsablePreferencesFile([
109
+ projectPreferencesPath(basePath),
110
+ legacyProjectPreferencesPathLowercase(basePath),
111
+ ], "project");
108
112
  }
109
113
  export function loadEffectiveGSDPreferences(basePath, opts) {
110
114
  const globalPreferences = loadGlobalGSDPreferences();
111
115
  const projectPreferences = loadProjectGSDPreferences(basePath);
112
- const projectHasPlanningDepth = projectPreferences?.preferences.planning_depth !== undefined;
113
- if (!globalPreferences && !projectPreferences)
116
+ const effectiveGlobalPreferences = globalPreferences?.ignored ? null : globalPreferences;
117
+ const effectiveProjectPreferences = projectPreferences?.ignored ? null : projectPreferences;
118
+ const projectHasPlanningDepth = effectiveProjectPreferences?.preferences.planning_depth !== undefined;
119
+ if (!effectiveGlobalPreferences && !effectiveProjectPreferences)
114
120
  return null;
115
121
  let result;
116
- if (!globalPreferences) {
117
- result = projectPreferences;
122
+ if (!effectiveGlobalPreferences) {
123
+ result = effectiveProjectPreferences;
118
124
  }
119
- else if (!projectPreferences) {
120
- result = globalPreferences;
125
+ else if (!effectiveProjectPreferences) {
126
+ result = mergePreferenceMetadata(effectiveGlobalPreferences, projectPreferences);
121
127
  }
122
128
  else {
123
- const mergedWarnings = [
124
- ...(globalPreferences.warnings ?? []),
125
- ...(projectPreferences.warnings ?? []),
126
- ];
129
+ const metadata = mergePreferenceMetadata(effectiveGlobalPreferences, effectiveProjectPreferences);
127
130
  result = {
128
- path: projectPreferences.path,
131
+ path: effectiveProjectPreferences.path,
129
132
  scope: "project",
130
- preferences: mergePreferences(globalPreferences.preferences, projectPreferences.preferences),
131
- ...(mergedWarnings.length > 0 ? { warnings: mergedWarnings } : {}),
133
+ preferences: mergePreferences(effectiveGlobalPreferences.preferences, effectiveProjectPreferences.preferences),
134
+ ...(metadata.warnings ? { warnings: metadata.warnings } : {}),
135
+ ...(metadata.diagnostics ? { diagnostics: metadata.diagnostics } : {}),
132
136
  };
133
137
  }
134
138
  // Apply token-profile defaults as the lowest-priority layer so that
@@ -152,6 +156,35 @@ export function loadEffectiveGSDPreferences(basePath, opts) {
152
156
  result = stripInheritedPlanningDepth(result, projectHasPlanningDepth);
153
157
  return result;
154
158
  }
159
+ function mergePreferenceMetadata(primary, secondary) {
160
+ const mergedWarnings = [
161
+ ...(primary.warnings ?? []),
162
+ ...(secondary?.warnings ?? []),
163
+ ];
164
+ const mergedDiagnostics = [
165
+ ...(primary.diagnostics ?? []),
166
+ ...(secondary?.diagnostics ?? []),
167
+ ];
168
+ return {
169
+ ...primary,
170
+ ...(mergedWarnings.length > 0 ? { warnings: mergedWarnings } : {}),
171
+ ...(mergedDiagnostics.length > 0 ? { diagnostics: mergedDiagnostics } : {}),
172
+ };
173
+ }
174
+ function loadFirstUsablePreferencesFile(paths, scope) {
175
+ let ignoredPreferences = null;
176
+ for (const path of paths) {
177
+ const loaded = loadPreferencesFile(path, scope);
178
+ if (!loaded)
179
+ continue;
180
+ if (!loaded.ignored)
181
+ return mergePreferenceMetadata(loaded, ignoredPreferences);
182
+ ignoredPreferences = ignoredPreferences
183
+ ? mergePreferenceMetadata(ignoredPreferences, loaded)
184
+ : loaded;
185
+ }
186
+ return ignoredPreferences;
187
+ }
155
188
  function stripInheritedPlanningDepth(loaded, projectHasPlanningDepth) {
156
189
  if (projectHasPlanningDepth || loaded.preferences.planning_depth === undefined) {
157
190
  return loaded;
@@ -167,16 +200,39 @@ function loadPreferencesFile(path, scope) {
167
200
  if (!existsSync(path))
168
201
  return null;
169
202
  const raw = readFileSync(path, "utf-8");
170
- const preferences = parsePreferencesMarkdown(raw);
171
- if (!preferences)
203
+ const parsed = parsePreferencesMarkdownWithDiagnostics(raw);
204
+ if (!parsed.preferences && parsed.diagnostics.length === 0)
172
205
  return null;
206
+ const ignored = parsed.diagnostics.some((diagnostic) => diagnostic.ignored === true);
207
+ const preferences = parsed.preferences ?? {};
173
208
  const validation = validatePreferences(preferences);
174
209
  const allWarnings = [...validation.warnings, ...validation.errors];
210
+ const diagnostics = [
211
+ ...parsed.diagnostics.map((diagnostic) => ({ ...diagnostic, path, scope })),
212
+ ...validation.errors.map((message) => ({
213
+ path,
214
+ scope,
215
+ severity: "error",
216
+ kind: "validation",
217
+ message,
218
+ sanitized: true,
219
+ })),
220
+ ...validation.warnings.map((message) => ({
221
+ path,
222
+ scope,
223
+ severity: "warning",
224
+ kind: "validation",
225
+ message,
226
+ sanitized: true,
227
+ })),
228
+ ];
175
229
  return {
176
230
  path,
177
231
  scope,
178
232
  preferences: validation.preferences,
233
+ ...(ignored ? { ignored: true } : {}),
179
234
  ...(allWarnings.length > 0 ? { warnings: allWarnings } : {}),
235
+ ...(diagnostics.length > 0 ? { diagnostics } : {}),
180
236
  };
181
237
  }
182
238
  let _warnedUnrecognizedFormat = false;
@@ -189,20 +245,35 @@ export function _resetParseWarningFlag() {
189
245
  }
190
246
  /** @internal Exported for testing only */
191
247
  export function parsePreferencesMarkdown(content) {
248
+ return parsePreferencesMarkdownWithDiagnostics(content).preferences;
249
+ }
250
+ function parsePreferencesMarkdownWithDiagnostics(content) {
192
251
  // Use indexOf instead of [\s\S]*? regex to avoid backtracking (#468)
193
252
  const startMarker = content.startsWith('---\r\n') ? '---\r\n' : '---\n';
194
253
  if (content.startsWith(startMarker)) {
195
254
  const searchStart = startMarker.length;
196
255
  const endIdx = content.indexOf('\n---', searchStart);
197
- if (endIdx === -1)
198
- return null;
256
+ if (endIdx === -1) {
257
+ return {
258
+ preferences: null,
259
+ diagnostics: [{
260
+ severity: "error",
261
+ kind: "parse",
262
+ message: "preferences frontmatter is missing a closing --- delimiter",
263
+ ignored: true,
264
+ }],
265
+ };
266
+ }
199
267
  const block = content.slice(searchStart, endIdx);
200
- return parseFrontmatterBlock(block.replace(/\r/g, ''));
268
+ return parseFrontmatterBlockWithDiagnostics(block.replace(/\r/g, ''), 1);
201
269
  }
202
270
  // Fallback: heading+list format (e.g. "## Git\n- isolation: none") (#2036)
203
271
  // GSD agents may write preferences files without frontmatter delimiters.
204
272
  if (/^##\s+\w/m.test(content)) {
205
- return parseHeadingListFormat(content);
273
+ return {
274
+ preferences: parseHeadingListFormat(content),
275
+ diagnostics: [],
276
+ };
206
277
  }
207
278
  // Warn when a non-empty file exists but lacks frontmatter delimiters (#2036).
208
279
  if (content.trim().length > 0 && !_warnedUnrecognizedFormat) {
@@ -210,16 +281,37 @@ export function parsePreferencesMarkdown(content) {
210
281
  console.warn("[GSD] Warning: preferences file has unrecognized format — content does not use YAML frontmatter delimiters (---). " +
211
282
  "Wrap your preferences in --- fences. See https://github.com/open-gsd/gsd-pi/issues/2036");
212
283
  }
213
- return null;
284
+ return {
285
+ preferences: null,
286
+ diagnostics: content.trim().length > 0
287
+ ? [{
288
+ severity: "error",
289
+ kind: "parse",
290
+ message: "preferences file has unrecognized format; expected YAML frontmatter delimiters (---) or markdown preference sections",
291
+ ignored: true,
292
+ }]
293
+ : [],
294
+ };
214
295
  }
215
296
  let _warnedFrontmatterParse = false;
216
- function parseFrontmatterBlock(frontmatter) {
297
+ function parseFrontmatterBlockWithDiagnostics(frontmatter, lineOffset) {
217
298
  try {
218
299
  const parsed = parseYaml(frontmatter);
219
300
  if (typeof parsed !== 'object' || parsed === null) {
220
- return {};
301
+ return {
302
+ preferences: {},
303
+ diagnostics: [{
304
+ severity: "error",
305
+ kind: "validation",
306
+ message: "preferences frontmatter must be a YAML object",
307
+ ignored: true,
308
+ }],
309
+ };
221
310
  }
222
- return normalizeParsedPreferences(parsed);
311
+ return {
312
+ preferences: normalizeParsedPreferences(parsed),
313
+ diagnostics: [],
314
+ };
223
315
  }
224
316
  catch (e) {
225
317
  // Warn at most once per session to avoid flooding TUI (#3376)
@@ -227,9 +319,35 @@ function parseFrontmatterBlock(frontmatter) {
227
319
  _warnedFrontmatterParse = true;
228
320
  logWarning("guided", `YAML parse error in preferences frontmatter (suppressing further): ${e.message}`);
229
321
  }
230
- return {};
322
+ const location = extractYamlErrorLocation(e, lineOffset);
323
+ return {
324
+ preferences: {},
325
+ diagnostics: [{
326
+ severity: "error",
327
+ kind: "parse",
328
+ message: cleanYamlErrorMessage(e),
329
+ ...(location.line !== undefined ? { line: location.line } : {}),
330
+ ...(location.column !== undefined ? { column: location.column } : {}),
331
+ ignored: true,
332
+ }],
333
+ };
231
334
  }
232
335
  }
336
+ function cleanYamlErrorMessage(error) {
337
+ const message = error instanceof Error ? error.message : String(error);
338
+ const firstLine = message.split("\n")[0]?.trim() ?? "unknown YAML parse error";
339
+ return firstLine.replace(/\s+at line \d+, column \d+:?$/, "");
340
+ }
341
+ function extractYamlErrorLocation(error, lineOffset) {
342
+ const linePos = error?.linePos;
343
+ const first = Array.isArray(linePos) ? linePos[0] : undefined;
344
+ const line = typeof first?.line === "number" ? first.line + lineOffset : undefined;
345
+ const column = typeof first?.col === "number" ? first.col : undefined;
346
+ return {
347
+ ...(line !== undefined ? { line } : {}),
348
+ ...(column !== undefined ? { column } : {}),
349
+ };
350
+ }
233
351
  function normalizeParsedPreferences(preferences) {
234
352
  const remoteQuestions = preferences.remote_questions;
235
353
  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.