gsd-pi 2.68.1 → 2.69.0-dev.232905b

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 (304) hide show
  1. package/dist/resources/extensions/gsd/auto-model-selection.js +27 -1
  2. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +7 -0
  3. package/dist/resources/extensions/gsd/bootstrap/system-context.js +6 -2
  4. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +1 -5
  5. package/dist/resources/extensions/gsd/codebase-generator.js +12 -0
  6. package/dist/resources/extensions/gsd/commands-cmux.js +30 -1
  7. package/dist/resources/extensions/gsd/guided-flow.js +25 -70
  8. package/dist/resources/extensions/gsd/model-router.js +85 -2
  9. package/dist/resources/extensions/gsd/prompts/discuss.md +2 -0
  10. package/dist/resources/extensions/gsd/templates/context.md +34 -2
  11. package/dist/resources/extensions/gsd/workflow-mcp.js +53 -6
  12. package/dist/web/standalone/.next/BUILD_ID +1 -1
  13. package/dist/web/standalone/.next/app-path-routes-manifest.json +9 -9
  14. package/dist/web/standalone/.next/build-manifest.json +3 -3
  15. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  16. package/dist/web/standalone/.next/required-server-files.json +3 -3
  17. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  18. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  19. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  20. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  21. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  22. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  28. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  29. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  30. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  31. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  32. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  33. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  34. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  38. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  39. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  40. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  41. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  42. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  43. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  44. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  45. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  46. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  47. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  48. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  49. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/experimental/route.js +2 -2
  56. package/dist/web/standalone/.next/server/app/api/experimental/route_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/notifications/route.js +2 -2
  76. package/dist/web/standalone/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  84. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +2 -2
  86. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  90. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  92. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  106. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  108. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  110. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +2 -2
  112. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  120. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  121. package/dist/web/standalone/.next/server/app/index.html +1 -1
  122. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  123. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  124. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  125. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  127. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/page.js +2 -2
  129. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  130. package/dist/web/standalone/.next/server/app-paths-manifest.json +9 -9
  131. package/dist/web/standalone/.next/server/chunks/63.js +3 -3
  132. package/dist/web/standalone/.next/server/chunks/6897.js +3 -3
  133. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/middleware.js +2 -2
  135. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  137. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  138. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  139. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  140. package/dist/web/standalone/.next/static/chunks/app/_not-found/{page-2f24283c162b6ab3.js → page-f2a7482d42a5614b.js} +1 -1
  141. package/dist/web/standalone/.next/static/chunks/app/{layout-9ecfd95f343793f0.js → layout-a16c7a7ecdf0c2cf.js} +1 -1
  142. package/dist/web/standalone/.next/static/chunks/app/page-f1e30ab6bb269149.js +1 -0
  143. package/dist/web/standalone/.next/static/chunks/main-app-fdab67f7802d7832.js +1 -0
  144. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  145. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  146. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  147. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  148. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  149. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  150. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  151. package/dist/web/standalone/server.js +1 -1
  152. package/package.json +1 -1
  153. package/packages/daemon/src/orchestrator.ts +9 -84
  154. package/packages/mcp-server/README.md +25 -3
  155. package/packages/mcp-server/dist/cli.d.ts +0 -1
  156. package/packages/mcp-server/dist/cli.d.ts.map +1 -1
  157. package/packages/mcp-server/dist/cli.js +4 -2
  158. package/packages/mcp-server/dist/cli.js.map +1 -1
  159. package/packages/mcp-server/dist/server.d.ts +32 -1
  160. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  161. package/packages/mcp-server/dist/server.js +118 -1
  162. package/packages/mcp-server/dist/server.js.map +1 -1
  163. package/packages/mcp-server/dist/tool-credentials.d.ts +6 -0
  164. package/packages/mcp-server/dist/tool-credentials.d.ts.map +1 -0
  165. package/packages/mcp-server/dist/tool-credentials.js +90 -0
  166. package/packages/mcp-server/dist/tool-credentials.js.map +1 -0
  167. package/packages/mcp-server/dist/workflow-tools.d.ts +1 -0
  168. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  169. package/packages/mcp-server/dist/workflow-tools.js +274 -2
  170. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  171. package/packages/mcp-server/src/cli.ts +5 -3
  172. package/packages/mcp-server/src/mcp-server.test.ts +85 -1
  173. package/packages/mcp-server/src/server.ts +188 -1
  174. package/packages/mcp-server/src/tool-credentials.test.ts +95 -0
  175. package/packages/mcp-server/src/tool-credentials.ts +97 -0
  176. package/packages/mcp-server/src/workflow-tools.test.ts +32 -25
  177. package/packages/mcp-server/src/workflow-tools.ts +365 -2
  178. package/packages/pi-ai/dist/index.d.ts +3 -0
  179. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  180. package/packages/pi-ai/dist/index.js +2 -0
  181. package/packages/pi-ai/dist/index.js.map +1 -1
  182. package/packages/pi-ai/dist/providers/amazon-bedrock.js +2 -2
  183. package/packages/pi-ai/dist/providers/amazon-bedrock.js.map +1 -1
  184. package/packages/pi-ai/dist/providers/anthropic-shared.js +2 -2
  185. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  186. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  187. package/packages/pi-ai/dist/providers/anthropic.js +1 -23
  188. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  189. package/packages/pi-ai/dist/providers/google-shared.js +2 -2
  190. package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
  191. package/packages/pi-ai/dist/providers/mistral.js +2 -2
  192. package/packages/pi-ai/dist/providers/mistral.js.map +1 -1
  193. package/packages/pi-ai/dist/providers/openai-completions.js +2 -2
  194. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  195. package/packages/pi-ai/dist/providers/openai-responses-shared.js +2 -2
  196. package/packages/pi-ai/dist/providers/openai-responses-shared.js.map +1 -1
  197. package/packages/pi-ai/dist/providers/provider-capabilities.d.ts +59 -0
  198. package/packages/pi-ai/dist/providers/provider-capabilities.d.ts.map +1 -0
  199. package/packages/pi-ai/dist/providers/provider-capabilities.js +173 -0
  200. package/packages/pi-ai/dist/providers/provider-capabilities.js.map +1 -0
  201. package/packages/pi-ai/dist/providers/provider-capabilities.test.d.ts +2 -0
  202. package/packages/pi-ai/dist/providers/provider-capabilities.test.d.ts.map +1 -0
  203. package/packages/pi-ai/dist/providers/provider-capabilities.test.js +132 -0
  204. package/packages/pi-ai/dist/providers/provider-capabilities.test.js.map +1 -0
  205. package/packages/pi-ai/dist/providers/transform-messages-report.test.d.ts +2 -0
  206. package/packages/pi-ai/dist/providers/transform-messages-report.test.d.ts.map +1 -0
  207. package/packages/pi-ai/dist/providers/transform-messages-report.test.js +172 -0
  208. package/packages/pi-ai/dist/providers/transform-messages-report.test.js.map +1 -0
  209. package/packages/pi-ai/dist/providers/transform-messages.d.ts +34 -1
  210. package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
  211. package/packages/pi-ai/dist/providers/transform-messages.js +73 -2
  212. package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
  213. package/packages/pi-ai/dist/utils/oauth/index.d.ts +3 -2
  214. package/packages/pi-ai/dist/utils/oauth/index.d.ts.map +1 -1
  215. package/packages/pi-ai/dist/utils/oauth/index.js +3 -5
  216. package/packages/pi-ai/dist/utils/oauth/index.js.map +1 -1
  217. package/packages/pi-ai/src/index.ts +3 -0
  218. package/packages/pi-ai/src/providers/amazon-bedrock.ts +2 -2
  219. package/packages/pi-ai/src/providers/anthropic-shared.ts +2 -2
  220. package/packages/pi-ai/src/providers/anthropic.ts +1 -31
  221. package/packages/pi-ai/src/providers/google-shared.ts +2 -2
  222. package/packages/pi-ai/src/providers/mistral.ts +2 -2
  223. package/packages/pi-ai/src/providers/openai-completions.ts +2 -2
  224. package/packages/pi-ai/src/providers/openai-responses-shared.ts +2 -2
  225. package/packages/pi-ai/src/providers/provider-capabilities.test.ts +174 -0
  226. package/packages/pi-ai/src/providers/provider-capabilities.ts +215 -0
  227. package/packages/pi-ai/src/providers/transform-messages-report.test.ts +189 -0
  228. package/packages/pi-ai/src/providers/transform-messages.ts +94 -1
  229. package/packages/pi-ai/src/utils/oauth/index.ts +3 -5
  230. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  231. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  232. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  233. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  234. package/packages/pi-coding-agent/dist/core/extensions/loader.js +10 -1
  235. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  236. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts +2 -1
  237. package/packages/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
  238. package/packages/pi-coding-agent/dist/core/extensions/runner.js +15 -0
  239. package/packages/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
  240. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +41 -0
  241. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  242. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  243. package/packages/pi-coding-agent/dist/core/tools/index.d.ts +1 -0
  244. package/packages/pi-coding-agent/dist/core/tools/index.d.ts.map +1 -1
  245. package/packages/pi-coding-agent/dist/core/tools/index.js +1 -0
  246. package/packages/pi-coding-agent/dist/core/tools/index.js.map +1 -1
  247. package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.d.ts +27 -0
  248. package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.d.ts.map +1 -0
  249. package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.js +69 -0
  250. package/packages/pi-coding-agent/dist/core/tools/tool-compatibility-registry.js.map +1 -0
  251. package/packages/pi-coding-agent/dist/index.d.ts +2 -2
  252. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  253. package/packages/pi-coding-agent/dist/index.js +3 -1
  254. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  255. package/packages/pi-coding-agent/package.json +1 -1
  256. package/packages/pi-coding-agent/src/core/extensions/index.ts +4 -0
  257. package/packages/pi-coding-agent/src/core/extensions/loader.ts +11 -1
  258. package/packages/pi-coding-agent/src/core/extensions/runner.ts +18 -0
  259. package/packages/pi-coding-agent/src/core/extensions/types.ts +45 -0
  260. package/packages/pi-coding-agent/src/core/tools/index.ts +7 -0
  261. package/packages/pi-coding-agent/src/core/tools/tool-compatibility-registry.ts +83 -0
  262. package/packages/pi-coding-agent/src/index.ts +9 -0
  263. package/pkg/package.json +1 -1
  264. package/src/resources/extensions/gsd/auto-model-selection.ts +36 -4
  265. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +8 -0
  266. package/src/resources/extensions/gsd/bootstrap/system-context.ts +9 -5
  267. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +1 -5
  268. package/src/resources/extensions/gsd/codebase-generator.ts +16 -0
  269. package/src/resources/extensions/gsd/commands-cmux.ts +32 -1
  270. package/src/resources/extensions/gsd/guided-flow.ts +22 -84
  271. package/src/resources/extensions/gsd/model-router.ts +117 -10
  272. package/src/resources/extensions/gsd/preferences-types.ts +3 -1
  273. package/src/resources/extensions/gsd/prompts/discuss.md +2 -0
  274. package/src/resources/extensions/gsd/templates/context.md +34 -2
  275. package/src/resources/extensions/gsd/tests/capability-router.test.ts +31 -7
  276. package/src/resources/extensions/gsd/tests/cmux.test.ts +67 -1
  277. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +28 -0
  278. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +6 -2
  279. package/src/resources/extensions/gsd/tests/model-router.test.ts +2 -2
  280. package/src/resources/extensions/gsd/tests/tool-compatibility.test.ts +199 -0
  281. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +23 -7
  282. package/src/resources/extensions/gsd/tests/write-gate.test.ts +13 -16
  283. package/src/resources/extensions/gsd/workflow-mcp.ts +59 -5
  284. package/dist/resources/extensions/gsd/prompt-validation.js +0 -67
  285. package/dist/resources/extensions/gsd/prompts/discuss-prepared.md +0 -424
  286. package/dist/resources/extensions/gsd/templates/context-enhanced.md +0 -138
  287. package/dist/web/standalone/.next/static/chunks/app/page-7115e62689b5fd84.js +0 -1
  288. package/dist/web/standalone/.next/static/chunks/main-app-d3d4c336195465f9.js +0 -1
  289. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-ab5a8926e07ec673.js +0 -1
  290. package/packages/pi-ai/dist/utils/oauth/anthropic.d.ts +0 -17
  291. package/packages/pi-ai/dist/utils/oauth/anthropic.d.ts.map +0 -1
  292. package/packages/pi-ai/dist/utils/oauth/anthropic.js +0 -106
  293. package/packages/pi-ai/dist/utils/oauth/anthropic.js.map +0 -1
  294. package/packages/pi-ai/src/utils/oauth/anthropic.ts +0 -140
  295. package/src/resources/extensions/gsd/prompt-validation.ts +0 -88
  296. package/src/resources/extensions/gsd/prompts/discuss-prepared.md +0 -424
  297. package/src/resources/extensions/gsd/templates/context-enhanced.md +0 -138
  298. package/src/resources/extensions/gsd/tests/adversarial-review-fixes.test.ts +0 -223
  299. package/src/resources/extensions/gsd/tests/integration/test-isolation.ts +0 -53
  300. package/src/resources/extensions/gsd/tests/integration-prepared-discussion.test.ts +0 -525
  301. package/src/resources/extensions/gsd/tests/preparation.test.ts +0 -1211
  302. package/src/resources/extensions/gsd/tests/prompt-builder.test.ts +0 -669
  303. /package/dist/web/standalone/.next/static/{u9mQsApZYm8sVYSAaft8g → CHeIRZw-E97oO51g7zDvv}/_buildManifest.js +0 -0
  304. /package/dist/web/standalone/.next/static/{u9mQsApZYm8sVYSAaft8g → CHeIRZw-E97oO51g7zDvv}/_ssgManifest.js +0 -0
@@ -0,0 +1,199 @@
1
+ // GSD-2 — Tool Compatibility + Model Router Tool Filtering Tests (ADR-005 Phases 2-3)
2
+ import { describe, test, beforeEach } from "node:test";
3
+ import assert from "node:assert/strict";
4
+
5
+ import {
6
+ registerToolCompatibility,
7
+ getToolCompatibility,
8
+ getAllToolCompatibility,
9
+ registerMcpToolCompatibility,
10
+ resetToolCompatibilityRegistry,
11
+ } from "@gsd/pi-coding-agent";
12
+
13
+ import {
14
+ isToolCompatibleWithProvider,
15
+ filterToolsForProvider,
16
+ adjustToolSet,
17
+ } from "../model-router.js";
18
+
19
+ import {
20
+ getProviderCapabilities,
21
+ } from "@gsd/pi-ai";
22
+
23
+ // ─── Tool Compatibility Registry ────────────────────────────────────────────
24
+
25
+ describe("tool compatibility registry", () => {
26
+ beforeEach(() => {
27
+ resetToolCompatibilityRegistry();
28
+ });
29
+
30
+ test("built-in tools are pre-registered", () => {
31
+ const builtins = ["bash", "read", "write", "edit", "grep", "find", "ls", "lsp"];
32
+ for (const name of builtins) {
33
+ const compat = getToolCompatibility(name);
34
+ assert.ok(compat !== undefined, `${name} should be pre-registered`);
35
+ }
36
+ });
37
+
38
+ test("unknown tool returns undefined", () => {
39
+ assert.equal(getToolCompatibility("nonexistent_tool_xyz"), undefined);
40
+ });
41
+
42
+ test("registerToolCompatibility stores and retrieves metadata", () => {
43
+ registerToolCompatibility("screenshot_tool", {
44
+ producesImages: true,
45
+ minCapabilityTier: "standard",
46
+ });
47
+ const compat = getToolCompatibility("screenshot_tool");
48
+ assert.ok(compat);
49
+ assert.equal(compat.producesImages, true);
50
+ assert.equal(compat.minCapabilityTier, "standard");
51
+ });
52
+
53
+ test("registerMcpToolCompatibility sets default schema features", () => {
54
+ registerMcpToolCompatibility("mcp__test__tool");
55
+ const compat = getToolCompatibility("mcp__test__tool");
56
+ assert.ok(compat);
57
+ assert.ok(compat.schemaFeatures?.includes("patternProperties"));
58
+ });
59
+
60
+ test("registerMcpToolCompatibility allows overrides", () => {
61
+ registerMcpToolCompatibility("mcp__test__override", { producesImages: true });
62
+ const compat = getToolCompatibility("mcp__test__override");
63
+ assert.ok(compat);
64
+ assert.equal(compat.producesImages, true);
65
+ assert.ok(compat.schemaFeatures?.includes("patternProperties"));
66
+ });
67
+
68
+ test("getAllToolCompatibility returns all entries", () => {
69
+ const all = getAllToolCompatibility();
70
+ assert.ok(all.size >= 10); // at least built-in tools
71
+ assert.ok(all.has("bash"));
72
+ assert.ok(all.has("read"));
73
+ });
74
+
75
+ test("resetToolCompatibilityRegistry clears custom entries but keeps builtins", () => {
76
+ registerToolCompatibility("custom_tool", { producesImages: true });
77
+ assert.ok(getToolCompatibility("custom_tool"));
78
+ resetToolCompatibilityRegistry();
79
+ assert.equal(getToolCompatibility("custom_tool"), undefined);
80
+ assert.ok(getToolCompatibility("bash")); // built-in preserved
81
+ });
82
+ });
83
+
84
+ // ─── isToolCompatibleWithProvider ───────────────────────────────────────────
85
+
86
+ describe("isToolCompatibleWithProvider", () => {
87
+ beforeEach(() => {
88
+ resetToolCompatibilityRegistry();
89
+ });
90
+
91
+ test("tool without compatibility metadata is always compatible", () => {
92
+ const caps = getProviderCapabilities("anthropic-messages");
93
+ assert.equal(isToolCompatibleWithProvider("unknown_tool", caps), true);
94
+ });
95
+
96
+ test("built-in tools are compatible with all providers", () => {
97
+ const providers = ["anthropic-messages", "openai-responses", "google-generative-ai", "mistral-conversations"];
98
+ const tools = ["bash", "read", "write", "edit"];
99
+ for (const api of providers) {
100
+ const caps = getProviderCapabilities(api);
101
+ for (const tool of tools) {
102
+ assert.equal(
103
+ isToolCompatibleWithProvider(tool, caps),
104
+ true,
105
+ `${tool} should be compatible with ${api}`,
106
+ );
107
+ }
108
+ }
109
+ });
110
+
111
+ test("image-producing tool filtered for providers without image support", () => {
112
+ registerToolCompatibility("screenshot", { producesImages: true });
113
+ const openaiCaps = getProviderCapabilities("openai-responses");
114
+ assert.equal(isToolCompatibleWithProvider("screenshot", openaiCaps), false);
115
+
116
+ const anthropicCaps = getProviderCapabilities("anthropic-messages");
117
+ assert.equal(isToolCompatibleWithProvider("screenshot", anthropicCaps), true);
118
+ });
119
+
120
+ test("tool with unsupported schema features filtered for Google", () => {
121
+ registerToolCompatibility("complex_schema_tool", {
122
+ schemaFeatures: ["patternProperties"],
123
+ });
124
+ const googleCaps = getProviderCapabilities("google-generative-ai");
125
+ assert.equal(isToolCompatibleWithProvider("complex_schema_tool", googleCaps), false);
126
+
127
+ const anthropicCaps = getProviderCapabilities("anthropic-messages");
128
+ assert.equal(isToolCompatibleWithProvider("complex_schema_tool", anthropicCaps), true);
129
+ });
130
+ });
131
+
132
+ // ─── filterToolsForProvider ─────────────────────────────────────────────────
133
+
134
+ describe("filterToolsForProvider", () => {
135
+ beforeEach(() => {
136
+ resetToolCompatibilityRegistry();
137
+ });
138
+
139
+ test("all built-in tools pass for any provider", () => {
140
+ const toolNames = ["bash", "read", "write", "edit", "grep", "find", "ls"];
141
+ const { compatible, filtered } = filterToolsForProvider(toolNames, "mistral-conversations");
142
+ assert.deepEqual(compatible, toolNames);
143
+ assert.deepEqual(filtered, []);
144
+ });
145
+
146
+ test("image tool filtered for OpenAI Responses", () => {
147
+ registerToolCompatibility("browser_screenshot", { producesImages: true });
148
+ const toolNames = ["bash", "read", "browser_screenshot"];
149
+ const { compatible, filtered } = filterToolsForProvider(toolNames, "openai-responses");
150
+ assert.deepEqual(compatible, ["bash", "read"]);
151
+ assert.deepEqual(filtered, ["browser_screenshot"]);
152
+ });
153
+
154
+ test("MCP tool with patternProperties filtered for Google", () => {
155
+ registerMcpToolCompatibility("mcp__repowise__search");
156
+ const toolNames = ["bash", "read", "mcp__repowise__search"];
157
+ const { compatible, filtered } = filterToolsForProvider(toolNames, "google-generative-ai");
158
+ assert.deepEqual(compatible, ["bash", "read"]);
159
+ assert.deepEqual(filtered, ["mcp__repowise__search"]);
160
+ });
161
+
162
+ test("unknown provider passes all tools (permissive default)", () => {
163
+ registerToolCompatibility("image_tool", { producesImages: true });
164
+ registerMcpToolCompatibility("mcp_tool");
165
+ const toolNames = ["bash", "image_tool", "mcp_tool"];
166
+ const { compatible, filtered } = filterToolsForProvider(toolNames, "unknown-provider-xyz");
167
+ assert.deepEqual(compatible, toolNames);
168
+ assert.deepEqual(filtered, []);
169
+ });
170
+ });
171
+
172
+ // ─── adjustToolSet ──────────────────────────────────────────────────────────
173
+
174
+ describe("adjustToolSet", () => {
175
+ beforeEach(() => {
176
+ resetToolCompatibilityRegistry();
177
+ });
178
+
179
+ test("returns all tools for Anthropic (most permissive)", () => {
180
+ registerToolCompatibility("screenshot", { producesImages: true });
181
+ const toolNames = ["bash", "read", "screenshot"];
182
+ const { toolNames: result, removedTools } = adjustToolSet(toolNames, "anthropic-messages");
183
+ assert.deepEqual(result, toolNames);
184
+ assert.deepEqual(removedTools, []);
185
+ });
186
+
187
+ test("removes incompatible tools and reports them", () => {
188
+ registerToolCompatibility("screenshot", { producesImages: true });
189
+ registerMcpToolCompatibility("mcp_complex");
190
+ const toolNames = ["bash", "read", "screenshot", "mcp_complex"];
191
+ const { toolNames: result, removedTools } = adjustToolSet(toolNames, "google-generative-ai");
192
+ // Google supports images but not patternProperties
193
+ assert.ok(result.includes("bash"));
194
+ assert.ok(result.includes("read"));
195
+ assert.ok(result.includes("screenshot")); // Google supports images
196
+ assert.ok(!result.includes("mcp_complex")); // patternProperties not supported
197
+ assert.deepEqual(removedTools, ["mcp_complex"]);
198
+ });
199
+ });
@@ -141,7 +141,11 @@ test("detectWorkflowMcpLaunchConfig resolves the bundled server relative to the
141
141
  assert.match(launch?.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "", /workflow-tool-executors\.(js|ts)$/);
142
142
  assert.match(launch?.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "", /write-gate\.(js|ts)$/);
143
143
  assert.equal(typeof launch?.args?.[0], "string");
144
- assert.match(launch?.args?.[0] ?? "", /packages[\/\\]mcp-server[\/\\]dist[\/\\]cli\.js$/);
144
+ assert.match(launch?.args?.[0] ?? "", /packages[\/\\]mcp-server[\/\\](dist[\/\\]cli\.js|src[\/\\]cli\.ts)$/);
145
+ if ((launch?.args?.[0] ?? "").endsWith(".ts")) {
146
+ assert.match(launch?.env?.NODE_OPTIONS ?? "", /--experimental-strip-types/);
147
+ assert.match(launch?.env?.NODE_OPTIONS ?? "", /resolve-ts\.mjs/);
148
+ }
145
149
  });
146
150
 
147
151
  test("detectWorkflowMcpLaunchConfig resolves the bundled server relative to the package without env hints", () => {
@@ -154,7 +158,11 @@ test("detectWorkflowMcpLaunchConfig resolves the bundled server relative to the
154
158
  assert.match(launch?.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "", /workflow-tool-executors\.(js|ts)$/);
155
159
  assert.match(launch?.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "", /write-gate\.(js|ts)$/);
156
160
  assert.equal(typeof launch?.args?.[0], "string");
157
- assert.match(launch?.args?.[0] ?? "", /packages[\/\\]mcp-server[\/\\]dist[\/\\]cli\.js$/);
161
+ assert.match(launch?.args?.[0] ?? "", /packages[\/\\]mcp-server[\/\\](dist[\/\\]cli\.js|src[\/\\]cli\.ts)$/);
162
+ if ((launch?.args?.[0] ?? "").endsWith(".ts")) {
163
+ assert.match(launch?.env?.NODE_OPTIONS ?? "", /--experimental-strip-types/);
164
+ assert.match(launch?.env?.NODE_OPTIONS ?? "", /resolve-ts\.mjs/);
165
+ }
158
166
  });
159
167
 
160
168
  test("workflow MCP launch config reaches mutation tools over stdio", async () => {
@@ -165,12 +173,16 @@ test("workflow MCP launch config reaches mutation tools over stdio", async () =>
165
173
  assert.ok(launch, "expected a workflow MCP launch config");
166
174
  assert.match(
167
175
  launch.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "",
168
- /dist[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]tools[\/\\]workflow-tool-executors\.js$/,
176
+ /(dist[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]tools[\/\\]workflow-tool-executors\.js|src[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]tools[\/\\]workflow-tool-executors\.(js|ts))$/,
169
177
  );
170
178
  assert.match(
171
179
  launch.env?.GSD_WORKFLOW_WRITE_GATE_MODULE ?? "",
172
- /dist[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]bootstrap[\/\\]write-gate\.js$/,
180
+ /(dist[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]bootstrap[\/\\]write-gate\.js|src[\/\\]resources[\/\\]extensions[\/\\]gsd[\/\\]bootstrap[\/\\]write-gate\.(js|ts))$/,
173
181
  );
182
+ if ((launch.env?.GSD_WORKFLOW_EXECUTORS_MODULE ?? "").endsWith(".ts")) {
183
+ assert.match(launch.env?.NODE_OPTIONS ?? "", /--experimental-strip-types/);
184
+ assert.match(launch.env?.NODE_OPTIONS ?? "", /resolve-ts\.mjs/);
185
+ }
174
186
 
175
187
  const client = new Client({ name: "workflow-mcp-transport-test", version: "1.0.0" });
176
188
  const transport = new StdioClientTransport({
@@ -189,6 +201,10 @@ test("workflow MCP launch config reaches mutation tools over stdio", async () =>
189
201
  (tools.tools ?? []).some((tool) => tool.name === "gsd_plan_slice"),
190
202
  "expected workflow MCP surface to expose gsd_plan_slice",
191
203
  );
204
+ assert.ok(
205
+ (tools.tools ?? []).some((tool) => tool.name === "ask_user_questions"),
206
+ "expected workflow MCP surface to expose ask_user_questions",
207
+ );
192
208
 
193
209
  const milestoneResult = await client.callTool(
194
210
  {
@@ -465,18 +481,18 @@ test("transport compatibility now allows replan-slice over workflow MCP surface"
465
481
  test("transport compatibility still blocks units whose MCP tools are not exposed", () => {
466
482
  const error = getWorkflowTransportSupportError(
467
483
  "claude-code",
468
- ["gsd_skip_slice"],
484
+ ["secure_env_collect"],
469
485
  {
470
486
  projectRoot: "/tmp/project",
471
487
  env: { GSD_WORKFLOW_MCP_COMMAND: "node" },
472
488
  surface: "auto-mode",
473
- unitType: "skip-slice",
489
+ unitType: "guided-discussion",
474
490
  authMode: "externalCli",
475
491
  baseUrl: "local://claude-code",
476
492
  },
477
493
  );
478
494
 
479
- assert.match(error ?? "", /requires gsd_skip_slice/);
495
+ assert.match(error ?? "", /requires secure_env_collect/);
480
496
  assert.match(error ?? "", /currently exposes only/);
481
497
  });
482
498
 
@@ -230,16 +230,13 @@ import {
230
230
  // ─── Scenario 19: isGateQuestionId recognizes all gate patterns ──
231
231
 
232
232
  test('write-gate: isGateQuestionId recognizes all gate patterns', () => {
233
- assert.strictEqual(isGateQuestionId('layer1_scope_gate'), true);
234
- assert.strictEqual(isGateQuestionId('layer2_architecture_gate'), true);
235
- assert.strictEqual(isGateQuestionId('layer3_error_gate'), true);
236
- assert.strictEqual(isGateQuestionId('layer4_quality_gate'), true);
237
233
  assert.strictEqual(isGateQuestionId('depth_verification'), true);
238
234
  assert.strictEqual(isGateQuestionId('depth_verification_M002'), true);
239
- assert.strictEqual(isGateQuestionId('my_layer1_scope_gate_question'), true);
235
+ assert.strictEqual(isGateQuestionId('depth_verification_confirm'), true);
240
236
  // Non-gate question IDs
241
237
  assert.strictEqual(isGateQuestionId('project_intent'), false);
242
238
  assert.strictEqual(isGateQuestionId('feature_priority'), false);
239
+ assert.strictEqual(isGateQuestionId('layer1_scope_gate'), false);
243
240
  assert.strictEqual(isGateQuestionId(''), false);
244
241
  });
245
242
 
@@ -249,14 +246,14 @@ test('write-gate: pending gate lifecycle (set, get, clear)', () => {
249
246
  clearDiscussionFlowState();
250
247
  assert.strictEqual(getPendingGate(), null, 'starts null');
251
248
 
252
- setPendingGate('layer1_scope_gate');
253
- assert.strictEqual(getPendingGate(), 'layer1_scope_gate', 'set correctly');
249
+ setPendingGate('depth_verification');
250
+ assert.strictEqual(getPendingGate(), 'depth_verification', 'set correctly');
254
251
 
255
252
  clearPendingGate();
256
253
  assert.strictEqual(getPendingGate(), null, 'cleared correctly');
257
254
 
258
255
  // clearDiscussionFlowState also clears pending gate
259
- setPendingGate('layer2_architecture_gate');
256
+ setPendingGate('depth_verification_M002');
260
257
  clearDiscussionFlowState();
261
258
  assert.strictEqual(getPendingGate(), null, 'clearDiscussionFlowState clears pending gate');
262
259
  });
@@ -265,12 +262,12 @@ test('write-gate: pending gate lifecycle (set, get, clear)', () => {
265
262
 
266
263
  test('write-gate: shouldBlockPendingGate blocks write/edit during pending gate', () => {
267
264
  clearDiscussionFlowState();
268
- setPendingGate('layer1_scope_gate');
265
+ setPendingGate('depth_verification');
269
266
 
270
267
  // write should be blocked during discussion
271
268
  const writeResult = shouldBlockPendingGate('write', 'M001', false);
272
269
  assert.strictEqual(writeResult.block, true, 'write should be blocked');
273
- assert.ok(writeResult.reason!.includes('layer1_scope_gate'), 'reason mentions the gate');
270
+ assert.ok(writeResult.reason!.includes('depth_verification'), 'reason mentions the gate');
274
271
 
275
272
  // edit should be blocked
276
273
  const editResult = shouldBlockPendingGate('edit', 'M001', false);
@@ -287,7 +284,7 @@ test('write-gate: shouldBlockPendingGate blocks write/edit during pending gate',
287
284
 
288
285
  test('write-gate: shouldBlockPendingGate allows read-only and ask_user_questions during pending gate', () => {
289
286
  clearDiscussionFlowState();
290
- setPendingGate('layer1_scope_gate');
287
+ setPendingGate('depth_verification');
291
288
 
292
289
  // ask_user_questions is always safe (model needs to re-ask)
293
290
  assert.strictEqual(shouldBlockPendingGate('ask_user_questions', 'M001').block, false);
@@ -304,7 +301,7 @@ test('write-gate: shouldBlockPendingGate allows read-only and ask_user_questions
304
301
 
305
302
  test('write-gate: shouldBlockPendingGate blocks outside discussion when a gate is pending', () => {
306
303
  clearDiscussionFlowState();
307
- setPendingGate('layer1_scope_gate');
304
+ setPendingGate('depth_verification');
308
305
 
309
306
  // No milestoneId and no queue phase — still block because the gate is pending
310
307
  const result = shouldBlockPendingGate('write', null, false);
@@ -330,7 +327,7 @@ test('write-gate: shouldBlockPendingGate blocks in queue mode when gate is pendi
330
327
 
331
328
  test('write-gate: shouldBlockPendingGateBash allows read-only commands during pending gate', () => {
332
329
  clearDiscussionFlowState();
333
- setPendingGate('layer2_architecture_gate');
330
+ setPendingGate('depth_verification');
334
331
 
335
332
  assert.strictEqual(shouldBlockPendingGateBash('cat file.txt', 'M001').block, false);
336
333
  assert.strictEqual(shouldBlockPendingGateBash('git log --oneline', 'M001').block, false);
@@ -344,11 +341,11 @@ test('write-gate: shouldBlockPendingGateBash allows read-only commands during pe
344
341
 
345
342
  test('write-gate: shouldBlockPendingGateBash blocks mutating commands during pending gate', () => {
346
343
  clearDiscussionFlowState();
347
- setPendingGate('layer2_architecture_gate');
344
+ setPendingGate('depth_verification');
348
345
 
349
346
  const result = shouldBlockPendingGateBash('npm run build', 'M001');
350
347
  assert.strictEqual(result.block, true, 'mutating bash should be blocked');
351
- assert.ok(result.reason!.includes('layer2_architecture_gate'));
348
+ assert.ok(result.reason!.includes('depth_verification'));
352
349
 
353
350
  clearDiscussionFlowState();
354
351
  });
@@ -365,7 +362,7 @@ test('write-gate: no pending gate means no blocking', () => {
365
362
  // ─── Scenario 28: resetWriteGateState clears pending gate ──
366
363
 
367
364
  test('write-gate: resetWriteGateState clears pending gate', () => {
368
- setPendingGate('layer3_error_gate');
365
+ setPendingGate('depth_verification');
369
366
  resetWriteGateState();
370
367
  assert.strictEqual(getPendingGate(), null);
371
368
  });
@@ -1,7 +1,7 @@
1
1
  import { execSync } from "node:child_process";
2
2
  import { existsSync } from "node:fs";
3
3
  import { dirname, resolve } from "node:path";
4
- import { fileURLToPath } from "node:url";
4
+ import { fileURLToPath, pathToFileURL } from "node:url";
5
5
 
6
6
  export interface WorkflowMcpLaunchConfig {
7
7
  name: string;
@@ -21,22 +21,35 @@ export interface WorkflowCapabilityOptions {
21
21
  }
22
22
 
23
23
  const MCP_WORKFLOW_TOOL_SURFACE = new Set([
24
+ "ask_user_questions",
25
+ "gsd_decision_save",
24
26
  "gsd_complete_milestone",
25
27
  "gsd_complete_task",
26
28
  "gsd_complete_slice",
29
+ "gsd_generate_milestone_id",
30
+ "gsd_journal_query",
27
31
  "gsd_milestone_complete",
32
+ "gsd_milestone_generate_id",
28
33
  "gsd_milestone_status",
29
34
  "gsd_milestone_validate",
35
+ "gsd_plan_task",
30
36
  "gsd_plan_milestone",
31
37
  "gsd_plan_slice",
32
38
  "gsd_replan_slice",
33
39
  "gsd_reassess_roadmap",
40
+ "gsd_requirement_save",
41
+ "gsd_requirement_update",
34
42
  "gsd_roadmap_reassess",
43
+ "gsd_save_decision",
35
44
  "gsd_save_gate_result",
45
+ "gsd_save_requirement",
46
+ "gsd_skip_slice",
36
47
  "gsd_slice_replan",
37
48
  "gsd_slice_complete",
38
49
  "gsd_summary_save",
50
+ "gsd_task_plan",
39
51
  "gsd_task_complete",
52
+ "gsd_update_requirement",
40
53
  "gsd_validate_milestone",
41
54
  ]);
42
55
 
@@ -95,6 +108,8 @@ function getBundledWorkflowMcpCliPath(env: NodeJS.ProcessEnv): string | null {
95
108
  }
96
109
 
97
110
  const candidates = [
111
+ resolve(fileURLToPath(new URL("../../../../packages/mcp-server/src/cli.ts", import.meta.url))),
112
+ resolve(fileURLToPath(new URL("../../../../../packages/mcp-server/src/cli.ts", import.meta.url))),
98
113
  resolve(fileURLToPath(new URL("../../../../packages/mcp-server/dist/cli.js", import.meta.url))),
99
114
  resolve(fileURLToPath(new URL("../../../../../packages/mcp-server/dist/cli.js", import.meta.url))),
100
115
  ];
@@ -108,9 +123,9 @@ function getBundledWorkflowMcpCliPath(env: NodeJS.ProcessEnv): string | null {
108
123
 
109
124
  function getBundledWorkflowExecutorModulePath(): string | null {
110
125
  const candidates = [
111
- resolve(fileURLToPath(new URL("../../../../dist/resources/extensions/gsd/tools/workflow-tool-executors.js", import.meta.url))),
112
126
  resolve(fileURLToPath(new URL("./tools/workflow-tool-executors.js", import.meta.url))),
113
127
  resolve(fileURLToPath(new URL("./tools/workflow-tool-executors.ts", import.meta.url))),
128
+ resolve(fileURLToPath(new URL("../../../../dist/resources/extensions/gsd/tools/workflow-tool-executors.js", import.meta.url))),
114
129
  ];
115
130
 
116
131
  for (const candidate of candidates) {
@@ -122,9 +137,9 @@ function getBundledWorkflowExecutorModulePath(): string | null {
122
137
 
123
138
  function getBundledWorkflowWriteGateModulePath(): string | null {
124
139
  const candidates = [
125
- resolve(fileURLToPath(new URL("../../../../dist/resources/extensions/gsd/bootstrap/write-gate.js", import.meta.url))),
126
140
  resolve(fileURLToPath(new URL("./bootstrap/write-gate.js", import.meta.url))),
127
141
  resolve(fileURLToPath(new URL("./bootstrap/write-gate.ts", import.meta.url))),
142
+ resolve(fileURLToPath(new URL("../../../../dist/resources/extensions/gsd/bootstrap/write-gate.js", import.meta.url))),
128
143
  ];
129
144
 
130
145
  for (const candidate of candidates) {
@@ -134,19 +149,58 @@ function getBundledWorkflowWriteGateModulePath(): string | null {
134
149
  return null;
135
150
  }
136
151
 
152
+ function getResolveTsHookPath(): string | null {
153
+ const candidates = [
154
+ resolve(fileURLToPath(new URL("./tests/resolve-ts.mjs", import.meta.url))),
155
+ resolve(fileURLToPath(new URL("../../../../src/resources/extensions/gsd/tests/resolve-ts.mjs", import.meta.url))),
156
+ ];
157
+
158
+ for (const candidate of candidates) {
159
+ if (existsSync(candidate)) return candidate;
160
+ }
161
+
162
+ return null;
163
+ }
164
+
165
+ function mergeNodeOptions(existing: string | undefined, additions: string[]): string | undefined {
166
+ const tokens = (existing ?? "").split(/\s+/).map((value) => value.trim()).filter(Boolean);
167
+ for (const addition of additions) {
168
+ if (!tokens.includes(addition)) {
169
+ tokens.push(addition);
170
+ }
171
+ }
172
+ return tokens.length > 0 ? tokens.join(" ") : undefined;
173
+ }
174
+
137
175
  function buildWorkflowLaunchEnv(
138
176
  projectRoot: string,
139
177
  gsdCliPath: string | undefined,
140
178
  explicitEnv?: Record<string, string>,
179
+ workflowCliPath?: string,
141
180
  ): Record<string, string> {
142
181
  const executorModulePath = getBundledWorkflowExecutorModulePath();
143
182
  const writeGateModulePath = getBundledWorkflowWriteGateModulePath();
183
+ const resolveTsHookPath = getResolveTsHookPath();
184
+ const wantsSourceTs =
185
+ Boolean(resolveTsHookPath) &&
186
+ (
187
+ (workflowCliPath?.endsWith(".ts") ?? false) ||
188
+ (executorModulePath?.endsWith(".ts") ?? false) ||
189
+ (writeGateModulePath?.endsWith(".ts") ?? false)
190
+ );
191
+ const nodeOptions = wantsSourceTs
192
+ ? mergeNodeOptions(explicitEnv?.NODE_OPTIONS, [
193
+ "--experimental-strip-types",
194
+ `--import=${pathToFileURL(resolveTsHookPath!).href}`,
195
+ ])
196
+ : explicitEnv?.NODE_OPTIONS;
144
197
 
145
198
  return {
146
199
  ...(explicitEnv ?? {}),
147
200
  ...(gsdCliPath ? { GSD_CLI_PATH: gsdCliPath } : {}),
148
201
  ...(executorModulePath ? { GSD_WORKFLOW_EXECUTORS_MODULE: executorModulePath } : {}),
149
202
  ...(writeGateModulePath ? { GSD_WORKFLOW_WRITE_GATE_MODULE: writeGateModulePath } : {}),
203
+ ...(nodeOptions ? { NODE_OPTIONS: nodeOptions } : {}),
150
204
  GSD_PERSIST_WRITE_GATE_STATE: "1",
151
205
  GSD_WORKFLOW_PROJECT_ROOT: projectRoot,
152
206
  };
@@ -188,7 +242,7 @@ export function detectWorkflowMcpLaunchConfig(
188
242
  command: process.execPath,
189
243
  args: [distCli],
190
244
  cwd: resolvedWorkflowProjectRoot,
191
- env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath),
245
+ env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath, undefined, distCli),
192
246
  };
193
247
  }
194
248
 
@@ -199,7 +253,7 @@ export function detectWorkflowMcpLaunchConfig(
199
253
  command: process.execPath,
200
254
  args: [bundledCli],
201
255
  cwd: resolvedWorkflowProjectRoot,
202
- env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath),
256
+ env: buildWorkflowLaunchEnv(resolvedWorkflowProjectRoot, gsdCliPath, undefined, bundledCli),
203
257
  };
204
258
  }
205
259
 
@@ -1,67 +0,0 @@
1
- /**
2
- * GSD Prompt Validation — Validates enhanced context output before writing.
3
- *
4
- * Implements R109 validation requirement: CONTEXT.md must have required sections
5
- * before being written to disk.
6
- */
7
- /**
8
- * Validate that enhanced context content has all required sections.
9
- *
10
- * Required sections per R109:
11
- * - Scope section (## Scope, ## Milestone Scope, or ## Why This Milestone)
12
- * - Architectural Decisions section (## Architectural Decisions)
13
- * - Acceptance Criteria section (## Acceptance Criteria or ## Final Integrated Acceptance)
14
- *
15
- * Additionally validates that the Architectural Decisions section contains
16
- * at least one decision entry (### heading or **Decision marker).
17
- *
18
- * @param content - The enhanced context markdown content
19
- * @returns ValidationResult with valid flag and list of missing sections
20
- */
21
- export function validateEnhancedContext(content) {
22
- const missing = [];
23
- // Required section 1: Scope (multiple acceptable header variants)
24
- const hasScopeSection = /^## Scope\b/m.test(content) ||
25
- /^## Milestone Scope\b/m.test(content) ||
26
- /^## Why This Milestone\b/m.test(content);
27
- if (!hasScopeSection) {
28
- missing.push("Milestone Scope or Why This Milestone");
29
- }
30
- // Required section 2: Architectural Decisions
31
- const hasArchitecturalDecisions = /^## Architectural Decisions\b/m.test(content);
32
- if (!hasArchitecturalDecisions) {
33
- missing.push("Architectural Decisions");
34
- }
35
- // Required section 3: Acceptance Criteria (multiple acceptable header variants)
36
- const hasAcceptanceCriteria = /^## Acceptance Criteria\b/m.test(content) ||
37
- /^## Final Integrated Acceptance\b/m.test(content);
38
- if (!hasAcceptanceCriteria) {
39
- missing.push("Acceptance Criteria");
40
- }
41
- // Additional validation: Architectural Decisions must have at least one entry
42
- if (hasArchitecturalDecisions) {
43
- // Extract the section content between ## Architectural Decisions and the next ## heading.
44
- // Uses indexOf-based extraction instead of regex with \z (which is invalid in JavaScript
45
- // regex — it's PCRE/Ruby syntax and JS treats it as literal 'z').
46
- const sectionStart = content.indexOf("## Architectural Decisions");
47
- if (sectionStart === -1) {
48
- missing.push("Architectural Decisions");
49
- }
50
- else {
51
- const afterHeading = content.slice(sectionStart + "## Architectural Decisions".length);
52
- const nextSection = afterHeading.search(/^## /m);
53
- const sectionContent = nextSection === -1 ? afterHeading : afterHeading.slice(0, nextSection);
54
- // Check for actual decision entries:
55
- // - ### heading (subsection per decision)
56
- // - **Decision marker (inline decision format)
57
- const hasDecisionEntry = /^### /m.test(sectionContent) || /^\*\*Decision/m.test(sectionContent);
58
- if (!hasDecisionEntry) {
59
- missing.push("At least one architectural decision entry");
60
- }
61
- }
62
- }
63
- return {
64
- valid: missing.length === 0,
65
- missing,
66
- };
67
- }