@opengsd/gsd-pi 1.1.1-dev.74e8dd1 → 1.1.1-dev.75048e7

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 (329) hide show
  1. package/dist/cli.js +3 -2
  2. package/dist/help-text.js +10 -6
  3. package/dist/resources/.managed-resources-content-hash +1 -1
  4. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +495 -0
  5. package/dist/resources/extensions/browser-tools/engine/selection.js +16 -0
  6. package/dist/resources/extensions/browser-tools/extension-manifest.json +2 -2
  7. package/dist/resources/extensions/browser-tools/index.js +57 -9
  8. package/dist/resources/extensions/browser-tools/package.json +5 -1
  9. package/dist/resources/extensions/gsd/auto/orchestrator.js +0 -1
  10. package/dist/resources/extensions/gsd/auto-dashboard.js +77 -13
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +16 -0
  12. package/dist/resources/extensions/gsd/auto-post-unit.js +21 -3
  13. package/dist/resources/extensions/gsd/auto-prompts.js +63 -22
  14. package/dist/resources/extensions/gsd/auto-recovery.js +3 -4
  15. package/dist/resources/extensions/gsd/auto-runtime-state.js +3 -0
  16. package/dist/resources/extensions/gsd/auto-tool-tracking.js +1 -1
  17. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +18 -66
  18. package/dist/resources/extensions/gsd/auto-worktree.js +18 -5
  19. package/dist/resources/extensions/gsd/auto.js +9 -2
  20. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +20 -14
  21. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +28 -13
  22. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +18 -29
  23. package/dist/resources/extensions/gsd/browser-evidence.js +29 -2
  24. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +61 -0
  25. package/dist/resources/extensions/gsd/commands/handlers/ops.js +2 -2
  26. package/dist/resources/extensions/gsd/commands-handlers.js +76 -11
  27. package/dist/resources/extensions/gsd/commands-mcp-status.js +2 -1
  28. package/dist/resources/extensions/gsd/dashboard-overlay.js +21 -7
  29. package/dist/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  30. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +2 -2
  31. package/dist/resources/extensions/gsd/escalation.js +4 -4
  32. package/dist/resources/extensions/gsd/forensics.js +74 -2
  33. package/dist/resources/extensions/gsd/gsd-db.js +5 -2
  34. package/dist/resources/extensions/gsd/guided-flow.js +118 -175
  35. package/dist/resources/extensions/gsd/mcp-project-config.js +9 -76
  36. package/dist/resources/extensions/gsd/memory-store.js +4 -1
  37. package/dist/resources/extensions/gsd/milestone-closeout.js +3 -1
  38. package/dist/resources/extensions/gsd/pending-auto-start.js +0 -1
  39. package/dist/resources/extensions/gsd/post-unit-hooks.js +9 -0
  40. package/dist/resources/extensions/gsd/preferences-validation.js +39 -0
  41. package/dist/resources/extensions/gsd/prompt-loader.js +7 -0
  42. package/dist/resources/extensions/gsd/prompts/forensics.md +61 -1
  43. package/dist/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  44. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  45. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  46. package/dist/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  47. package/dist/resources/extensions/gsd/prompts/run-uat.md +25 -21
  48. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  49. package/dist/resources/extensions/gsd/recovery-classification.js +20 -0
  50. package/dist/resources/extensions/gsd/rule-registry.js +428 -52
  51. package/dist/resources/extensions/gsd/state.js +2 -2
  52. package/dist/resources/extensions/gsd/templates/plan.md +3 -1
  53. package/dist/resources/extensions/gsd/tool-contract.js +5 -0
  54. package/dist/resources/extensions/gsd/tool-presentation-plan.js +30 -7
  55. package/dist/resources/extensions/gsd/tools/complete-slice.js +15 -1
  56. package/dist/resources/extensions/gsd/tools/complete-task.js +11 -1
  57. package/dist/resources/extensions/gsd/tools/validate-milestone.js +46 -16
  58. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +132 -18
  59. package/dist/resources/extensions/gsd/unit-tool-contracts.js +169 -0
  60. package/dist/resources/extensions/gsd/verdict-parser.js +59 -15
  61. package/dist/resources/extensions/gsd/verification-gate.js +72 -1
  62. package/dist/resources/extensions/gsd/workflow-mcp.js +3 -75
  63. package/dist/resources/extensions/shared/gsd-browser-cli.js +145 -0
  64. package/dist/rtk.d.ts +7 -1
  65. package/dist/rtk.js +27 -11
  66. package/dist/update-check.d.ts +15 -1
  67. package/dist/update-check.js +87 -12
  68. package/dist/update-cmd.d.ts +1 -0
  69. package/dist/update-cmd.js +53 -2
  70. package/dist/web/standalone/.next/BUILD_ID +1 -1
  71. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  72. package/dist/web/standalone/.next/build-manifest.json +2 -2
  73. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  74. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  75. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  81. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  82. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  83. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  84. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  85. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  86. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  87. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  88. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  89. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  90. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/index.html +1 -1
  92. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  93. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  94. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  95. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  96. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  97. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  98. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  99. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  100. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  102. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  103. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  104. package/package.json +4 -2
  105. package/packages/cloud-mcp-gateway/package.json +2 -2
  106. package/packages/contracts/package.json +1 -1
  107. package/packages/daemon/package.json +4 -4
  108. package/packages/gsd-agent-core/dist/agent-session.d.ts +9 -0
  109. package/packages/gsd-agent-core/dist/agent-session.d.ts.map +1 -1
  110. package/packages/gsd-agent-core/dist/agent-session.js +32 -0
  111. package/packages/gsd-agent-core/dist/agent-session.js.map +1 -1
  112. package/packages/gsd-agent-core/dist/index.d.ts +1 -0
  113. package/packages/gsd-agent-core/dist/index.d.ts.map +1 -1
  114. package/packages/gsd-agent-core/dist/index.js +1 -0
  115. package/packages/gsd-agent-core/dist/index.js.map +1 -1
  116. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts +2 -0
  117. package/packages/gsd-agent-core/dist/session/agent-session-compaction.d.ts.map +1 -1
  118. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js +8 -2
  119. package/packages/gsd-agent-core/dist/session/agent-session-compaction.js.map +1 -1
  120. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts +7 -0
  121. package/packages/gsd-agent-core/dist/session/agent-session-host.d.ts.map +1 -1
  122. package/packages/gsd-agent-core/dist/session/agent-session-host.js.map +1 -1
  123. package/packages/gsd-agent-core/dist/session/agent-session-prompt.d.ts.map +1 -1
  124. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js +69 -1
  125. package/packages/gsd-agent-core/dist/session/agent-session-prompt.js.map +1 -1
  126. package/packages/gsd-agent-core/dist/turn-latency.d.ts +47 -0
  127. package/packages/gsd-agent-core/dist/turn-latency.d.ts.map +1 -0
  128. package/packages/gsd-agent-core/dist/turn-latency.js +123 -0
  129. package/packages/gsd-agent-core/dist/turn-latency.js.map +1 -0
  130. package/packages/gsd-agent-core/package.json +6 -6
  131. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +21 -0
  132. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +1 -0
  133. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +213 -0
  134. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +1 -0
  135. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  136. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
  137. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  138. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  139. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +20 -0
  140. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  141. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  142. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +7 -1
  143. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  144. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.d.ts.map +1 -1
  145. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js +6 -0
  146. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-command-handlers.js.map +1 -1
  147. package/packages/gsd-agent-modes/package.json +7 -7
  148. package/packages/mcp-server/dist/remote-questions.d.ts.map +1 -1
  149. package/packages/mcp-server/dist/remote-questions.js +23 -9
  150. package/packages/mcp-server/dist/remote-questions.js.map +1 -1
  151. package/packages/mcp-server/dist/workflow-tools.js +2 -2
  152. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  153. package/packages/mcp-server/package.json +3 -3
  154. package/packages/native/package.json +1 -1
  155. package/packages/pi-agent-core/dist/agent-loop.js +42 -3
  156. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  157. package/packages/pi-agent-core/dist/agent.d.ts +5 -1
  158. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  159. package/packages/pi-agent-core/dist/agent.js +2 -0
  160. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  161. package/packages/pi-agent-core/dist/harness/agent-harness.d.ts.map +1 -1
  162. package/packages/pi-agent-core/dist/harness/agent-harness.js +3 -1
  163. package/packages/pi-agent-core/dist/harness/agent-harness.js.map +1 -1
  164. package/packages/pi-agent-core/dist/harness/types.d.ts +1 -0
  165. package/packages/pi-agent-core/dist/harness/types.d.ts.map +1 -1
  166. package/packages/pi-agent-core/dist/harness/types.js.map +1 -1
  167. package/packages/pi-agent-core/dist/types.d.ts +6 -1
  168. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  169. package/packages/pi-agent-core/dist/types.js.map +1 -1
  170. package/packages/pi-agent-core/package.json +1 -1
  171. package/packages/pi-ai/dist/api-registry.d.ts +2 -0
  172. package/packages/pi-ai/dist/api-registry.d.ts.map +1 -1
  173. package/packages/pi-ai/dist/api-registry.js +23 -0
  174. package/packages/pi-ai/dist/api-registry.js.map +1 -1
  175. package/packages/pi-ai/dist/models.generated.d.ts +74 -23
  176. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  177. package/packages/pi-ai/dist/models.generated.js +82 -31
  178. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  179. package/packages/pi-ai/dist/stream.js +6 -6
  180. package/packages/pi-ai/dist/stream.js.map +1 -1
  181. package/packages/pi-ai/package.json +1 -1
  182. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts +3 -0
  183. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.d.ts.map +1 -1
  184. package/packages/pi-coding-agent/dist/core/extensions/extension-upstream-types.js.map +1 -1
  185. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  186. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -2
  187. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  188. package/packages/pi-coding-agent/dist/core/tools/bash.js +2 -2
  189. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  190. package/packages/pi-coding-agent/dist/core/tools/edit.d.ts.map +1 -1
  191. package/packages/pi-coding-agent/dist/core/tools/edit.js +3 -2
  192. package/packages/pi-coding-agent/dist/core/tools/edit.js.map +1 -1
  193. package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts +1 -0
  194. package/packages/pi-coding-agent/dist/core/tools/render-utils.d.ts.map +1 -1
  195. package/packages/pi-coding-agent/dist/core/tools/render-utils.js +6 -0
  196. package/packages/pi-coding-agent/dist/core/tools/render-utils.js.map +1 -1
  197. package/packages/pi-coding-agent/dist/core/tools/write.d.ts.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/tools/write.js +3 -2
  199. package/packages/pi-coding-agent/dist/core/tools/write.js.map +1 -1
  200. package/packages/pi-coding-agent/package.json +7 -7
  201. package/packages/pi-tui/package.json +1 -1
  202. package/packages/rpc-client/package.json +2 -2
  203. package/pkg/package.json +1 -1
  204. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +579 -0
  205. package/src/resources/extensions/browser-tools/engine/selection.ts +19 -0
  206. package/src/resources/extensions/browser-tools/extension-manifest.json +2 -2
  207. package/src/resources/extensions/browser-tools/index.ts +60 -9
  208. package/src/resources/extensions/browser-tools/package.json +5 -1
  209. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +35 -0
  210. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +33 -0
  211. package/src/resources/extensions/gsd/auto/orchestrator.ts +0 -1
  212. package/src/resources/extensions/gsd/auto-dashboard.ts +82 -14
  213. package/src/resources/extensions/gsd/auto-dispatch.ts +19 -0
  214. package/src/resources/extensions/gsd/auto-post-unit.ts +28 -2
  215. package/src/resources/extensions/gsd/auto-prompts.ts +97 -15
  216. package/src/resources/extensions/gsd/auto-recovery.ts +3 -3
  217. package/src/resources/extensions/gsd/auto-runtime-state.ts +4 -0
  218. package/src/resources/extensions/gsd/auto-tool-tracking.ts +1 -1
  219. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +43 -74
  220. package/src/resources/extensions/gsd/auto-worktree.ts +23 -5
  221. package/src/resources/extensions/gsd/auto.ts +12 -2
  222. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +20 -14
  223. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +32 -13
  224. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +50 -54
  225. package/src/resources/extensions/gsd/browser-evidence.ts +26 -2
  226. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +137 -0
  227. package/src/resources/extensions/gsd/commands/handlers/ops.ts +2 -2
  228. package/src/resources/extensions/gsd/commands-handlers.ts +76 -11
  229. package/src/resources/extensions/gsd/commands-mcp-status.ts +2 -1
  230. package/src/resources/extensions/gsd/dashboard-overlay.ts +28 -7
  231. package/src/resources/extensions/gsd/docs/preferences-reference.md +8 -0
  232. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +2 -2
  233. package/src/resources/extensions/gsd/escalation.ts +4 -4
  234. package/src/resources/extensions/gsd/forensics.ts +99 -5
  235. package/src/resources/extensions/gsd/gsd-db.ts +5 -2
  236. package/src/resources/extensions/gsd/guided-flow.ts +214 -216
  237. package/src/resources/extensions/gsd/mcp-project-config.ts +13 -78
  238. package/src/resources/extensions/gsd/memory-store.ts +4 -1
  239. package/src/resources/extensions/gsd/milestone-closeout.ts +3 -1
  240. package/src/resources/extensions/gsd/pending-auto-start.ts +0 -2
  241. package/src/resources/extensions/gsd/post-unit-hooks.ts +14 -1
  242. package/src/resources/extensions/gsd/preferences-validation.ts +36 -0
  243. package/src/resources/extensions/gsd/prompt-loader.ts +8 -0
  244. package/src/resources/extensions/gsd/prompts/forensics.md +61 -1
  245. package/src/resources/extensions/gsd/prompts/gate-evaluate.md +3 -1
  246. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +3 -1
  247. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  248. package/src/resources/extensions/gsd/prompts/reactive-execute.md +3 -1
  249. package/src/resources/extensions/gsd/prompts/run-uat.md +25 -21
  250. package/src/resources/extensions/gsd/prompts/validate-milestone.md +3 -3
  251. package/src/resources/extensions/gsd/recovery-classification.ts +20 -0
  252. package/src/resources/extensions/gsd/rule-registry.ts +558 -58
  253. package/src/resources/extensions/gsd/rule-types.ts +2 -0
  254. package/src/resources/extensions/gsd/state.ts +2 -2
  255. package/src/resources/extensions/gsd/templates/plan.md +3 -1
  256. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +105 -4
  257. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +37 -0
  258. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +10 -2
  259. package/src/resources/extensions/gsd/tests/auto-start-bootstrap-await-3420.test.ts +4 -1
  260. package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +12 -2
  261. package/src/resources/extensions/gsd/tests/browser-evidence.test.ts +142 -0
  262. package/src/resources/extensions/gsd/tests/check-auto-start-pending-gate.test.ts +9 -15
  263. package/src/resources/extensions/gsd/tests/check-auto-start-ready-guard.test.ts +26 -16
  264. package/src/resources/extensions/gsd/tests/commands-dispatcher-unmerged-milestone.test.ts +21 -0
  265. package/src/resources/extensions/gsd/tests/complete-milestone-excerpt.test.ts +30 -0
  266. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  267. package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +45 -0
  268. package/src/resources/extensions/gsd/tests/deep-planning-mode-dispatch.test.ts +53 -0
  269. package/src/resources/extensions/gsd/tests/discuss-milestone-structured-questions.test.ts +31 -0
  270. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +40 -1
  271. package/src/resources/extensions/gsd/tests/doctor-runtime-checks.test.ts +27 -0
  272. package/src/resources/extensions/gsd/tests/escalation.test.ts +16 -27
  273. package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +20 -0
  274. package/src/resources/extensions/gsd/tests/forensics-prompt-rendering.test.ts +3 -0
  275. package/src/resources/extensions/gsd/tests/forensics-tool-scope.test.ts +69 -0
  276. package/src/resources/extensions/gsd/tests/gate-1b-orphan-discrimination.test.ts +31 -79
  277. package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +40 -1
  278. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +86 -0
  279. package/src/resources/extensions/gsd/tests/guided-flow-session-isolation.test.ts +5 -3
  280. package/src/resources/extensions/gsd/tests/guided-flow-state-rebuild.test.ts +40 -4
  281. package/src/resources/extensions/gsd/tests/guided-flow.test.ts +12 -9
  282. package/src/resources/extensions/gsd/tests/integration/auto-recovery.test.ts +4 -4
  283. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +8 -0
  284. package/src/resources/extensions/gsd/tests/integration/parallel-merge.test.ts +16 -0
  285. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +72 -10
  286. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +32 -0
  287. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +2 -0
  288. package/src/resources/extensions/gsd/tests/memory-maintenance.test.ts +39 -8
  289. package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +63 -0
  290. package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +10 -1
  291. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +9 -1
  292. package/src/resources/extensions/gsd/tests/new-milestone-discuss-routing.test.ts +3 -3
  293. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +9 -0
  294. package/src/resources/extensions/gsd/tests/post-unit-hooks.test.ts +157 -0
  295. package/src/resources/extensions/gsd/tests/post-unit-retry-on-orchestrator-bridge.test.ts +179 -0
  296. package/src/resources/extensions/gsd/tests/preferences.test.ts +29 -0
  297. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +73 -1
  298. package/src/resources/extensions/gsd/tests/prompt-loader-extension-dir.test.ts +14 -0
  299. package/src/resources/extensions/gsd/tests/queued-discuss-fast-path.test.ts +7 -8
  300. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +44 -0
  301. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +75 -0
  302. package/src/resources/extensions/gsd/tests/run-uat-composer.test.ts +4 -0
  303. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +36 -0
  304. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +100 -0
  305. package/src/resources/extensions/gsd/tests/state-reconciliation-drift.test.ts +139 -0
  306. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -4
  307. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +19 -0
  308. package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +7 -1
  309. package/src/resources/extensions/gsd/tests/validate-milestone-prompt-verification-classes.test.ts +6 -3
  310. package/src/resources/extensions/gsd/tests/validate-milestone-write-order.test.ts +133 -0
  311. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +51 -0
  312. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +410 -0
  313. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -0
  314. package/src/resources/extensions/gsd/tool-contract.ts +6 -0
  315. package/src/resources/extensions/gsd/tool-presentation-plan.ts +63 -7
  316. package/src/resources/extensions/gsd/tools/complete-slice.ts +14 -1
  317. package/src/resources/extensions/gsd/tools/complete-task.ts +20 -2
  318. package/src/resources/extensions/gsd/tools/validate-milestone.ts +46 -15
  319. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +163 -20
  320. package/src/resources/extensions/gsd/types.ts +69 -5
  321. package/src/resources/extensions/gsd/unit-tool-contracts.ts +186 -0
  322. package/src/resources/extensions/gsd/verdict-parser.ts +54 -13
  323. package/src/resources/extensions/gsd/verification-gate.ts +87 -1
  324. package/src/resources/extensions/gsd/workflow-mcp.ts +3 -75
  325. package/src/resources/extensions/shared/gsd-browser-cli.ts +172 -0
  326. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound-corrections.test.ts +0 -246
  327. package/src/resources/extensions/gsd/tests/gate-1b-recovery-bound.test.ts +0 -218
  328. /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → h4TGni4xJzlZjGkxaT6uU}/_buildManifest.js +0 -0
  329. /package/dist/web/standalone/.next/static/{eRWf-RI9bzbrwEurm_3uI → h4TGni4xJzlZjGkxaT6uU}/_ssgManifest.js +0 -0
@@ -0,0 +1,186 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Central Unit-to-tool contracts for phase-aware GSD tool surfaces.
3
+
4
+ export interface UnitToolSurfaceContract {
5
+ allowedGsdTools: readonly string[];
6
+ requiredWorkflowTools: readonly string[];
7
+ forbiddenGsdTools?: Readonly<Record<string, string>>;
8
+ }
9
+
10
+ export const RUN_UAT_WORKFLOW_TOOL_NAMES = [
11
+ "gsd_uat_exec",
12
+ "gsd_uat_result_save",
13
+ "gsd_resume",
14
+ "gsd_milestone_status",
15
+ "gsd_journal_query",
16
+ ] as const;
17
+
18
+ export const RUN_UAT_READ_ONLY_TOOL_NAMES = [
19
+ "find",
20
+ "glob",
21
+ "grep",
22
+ "ls",
23
+ "read",
24
+ ] as const;
25
+
26
+ export const RUN_UAT_BROWSER_TOOL_NAMES = [
27
+ "browser_navigate",
28
+ "browser_click",
29
+ "browser_type",
30
+ "browser_fill_form",
31
+ "browser_click_ref",
32
+ "browser_fill_ref",
33
+ "browser_wait_for",
34
+ "browser_assert",
35
+ "browser_verify",
36
+ "browser_screenshot",
37
+ "browser_snapshot_refs",
38
+ "browser_find",
39
+ "browser_get_console_logs",
40
+ "browser_get_network_logs",
41
+ "browser_evaluate",
42
+ "browser_reload",
43
+ "browser_batch",
44
+ "browser_act",
45
+ ] as const;
46
+
47
+ export const RUN_UAT_TOOL_PRESENTATION_PLAN_ID = "run-uat/default-v1";
48
+
49
+ export const UNIT_TOOL_CONTRACTS: Record<string, UnitToolSurfaceContract> = {
50
+ "research-milestone": {
51
+ allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
52
+ requiredWorkflowTools: ["gsd_summary_save"],
53
+ },
54
+ "plan-milestone": {
55
+ allowedGsdTools: ["gsd_plan_milestone", "gsd_decision_save", "gsd_requirement_update"],
56
+ requiredWorkflowTools: ["gsd_plan_milestone"],
57
+ },
58
+ "discuss-milestone": {
59
+ allowedGsdTools: [
60
+ "gsd_summary_save",
61
+ "gsd_decision_save",
62
+ "gsd_requirement_save",
63
+ "gsd_requirement_update",
64
+ "gsd_plan_milestone",
65
+ "gsd_milestone_generate_id",
66
+ ],
67
+ requiredWorkflowTools: [
68
+ "gsd_summary_save",
69
+ "gsd_requirement_save",
70
+ "gsd_requirement_update",
71
+ "gsd_plan_milestone",
72
+ "gsd_milestone_generate_id",
73
+ ],
74
+ },
75
+ "discuss-slice": {
76
+ allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
77
+ requiredWorkflowTools: ["gsd_summary_save"],
78
+ },
79
+ "validate-milestone": {
80
+ allowedGsdTools: ["gsd_validate_milestone", "gsd_reassess_roadmap", "subagent"],
81
+ requiredWorkflowTools: ["gsd_milestone_status", "gsd_validate_milestone", "gsd_reassess_roadmap"],
82
+ },
83
+ "complete-milestone": {
84
+ allowedGsdTools: ["gsd_complete_milestone", "subagent"],
85
+ requiredWorkflowTools: ["gsd_milestone_status", "gsd_complete_milestone"],
86
+ },
87
+ "research-slice": {
88
+ allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
89
+ requiredWorkflowTools: ["gsd_summary_save"],
90
+ },
91
+ "plan-slice": {
92
+ allowedGsdTools: ["gsd_plan_slice", "gsd_plan_task", "gsd_decision_save"],
93
+ requiredWorkflowTools: ["gsd_plan_slice"],
94
+ },
95
+ "refine-slice": {
96
+ allowedGsdTools: ["gsd_plan_slice", "gsd_plan_task", "gsd_decision_save"],
97
+ requiredWorkflowTools: [],
98
+ },
99
+ "replan-slice": {
100
+ allowedGsdTools: ["gsd_replan_slice", "gsd_plan_task", "gsd_decision_save"],
101
+ requiredWorkflowTools: ["gsd_replan_slice"],
102
+ },
103
+ "complete-slice": {
104
+ allowedGsdTools: [
105
+ "gsd_slice_complete",
106
+ "gsd_task_reopen",
107
+ "gsd_replan_slice",
108
+ "gsd_decision_save",
109
+ "gsd_requirement_update",
110
+ "subagent",
111
+ ],
112
+ requiredWorkflowTools: ["gsd_slice_complete", "gsd_task_reopen", "gsd_replan_slice"],
113
+ forbiddenGsdTools: {
114
+ gsd_uat_result_save: "Run UAT owns persisted UAT Assessment.",
115
+ },
116
+ },
117
+ "reassess-roadmap": {
118
+ allowedGsdTools: ["gsd_reassess_roadmap"],
119
+ requiredWorkflowTools: ["gsd_milestone_status", "gsd_reassess_roadmap"],
120
+ },
121
+ "execute-task": {
122
+ allowedGsdTools: ["gsd_task_complete", "gsd_decision_save"],
123
+ requiredWorkflowTools: ["gsd_task_complete"],
124
+ },
125
+ "execute-task-simple": {
126
+ allowedGsdTools: ["gsd_task_complete", "gsd_decision_save"],
127
+ requiredWorkflowTools: ["gsd_task_complete"],
128
+ },
129
+ "reactive-execute": {
130
+ allowedGsdTools: ["gsd_task_complete", "gsd_decision_save"],
131
+ requiredWorkflowTools: ["gsd_task_complete"],
132
+ },
133
+ "run-uat": {
134
+ allowedGsdTools: [...RUN_UAT_WORKFLOW_TOOL_NAMES, "subagent"],
135
+ requiredWorkflowTools: [...RUN_UAT_WORKFLOW_TOOL_NAMES],
136
+ forbiddenGsdTools: {
137
+ gsd_exec: "Use gsd_uat_exec so acceptance evidence is typed as UAT-owned.",
138
+ gsd_save_gate_result: "gsd_uat_result_save owns the aggregate UAT gate.",
139
+ gsd_summary_save: "gsd_uat_result_save owns persisted UAT Assessment writes.",
140
+ },
141
+ },
142
+ "gate-evaluate": {
143
+ allowedGsdTools: ["gsd_save_gate_result"],
144
+ requiredWorkflowTools: ["gsd_save_gate_result"],
145
+ },
146
+ "rewrite-docs": {
147
+ allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
148
+ requiredWorkflowTools: [],
149
+ },
150
+ "workflow-preferences": {
151
+ allowedGsdTools: ["gsd_summary_save"],
152
+ requiredWorkflowTools: [],
153
+ },
154
+ "discuss-project": {
155
+ allowedGsdTools: ["gsd_summary_save", "gsd_decision_save", "gsd_requirement_save"],
156
+ requiredWorkflowTools: ["ask_user_questions", "gsd_summary_save"],
157
+ },
158
+ "discuss-requirements": {
159
+ allowedGsdTools: ["gsd_requirement_save", "gsd_summary_save"],
160
+ requiredWorkflowTools: ["ask_user_questions", "gsd_requirement_save", "gsd_summary_save"],
161
+ },
162
+ "research-decision": {
163
+ allowedGsdTools: ["gsd_summary_save"],
164
+ requiredWorkflowTools: ["ask_user_questions"],
165
+ },
166
+ "research-project": {
167
+ allowedGsdTools: ["gsd_summary_save", "gsd_decision_save"],
168
+ requiredWorkflowTools: [],
169
+ },
170
+ };
171
+
172
+ export const AUTO_UNIT_SCOPED_TOOLS: Record<string, readonly string[]> = Object.fromEntries(
173
+ Object.entries(UNIT_TOOL_CONTRACTS).map(([unitType, contract]) => [unitType, contract.allowedGsdTools]),
174
+ );
175
+
176
+ export function getUnitToolSurfaceContract(unitType: string): UnitToolSurfaceContract | undefined {
177
+ return UNIT_TOOL_CONTRACTS[unitType];
178
+ }
179
+
180
+ export function getRequiredWorkflowToolsForUnit(unitType: string): string[] {
181
+ return [...(UNIT_TOOL_CONTRACTS[unitType]?.requiredWorkflowTools ?? [])];
182
+ }
183
+
184
+ export function getForbiddenGsdToolReason(unitType: string, toolName: string): string | undefined {
185
+ return UNIT_TOOL_CONTRACTS[unitType]?.forbiddenGsdTools?.[toolName];
186
+ }
@@ -7,9 +7,60 @@
7
7
 
8
8
  import { extractUatType } from "./files.js";
9
9
  import type { UatType } from "./files.js";
10
+ import { splitFrontmatter, parseFrontmatterMap } from "../shared/frontmatter.js";
11
+ import { parse as parseYaml } from "yaml";
12
+
13
+ function normalizeVerdict(value: unknown): string | undefined {
14
+ if (typeof value !== "string") return undefined;
15
+ let verdict = value.trim().toLowerCase();
16
+ if (!verdict) return undefined;
17
+ if (verdict === "passed") verdict = "pass";
18
+ return verdict;
19
+ }
20
+
21
+ function getCaseInsensitive(obj: Record<string, unknown>, key: string): unknown {
22
+ const lowerKey = key.toLowerCase();
23
+ for (const [candidate, value] of Object.entries(obj)) {
24
+ if (candidate.toLowerCase() === lowerKey) return value;
25
+ }
26
+ return undefined;
27
+ }
10
28
 
11
29
  // ── Verdict extraction ──────────────────────────────────────────────────
12
30
 
31
+ /**
32
+ * Extract and normalize the frontmatter `verdict` value.
33
+ *
34
+ * Supports both top-level `verdict` and the hook outcome shape
35
+ * `outcome.verdict`. Returns `undefined` when frontmatter is absent or has no
36
+ * verdict field.
37
+ */
38
+ export function extractFrontmatterVerdict(content: string): string | undefined {
39
+ const [frontmatterLines] = splitFrontmatter(content);
40
+ if (!frontmatterLines) return undefined;
41
+
42
+ try {
43
+ const parsed = parseYaml(frontmatterLines.join("\n")) as unknown;
44
+ if (parsed && typeof parsed === "object") {
45
+ const root = parsed as Record<string, unknown>;
46
+ const topLevel = normalizeVerdict(getCaseInsensitive(root, "verdict"));
47
+ if (topLevel) return topLevel;
48
+ const outcome = getCaseInsensitive(root, "outcome");
49
+ if (outcome && typeof outcome === "object") {
50
+ const nested = normalizeVerdict(getCaseInsensitive(outcome as Record<string, unknown>, "verdict"));
51
+ if (nested) return nested;
52
+ }
53
+ }
54
+ } catch {
55
+ // Fall through to the permissive parser used by legacy frontmatter paths.
56
+ }
57
+
58
+ const frontmatter = parseFrontmatterMap(frontmatterLines);
59
+ const topLevel = normalizeVerdict(getCaseInsensitive(frontmatter, "verdict"));
60
+ if (topLevel) return topLevel;
61
+ return undefined;
62
+ }
63
+
13
64
  /**
14
65
  * Extract and normalize the `verdict` value from YAML frontmatter.
15
66
  *
@@ -21,24 +72,14 @@ import type { UatType } from "./files.js";
21
72
  */
22
73
  export function extractVerdict(content: string): string | undefined {
23
74
  // Primary: YAML frontmatter verdict (canonical format)
24
- const fmMatch = content.match(/^---\n([\s\S]*?)\n---/);
25
- if (fmMatch) {
26
- const verdictMatch = fmMatch[1].match(/verdict:\s*([\w-]+)/i);
27
- if (verdictMatch) {
28
- let v = verdictMatch[1].toLowerCase();
29
- if (v === "passed") v = "pass";
30
- return v;
31
- }
32
- return undefined;
33
- }
75
+ const [frontmatterLines] = splitFrontmatter(content);
76
+ if (frontmatterLines) return extractFrontmatterVerdict(content);
34
77
 
35
78
  // Fallback: detect verdict in markdown body (LLM manual writes, #2960).
36
79
  // Matches patterns like: **Verdict:** PASS, **Verdict:** ✅ PASS, **Verdict** needs-remediation
37
80
  const bodyMatch = content.match(/\*\*Verdict:?\*\*\s*(?:✅\s*)?(\w[\w-]*)/i);
38
81
  if (bodyMatch) {
39
- let v = bodyMatch[1].toLowerCase();
40
- if (v === "passed") v = "pass";
41
- return v;
82
+ return normalizeVerdict(bodyMatch[1]);
42
83
  }
43
84
 
44
85
  return undefined;
@@ -295,6 +295,90 @@ function hasUnsafeShellSyntax(cmd: string): boolean {
295
295
  return false;
296
296
  }
297
297
 
298
+ function splitLeadingShellWords(cmd: string): string[] {
299
+ const words: string[] = [];
300
+ let current = "";
301
+ let inSingle = false;
302
+ let inDouble = false;
303
+ let escaped = false;
304
+
305
+ for (let i = 0; i < cmd.length; i += 1) {
306
+ const ch = cmd[i];
307
+
308
+ if (escaped) {
309
+ current += ch;
310
+ escaped = false;
311
+ continue;
312
+ }
313
+
314
+ if (ch === "\\" && !inSingle) {
315
+ escaped = true;
316
+ continue;
317
+ }
318
+
319
+ if (ch === "'" && !inDouble) {
320
+ inSingle = !inSingle;
321
+ continue;
322
+ }
323
+
324
+ if (ch === "\"" && !inSingle) {
325
+ inDouble = !inDouble;
326
+ continue;
327
+ }
328
+
329
+ if (!inSingle && !inDouble) {
330
+ if (/\s/.test(ch)) {
331
+ if (current) {
332
+ words.push(current);
333
+ current = "";
334
+ }
335
+ continue;
336
+ }
337
+
338
+ if ([";", "|", "&", "<", ">"].includes(ch)) {
339
+ break;
340
+ }
341
+ }
342
+
343
+ current += ch;
344
+ }
345
+
346
+ if (current) {
347
+ words.push(current);
348
+ }
349
+
350
+ return words;
351
+ }
352
+
353
+ function isCountFlag(token: string): boolean {
354
+ return (
355
+ token === "--count" ||
356
+ token.startsWith("--count=") ||
357
+ token === "--count-matches" ||
358
+ token.startsWith("--count-matches=") ||
359
+ /^-[A-Za-z]*c[A-Za-z]*$/.test(token)
360
+ );
361
+ }
362
+
363
+ function countSearchWarning(command: string, exitCode: number): string | null {
364
+ if (exitCode !== 1) return null;
365
+
366
+ const trimmed = command.trim();
367
+ if (trimmed.startsWith("!")) return null;
368
+
369
+ const [tool, ...args] = splitLeadingShellWords(trimmed);
370
+ if (tool !== "grep" && tool !== "rg") return null;
371
+ if (!args.some(isCountFlag)) return null;
372
+
373
+ return `verification-gate: warning: '${tool} -c' returns exit 1 when count=0; for absence checks use '! ${tool} -q ...' instead.`;
374
+ }
375
+
376
+ function appendStderrWarning(stderr: string, warning: string | null): string {
377
+ if (!warning) return stderr;
378
+ const trimmed = stderr.trimEnd();
379
+ return trimmed ? `${trimmed}\n${warning}` : warning;
380
+ }
381
+
298
382
  /**
299
383
  * Known executable first-tokens that are safe to run.
300
384
  * Lowercase commands, common build/test tools, and npm/yarn/pnpm invocations.
@@ -486,11 +570,13 @@ export function runVerificationGate(options: RunVerificationGateOptions): Verifi
486
570
  stderr = truncate(result.stderr, MAX_OUTPUT_BYTES);
487
571
  }
488
572
 
573
+ const warning = countSearchWarning(command, exitCode);
574
+
489
575
  checks.push({
490
576
  command,
491
577
  exitCode,
492
578
  stdout: truncate(result.stdout, MAX_OUTPUT_BYTES),
493
- stderr,
579
+ stderr: truncate(appendStderrWarning(stderr, warning), MAX_OUTPUT_BYTES),
494
580
  durationMs,
495
581
  });
496
582
  }
@@ -2,7 +2,7 @@ import { execSync } from "node:child_process";
2
2
  import { existsSync, realpathSync } from "node:fs";
3
3
  import { dirname, resolve, sep } from "node:path";
4
4
  import { fileURLToPath, pathToFileURL } from "node:url";
5
- import { RUN_UAT_WORKFLOW_TOOL_NAMES } from "./tool-presentation-plan.js";
5
+ import { getRequiredWorkflowToolsForUnit } from "./unit-tool-contracts.js";
6
6
 
7
7
  type WorkflowExecutorsModule = typeof import("./tools/workflow-tool-executors.js");
8
8
 
@@ -414,83 +414,11 @@ export function buildWorkflowMcpServers(
414
414
  }
415
415
 
416
416
  export function getRequiredWorkflowToolsForGuidedUnit(unitType: string): string[] {
417
- switch (unitType) {
418
- case "discuss-project":
419
- return ["ask_user_questions", "gsd_summary_save"];
420
- case "discuss-requirements":
421
- return ["ask_user_questions", "gsd_requirement_save", "gsd_summary_save"];
422
- case "research-decision":
423
- return ["ask_user_questions"];
424
- case "discuss-milestone":
425
- return [
426
- "gsd_summary_save",
427
- "gsd_requirement_save",
428
- "gsd_requirement_update",
429
- "gsd_plan_milestone",
430
- "gsd_milestone_generate_id",
431
- ];
432
- case "discuss-slice":
433
- return ["gsd_summary_save"];
434
- case "research-milestone":
435
- case "research-slice":
436
- return ["gsd_summary_save"];
437
- case "plan-milestone":
438
- return ["gsd_plan_milestone"];
439
- case "plan-slice":
440
- return ["gsd_plan_slice"];
441
- case "execute-task":
442
- return ["gsd_task_complete"];
443
- case "complete-slice":
444
- return ["gsd_slice_complete", "gsd_task_reopen", "gsd_replan_slice"];
445
- default:
446
- return [];
447
- }
417
+ return getRequiredWorkflowToolsForUnit(unitType);
448
418
  }
449
419
 
450
420
  export function getRequiredWorkflowToolsForAutoUnit(unitType: string): string[] {
451
- switch (unitType) {
452
- case "discuss-project":
453
- return ["ask_user_questions", "gsd_summary_save"];
454
- case "discuss-requirements":
455
- return ["ask_user_questions", "gsd_requirement_save", "gsd_summary_save"];
456
- case "research-decision":
457
- return ["ask_user_questions"];
458
- case "discuss-milestone":
459
- return [
460
- "gsd_summary_save",
461
- "gsd_requirement_save",
462
- "gsd_requirement_update",
463
- "gsd_plan_milestone",
464
- "gsd_milestone_generate_id",
465
- ];
466
- case "research-milestone":
467
- case "research-slice":
468
- return ["gsd_summary_save"];
469
- case "run-uat":
470
- return [...RUN_UAT_WORKFLOW_TOOL_NAMES];
471
- case "plan-milestone":
472
- return ["gsd_plan_milestone"];
473
- case "plan-slice":
474
- return ["gsd_plan_slice"];
475
- case "execute-task":
476
- case "execute-task-simple":
477
- case "reactive-execute":
478
- return ["gsd_task_complete"];
479
- case "complete-slice":
480
- return ["gsd_slice_complete", "gsd_task_reopen", "gsd_replan_slice"];
481
- case "replan-slice":
482
- return ["gsd_replan_slice"];
483
- case "reassess-roadmap":
484
- return ["gsd_milestone_status", "gsd_reassess_roadmap"];
485
- case "gate-evaluate":
486
- return ["gsd_save_gate_result"];
487
- case "validate-milestone":
488
- return ["gsd_milestone_status", "gsd_validate_milestone", "gsd_reassess_roadmap"];
489
- case "complete-milestone":
490
- return ["gsd_milestone_status", "gsd_complete_milestone"];
491
- default:
492
- return [];
493
- }
421
+ return getRequiredWorkflowToolsForUnit(unitType);
494
422
  }
495
423
 
496
424
  export function usesWorkflowMcpTransport(
@@ -0,0 +1,172 @@
1
+ import { createHash } from "node:crypto";
2
+ import { execFileSync } from "node:child_process";
3
+ import { existsSync, readFileSync } from "node:fs";
4
+ import { createRequire } from "node:module";
5
+ import { basename, resolve } from "node:path";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ export const GSD_BROWSER_MCP_SERVER_NAME = "gsd-browser";
9
+
10
+ export interface GsdBrowserMcpLaunchConfig {
11
+ serverName: string;
12
+ command: string;
13
+ args: string[];
14
+ cwd: string;
15
+ env?: Record<string, string>;
16
+ projectRoot: string;
17
+ sessionName: string;
18
+ }
19
+
20
+ export interface GsdBrowserMcpLaunchOptions {
21
+ sessionName?: string;
22
+ sessionSuffix?: string;
23
+ }
24
+
25
+ function parseJsonEnv<T>(env: NodeJS.ProcessEnv, name: string): T | undefined {
26
+ const raw = env[name];
27
+ if (!raw) return undefined;
28
+ try {
29
+ return JSON.parse(raw) as T;
30
+ } catch {
31
+ throw new Error(`Invalid JSON in ${name}`);
32
+ }
33
+ }
34
+
35
+ function sanitizeSessionSegment(value: string): string {
36
+ return value
37
+ .replace(/[^a-zA-Z0-9._-]+/g, "-")
38
+ .replace(/^-+|-+$/g, "")
39
+ .slice(0, 40);
40
+ }
41
+
42
+ function compareSemverLocal(a: string, b: string): number {
43
+ const left = a.split(".").map(Number);
44
+ const right = b.split(".").map(Number);
45
+ for (let index = 0; index < Math.max(left.length, right.length); index++) {
46
+ const leftValue = left[index] || 0;
47
+ const rightValue = right[index] || 0;
48
+ if (leftValue > rightValue) return 1;
49
+ if (leftValue < rightValue) return -1;
50
+ }
51
+ return 0;
52
+ }
53
+
54
+ function parseGsdBrowserVersion(output: string): string | null {
55
+ return output.match(/\b(\d+\.\d+\.\d+)\b/)?.[1] ?? null;
56
+ }
57
+
58
+ function resolveBundledGsdBrowserPackageVersion(): string | null {
59
+ try {
60
+ const requireFromHere = createRequire(import.meta.url);
61
+ const packageJsonPath = requireFromHere.resolve("@opengsd/gsd-browser/package.json");
62
+ const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8")) as { version?: unknown };
63
+ return typeof pkg.version === "string" ? parseGsdBrowserVersion(pkg.version) : null;
64
+ } catch {
65
+ return null;
66
+ }
67
+ }
68
+
69
+ function resolvePathGsdBrowserVersion(env: NodeJS.ProcessEnv): string | null {
70
+ const explicit = env.GSD_BROWSER_PATH_VERSION?.trim();
71
+ if (explicit) return parseGsdBrowserVersion(explicit);
72
+
73
+ try {
74
+ return parseGsdBrowserVersion(execFileSync("gsd-browser", ["--version"], {
75
+ encoding: "utf-8",
76
+ env,
77
+ stdio: ["ignore", "pipe", "ignore"],
78
+ timeout: 2000,
79
+ }));
80
+ } catch {
81
+ return null;
82
+ }
83
+ }
84
+
85
+ function shouldPreferPathGsdBrowser(env: NodeJS.ProcessEnv): boolean {
86
+ const pathVersion = resolvePathGsdBrowserVersion(env);
87
+ if (!pathVersion) return false;
88
+
89
+ const bundledVersion = resolveBundledGsdBrowserPackageVersion();
90
+ return !bundledVersion || compareSemverLocal(pathVersion, bundledVersion) > 0;
91
+ }
92
+
93
+ export function resolveBundledGsdBrowserCliPath(env: NodeJS.ProcessEnv = process.env): string | null {
94
+ const explicit = env.GSD_BROWSER_CLI_PATH?.trim() || env.GSD_BROWSER_BIN_PATH?.trim();
95
+ if (explicit) return explicit;
96
+
97
+ try {
98
+ const requireFromHere = createRequire(import.meta.url);
99
+ const packageJsonPath = requireFromHere.resolve("@opengsd/gsd-browser/package.json");
100
+ const candidate = resolve(packageJsonPath, "..", "bin", "gsd-browser");
101
+ if (existsSync(candidate)) return candidate;
102
+ } catch {
103
+ // Fall through to path candidates for source/dist layouts.
104
+ }
105
+
106
+ const candidates = [
107
+ resolve(fileURLToPath(new URL("../../../../node_modules/@opengsd/gsd-browser/bin/gsd-browser", import.meta.url))),
108
+ resolve(fileURLToPath(new URL("../../../../node_modules/.bin/gsd-browser", import.meta.url))),
109
+ ];
110
+
111
+ for (const candidate of candidates) {
112
+ if (existsSync(candidate)) return candidate;
113
+ }
114
+
115
+ return null;
116
+ }
117
+
118
+ export function buildGsdBrowserSessionName(projectRoot: string, suffix?: string): string {
119
+ const resolvedProjectRoot = resolve(projectRoot);
120
+ const base = sanitizeSessionSegment(basename(resolvedProjectRoot)) || "project";
121
+ const hash = createHash("sha1").update(resolvedProjectRoot).digest("hex").slice(0, 8);
122
+ const cleanSuffix = suffix ? sanitizeSessionSegment(suffix) : "";
123
+ return cleanSuffix ? `gsd-${base}-${hash}-${cleanSuffix}` : `gsd-${base}-${hash}`;
124
+ }
125
+
126
+ export function resolveGsdBrowserMcpLaunchConfig(
127
+ projectRoot: string,
128
+ env: NodeJS.ProcessEnv = process.env,
129
+ options: GsdBrowserMcpLaunchOptions = {},
130
+ ): GsdBrowserMcpLaunchConfig {
131
+ const resolvedProjectRoot = resolve(projectRoot);
132
+ const serverName = env.GSD_BROWSER_MCP_NAME?.trim() || GSD_BROWSER_MCP_SERVER_NAME;
133
+ const explicitArgs = parseJsonEnv<unknown>(env, "GSD_BROWSER_MCP_ARGS");
134
+ const explicitEnv = parseJsonEnv<Record<string, string>>(env, "GSD_BROWSER_MCP_ENV");
135
+ const explicitCommand = env.GSD_BROWSER_MCP_COMMAND?.trim();
136
+ const explicitCliPath = env.GSD_BROWSER_CLI_PATH?.trim() || env.GSD_BROWSER_BIN_PATH?.trim();
137
+ const preferPathCli = !explicitCommand && !explicitCliPath && shouldPreferPathGsdBrowser(env);
138
+ const bundledCliPath = !explicitCommand && !explicitCliPath && !preferPathCli
139
+ ? resolveBundledGsdBrowserCliPath(env)
140
+ : null;
141
+ const sessionName =
142
+ options.sessionName?.trim() || buildGsdBrowserSessionName(resolvedProjectRoot, options.sessionSuffix);
143
+ const command =
144
+ explicitCommand
145
+ || explicitCliPath
146
+ || (preferPathCli ? "gsd-browser" : undefined)
147
+ || (bundledCliPath ? process.execPath : undefined)
148
+ || "gsd-browser";
149
+ const args = Array.isArray(explicitArgs) && explicitArgs.length > 0
150
+ ? explicitArgs.map(String)
151
+ : [
152
+ ...(bundledCliPath ? [bundledCliPath] : []),
153
+ "mcp",
154
+ "--session",
155
+ sessionName,
156
+ "--identity-scope",
157
+ "project",
158
+ "--identity-project",
159
+ resolvedProjectRoot,
160
+ ];
161
+ const cwd = env.GSD_BROWSER_MCP_CWD?.trim() || resolvedProjectRoot;
162
+
163
+ return {
164
+ serverName,
165
+ command,
166
+ args,
167
+ cwd,
168
+ ...(explicitEnv ? { env: explicitEnv } : {}),
169
+ projectRoot: resolvedProjectRoot,
170
+ sessionName,
171
+ };
172
+ }