@opengsd/gsd-pi 1.2.0-dev.844675c9 → 1.2.0-dev.b1abb545

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (375) hide show
  1. package/dist/cli-web-branch.d.ts +2 -0
  2. package/dist/cli-web-branch.js +9 -2
  3. package/dist/help-text.js +5 -0
  4. package/dist/resources/.managed-resources-content-hash +1 -1
  5. package/dist/resources/extensions/ask-user-questions.js +78 -23
  6. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +84 -228
  7. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
  8. package/dist/resources/extensions/github-sync/templates.js +3 -3
  9. package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
  10. package/dist/resources/extensions/gsd/auto/loop.js +74 -56
  11. package/dist/resources/extensions/gsd/auto/orchestrator.js +109 -11
  12. package/dist/resources/extensions/gsd/auto/phases.js +28 -3
  13. package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
  14. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  15. package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
  16. package/dist/resources/extensions/gsd/auto-dispatch.js +6 -5
  17. package/dist/resources/extensions/gsd/auto-model-selection.js +8 -0
  18. package/dist/resources/extensions/gsd/auto-post-unit.js +4 -3
  19. package/dist/resources/extensions/gsd/auto-prompts.js +81 -8
  20. package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
  21. package/dist/resources/extensions/gsd/auto-runtime-state.js +14 -0
  22. package/dist/resources/extensions/gsd/auto-start.js +12 -23
  23. package/dist/resources/extensions/gsd/auto-timers.js +16 -2
  24. package/dist/resources/extensions/gsd/auto-tool-tracking.js +32 -0
  25. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +4 -29
  26. package/dist/resources/extensions/gsd/auto-verification.js +7 -7
  27. package/dist/resources/extensions/gsd/auto-worktree.js +21 -19
  28. package/dist/resources/extensions/gsd/auto.js +11 -7
  29. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
  30. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +11 -37
  31. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
  32. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +100 -138
  33. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +63 -4
  34. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
  35. package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
  36. package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
  37. package/dist/resources/extensions/gsd/commands-handlers.js +20 -0
  38. package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
  39. package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
  40. package/dist/resources/extensions/gsd/commands-ship.js +2 -2
  41. package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
  42. package/dist/resources/extensions/gsd/db-workspace.js +103 -0
  43. package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
  44. package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
  45. package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  46. package/dist/resources/extensions/gsd/doctor.js +16 -9
  47. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  48. package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
  49. package/dist/resources/extensions/gsd/gsd-db.js +12 -0
  50. package/dist/resources/extensions/gsd/guided-flow.js +34 -468
  51. package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
  52. package/dist/resources/extensions/gsd/markdown-renderer.js +2 -1
  53. package/dist/resources/extensions/gsd/mcp-filter.js +2 -1
  54. package/dist/resources/extensions/gsd/mcp-tool-name.js +26 -0
  55. package/dist/resources/extensions/gsd/md-importer.js +4 -3
  56. package/dist/resources/extensions/gsd/migrate/safety.js +2 -2
  57. package/dist/resources/extensions/gsd/migration-auto-check.js +3 -2
  58. package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
  59. package/dist/resources/extensions/gsd/milestone-closeout.js +12 -4
  60. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
  61. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
  62. package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
  63. package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
  64. package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
  65. package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
  66. package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
  67. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
  68. package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
  69. package/dist/resources/extensions/gsd/preferences.js +147 -29
  70. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  71. package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -0
  72. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
  73. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  74. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  75. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  76. package/dist/resources/extensions/gsd/prompts/system.md +1 -1
  77. package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
  78. package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
  79. package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
  80. package/dist/resources/extensions/gsd/question-transport.js +86 -0
  81. package/dist/resources/extensions/gsd/roadmap-slices.js +8 -2
  82. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
  83. package/dist/resources/extensions/gsd/state.js +13 -5
  84. package/dist/resources/extensions/gsd/templates/plan.md +7 -0
  85. package/dist/resources/extensions/gsd/templates/project.md +1 -0
  86. package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
  87. package/dist/resources/extensions/gsd/templates/uat.md +5 -1
  88. package/dist/resources/extensions/gsd/tool-contract.js +52 -8
  89. package/dist/resources/extensions/gsd/tool-presentation-plan.js +15 -34
  90. package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
  91. package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
  92. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +39 -0
  93. package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
  94. package/dist/resources/extensions/gsd/uat-policy.js +16 -10
  95. package/dist/resources/extensions/gsd/uat-run.js +9 -14
  96. package/dist/resources/extensions/gsd/unit-context-composer.js +40 -20
  97. package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
  98. package/dist/resources/extensions/gsd/unit-tool-contracts.js +2 -1
  99. package/dist/resources/extensions/gsd/user-input-boundary.js +23 -0
  100. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  101. package/dist/resources/extensions/gsd/web-app-uat.js +80 -0
  102. package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
  103. package/dist/resources/extensions/gsd/workflow-reconcile.js +4 -3
  104. package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
  105. package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
  106. package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
  107. package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
  108. package/dist/resources/extensions/shared/interview-ui.js +2 -2
  109. package/dist/resources/shared/claude-runtime-floor.js +182 -0
  110. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  111. package/dist/update-cmd.js +20 -0
  112. package/dist/web/standalone/.next/BUILD_ID +1 -1
  113. package/dist/web/standalone/.next/app-path-routes-manifest.json +7 -7
  114. package/dist/web/standalone/.next/build-manifest.json +3 -3
  115. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  116. package/dist/web/standalone/.next/react-loadable-manifest.json +8 -8
  117. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  118. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  123. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  125. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  126. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/index.html +1 -1
  134. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app-paths-manifest.json +7 -7
  141. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  142. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  144. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  145. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  146. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  147. package/dist/web/standalone/.next/static/chunks/2659.b7b129ee6a769448.js +1 -0
  148. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
  149. package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
  150. package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
  151. package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
  152. package/dist/web/standalone/.next/static/chunks/796.cf859a427a2cb2ac.js +10 -0
  153. package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
  154. package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-fbea77b5f9953368.js} +1 -1
  155. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  156. package/dist/web-mode.d.ts +2 -0
  157. package/dist/web-mode.js +20 -8
  158. package/package.json +2 -1
  159. package/packages/cloud-mcp-gateway/package.json +2 -2
  160. package/packages/contracts/package.json +1 -1
  161. package/packages/daemon/package.json +4 -4
  162. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
  163. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  164. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
  165. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  166. package/packages/gsd-agent-core/package.json +5 -5
  167. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  168. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +106 -40
  169. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  170. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
  171. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
  172. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
  173. package/packages/gsd-agent-modes/package.json +7 -7
  174. package/packages/mcp-server/dist/server.d.ts +10 -0
  175. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  176. package/packages/mcp-server/dist/server.js +8 -0
  177. package/packages/mcp-server/dist/server.js.map +1 -1
  178. package/packages/mcp-server/dist/workflow-tools.d.ts +41 -0
  179. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  180. package/packages/mcp-server/dist/workflow-tools.js +2 -1
  181. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  182. package/packages/mcp-server/package.json +3 -3
  183. package/packages/native/package.json +1 -1
  184. package/packages/pi-agent-core/package.json +1 -1
  185. package/packages/pi-ai/dist/models.generated.d.ts +8 -93
  186. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  187. package/packages/pi-ai/dist/models.generated.js +35 -120
  188. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  189. package/packages/pi-ai/package.json +1 -1
  190. package/packages/pi-coding-agent/package.json +7 -7
  191. package/packages/pi-tui/dist/components/input.js +1 -1
  192. package/packages/pi-tui/dist/components/input.js.map +1 -1
  193. package/packages/pi-tui/dist/keys.d.ts.map +1 -1
  194. package/packages/pi-tui/dist/keys.js +39 -30
  195. package/packages/pi-tui/dist/keys.js.map +1 -1
  196. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  197. package/packages/pi-tui/dist/stdin-buffer.js +22 -0
  198. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  199. package/packages/pi-tui/package.json +2 -2
  200. package/packages/rpc-client/package.json +2 -2
  201. package/pkg/package.json +1 -1
  202. package/src/resources/extensions/ask-user-questions.ts +87 -24
  203. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +108 -281
  204. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +240 -0
  205. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
  206. package/src/resources/extensions/github-sync/templates.ts +3 -3
  207. package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
  208. package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
  209. package/src/resources/extensions/gsd/auto/contracts.ts +32 -2
  210. package/src/resources/extensions/gsd/auto/loop-deps.ts +2 -0
  211. package/src/resources/extensions/gsd/auto/loop.ts +83 -61
  212. package/src/resources/extensions/gsd/auto/orchestrator.ts +125 -12
  213. package/src/resources/extensions/gsd/auto/phases.ts +35 -3
  214. package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
  215. package/src/resources/extensions/gsd/auto/session.ts +4 -0
  216. package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
  217. package/src/resources/extensions/gsd/auto-dispatch.ts +20 -7
  218. package/src/resources/extensions/gsd/auto-model-selection.ts +8 -0
  219. package/src/resources/extensions/gsd/auto-post-unit.ts +4 -3
  220. package/src/resources/extensions/gsd/auto-prompts.ts +107 -9
  221. package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
  222. package/src/resources/extensions/gsd/auto-runtime-state.ts +26 -0
  223. package/src/resources/extensions/gsd/auto-start.ts +17 -20
  224. package/src/resources/extensions/gsd/auto-timers.ts +16 -2
  225. package/src/resources/extensions/gsd/auto-tool-tracking.ts +35 -0
  226. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +9 -30
  227. package/src/resources/extensions/gsd/auto-verification.ts +7 -8
  228. package/src/resources/extensions/gsd/auto-worktree.ts +33 -26
  229. package/src/resources/extensions/gsd/auto.ts +15 -8
  230. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
  231. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +10 -37
  232. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
  233. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +116 -151
  234. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +107 -3
  235. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
  236. package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
  237. package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
  238. package/src/resources/extensions/gsd/commands-handlers.ts +18 -0
  239. package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
  240. package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
  241. package/src/resources/extensions/gsd/commands-ship.ts +2 -2
  242. package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
  243. package/src/resources/extensions/gsd/db-workspace.ts +170 -0
  244. package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
  245. package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
  246. package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  247. package/src/resources/extensions/gsd/doctor.ts +15 -5
  248. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  249. package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
  250. package/src/resources/extensions/gsd/gsd-db.ts +12 -0
  251. package/src/resources/extensions/gsd/guided-flow.ts +47 -558
  252. package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
  253. package/src/resources/extensions/gsd/markdown-renderer.ts +2 -1
  254. package/src/resources/extensions/gsd/mcp-filter.ts +2 -1
  255. package/src/resources/extensions/gsd/mcp-tool-name.ts +35 -0
  256. package/src/resources/extensions/gsd/md-importer.ts +3 -3
  257. package/src/resources/extensions/gsd/migrate/safety.ts +2 -2
  258. package/src/resources/extensions/gsd/migration-auto-check.ts +2 -2
  259. package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
  260. package/src/resources/extensions/gsd/milestone-closeout.ts +12 -4
  261. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
  262. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
  263. package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
  264. package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
  265. package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
  266. package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
  267. package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
  268. package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
  269. package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
  270. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  271. package/src/resources/extensions/gsd/preferences.ts +173 -28
  272. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -0
  273. package/src/resources/extensions/gsd/prompts/execute-task.md +2 -0
  274. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +3 -1
  275. package/src/resources/extensions/gsd/prompts/plan-milestone.md +2 -0
  276. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -0
  277. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -0
  278. package/src/resources/extensions/gsd/prompts/system.md +1 -1
  279. package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
  280. package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
  281. package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
  282. package/src/resources/extensions/gsd/question-transport.ts +138 -0
  283. package/src/resources/extensions/gsd/roadmap-slices.ts +8 -2
  284. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
  285. package/src/resources/extensions/gsd/state.ts +15 -5
  286. package/src/resources/extensions/gsd/templates/plan.md +7 -0
  287. package/src/resources/extensions/gsd/templates/project.md +1 -0
  288. package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
  289. package/src/resources/extensions/gsd/templates/uat.md +5 -1
  290. package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
  291. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
  292. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +321 -5
  293. package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
  294. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
  295. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +133 -4
  296. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
  297. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
  298. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  299. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
  300. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +38 -1
  301. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
  302. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +88 -0
  303. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
  304. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
  305. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
  306. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
  307. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
  308. package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
  309. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +58 -0
  310. package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
  311. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +25 -0
  312. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
  313. package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
  314. package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
  315. package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
  316. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
  317. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +2 -0
  318. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
  319. package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
  320. package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
  321. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +46 -0
  322. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
  323. package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
  324. package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
  325. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +94 -0
  326. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
  327. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +25 -1
  328. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
  329. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +101 -1
  330. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
  331. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +2 -1
  332. package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
  333. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
  334. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +23 -0
  335. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +47 -0
  336. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +86 -1
  337. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
  338. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +150 -0
  339. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +126 -9
  340. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
  341. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +21 -0
  342. package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
  343. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
  344. package/src/resources/extensions/gsd/tests/write-gate.test.ts +79 -0
  345. package/src/resources/extensions/gsd/tool-contract.ts +86 -8
  346. package/src/resources/extensions/gsd/tool-presentation-plan.ts +16 -33
  347. package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
  348. package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
  349. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +43 -0
  350. package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
  351. package/src/resources/extensions/gsd/uat-policy.ts +19 -10
  352. package/src/resources/extensions/gsd/uat-run.ts +10 -14
  353. package/src/resources/extensions/gsd/unit-context-composer.ts +85 -20
  354. package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
  355. package/src/resources/extensions/gsd/unit-tool-contracts.ts +2 -1
  356. package/src/resources/extensions/gsd/user-input-boundary.ts +18 -0
  357. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  358. package/src/resources/extensions/gsd/web-app-uat.ts +101 -0
  359. package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
  360. package/src/resources/extensions/gsd/workflow-reconcile.ts +3 -3
  361. package/src/resources/extensions/gsd/workflow-tool-surface.ts +73 -0
  362. package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
  363. package/src/resources/extensions/gsd/worktree-lifecycle.ts +7 -16
  364. package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
  365. package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
  366. package/src/resources/extensions/shared/interview-ui.ts +15 -2
  367. package/src/resources/shared/claude-runtime-floor.ts +248 -0
  368. package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
  369. package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
  370. package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
  371. package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
  372. package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
  373. package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
  374. /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → 3PtrU9qGPEXwNLWkIyiqk}/_buildManifest.js +0 -0
  375. /package/dist/web/standalone/.next/static/{Qbr81pQ-pbQXP4bq2VXLv → 3PtrU9qGPEXwNLWkIyiqk}/_ssgManifest.js +0 -0
@@ -74,6 +74,29 @@ const PREPARE_WRITE_RE = /\.prepare\s*\(\s*[`'"][^`'"]*\b(INSERT|UPDATE|DELETE|R
74
74
 
75
75
  // Match .exec("... INSERT|UPDATE|DELETE|REPLACE ...") or raw BEGIN/COMMIT/ROLLBACK.
76
76
  const EXEC_WRITE_RE = /\.exec\s*\(\s*[`'"][^`'"]*\b(INSERT|UPDATE|DELETE|REPLACE|BEGIN|COMMIT|ROLLBACK)\b/i;
77
+ const DB_WORKSPACE_MECHANICS = new Set([
78
+ "backupDatabaseSnapshot",
79
+ "checkpointDatabase",
80
+ "closeAllDatabases",
81
+ "closeDatabase",
82
+ "closeDatabaseByWorkspace",
83
+ "getDbPath",
84
+ "getDbProvider",
85
+ "getDbStatus",
86
+ "openDatabase",
87
+ "openDatabaseByScope",
88
+ "openDatabaseByWorkspace",
89
+ "refreshOpenDatabaseFromDisk",
90
+ "vacuumDatabase",
91
+ "wasDbOpenAttempted",
92
+ ]);
93
+
94
+ function importNames(specifierBlock: string): string[] {
95
+ return specifierBlock
96
+ .split(",")
97
+ .map((name) => name.trim().replace(/^type\s+/, "").split(/\s+as\s+/)[0]?.trim() ?? "")
98
+ .filter(Boolean);
99
+ }
77
100
 
78
101
  test("no module outside gsd-db.ts issues raw write SQL against the engine DB", () => {
79
102
  const files = walkTsFiles(gsdDir);
@@ -166,6 +189,84 @@ test("gsd-db.ts exports the expected single-writer wrappers", async () => {
166
189
  }
167
190
  });
168
191
 
192
+ test("DB Workspace Interface owns database open-state and maintenance calls", async () => {
193
+ const workspaceDb = await import("../db-workspace.js");
194
+
195
+ const expected = [
196
+ "backupWorkflowDatabaseSnapshot",
197
+ "checkpointWorkflowDatabase",
198
+ "closeAllWorkflowDatabases",
199
+ "closeWorkflowDatabase",
200
+ "closeWorkflowDatabaseByWorkspace",
201
+ "getWorkflowDatabasePath",
202
+ "getWorkflowDatabaseProvider",
203
+ "getWorkflowDatabaseStatus",
204
+ "isWorkflowDatabaseOpen",
205
+ "openExistingWorkflowDatabase",
206
+ "openWorkflowDatabase",
207
+ "openWorkflowDatabaseByScope",
208
+ "openWorkflowDatabaseByWorkspace",
209
+ "openWorkflowDatabasePath",
210
+ "refreshWorkflowDatabaseFromDisk",
211
+ "resolveProjectRootDbPath",
212
+ "resolveWorkflowDatabaseLocation",
213
+ "vacuumWorkflowDatabase",
214
+ "wasWorkflowDatabaseOpenAttempted",
215
+ ];
216
+
217
+ for (const name of expected) {
218
+ assert.ok(
219
+ typeof (workspaceDb as Record<string, unknown>)[name] === "function",
220
+ `db-workspace.ts must export ${name} as a function`,
221
+ );
222
+ }
223
+ });
224
+
225
+ test("production modules do not import DB open-state mechanics from gsd-db.ts", () => {
226
+ const files = walkTsFiles(gsdDir);
227
+ const violations: Violation[] = [];
228
+ const staticImportRe = /import\s*\{([\s\S]*?)\}\s*from\s*["'][^"']*gsd-db\.(?:js|ts)["']/g;
229
+ const dynamicImportRe = /(?:const|let)\s*\{([\s\S]*?)\}\s*=\s*await\s+import\(["'][^"']*gsd-db\.(?:js|ts)["']\)/g;
230
+
231
+ for (const abs of files) {
232
+ const rel = relative(gsdDir, abs);
233
+ if (rel === "gsd-db.ts" || rel === "db-workspace.ts") continue;
234
+
235
+ let content: string;
236
+ try {
237
+ content = readFileSync(abs, "utf-8");
238
+ } catch {
239
+ continue;
240
+ }
241
+
242
+ for (const re of [staticImportRe, dynamicImportRe]) {
243
+ re.lastIndex = 0;
244
+ let match: RegExpExecArray | null;
245
+ while ((match = re.exec(content)) !== null) {
246
+ const leaked = importNames(match[1] ?? "").filter((name) => DB_WORKSPACE_MECHANICS.has(name));
247
+ if (leaked.length === 0) continue;
248
+ violations.push({
249
+ file: rel,
250
+ line: content.slice(0, match.index).split("\n").length,
251
+ snippet: leaked.join(", "),
252
+ kind: "db-workspace-leak",
253
+ });
254
+ }
255
+ }
256
+ }
257
+
258
+ if (violations.length > 0) {
259
+ const lines = violations.map(
260
+ (v) => ` ${v.file}:${v.line} [${v.kind}] — ${v.snippet}`,
261
+ );
262
+ assert.fail(
263
+ `Found ${violations.length} DB open-state import(s) from gsd-db.ts:\n` +
264
+ lines.join("\n") +
265
+ "\n\nImport these through db-workspace.ts so gsd-db.ts stays the single-writer implementation, not the caller-facing DB Workspace Interface.",
266
+ );
267
+ }
268
+ });
269
+
169
270
  test("the invariant test touches every .ts module under gsd/ (sanity check)", () => {
170
271
  const files = walkTsFiles(gsdDir);
171
272
  // Rough sanity: ensure we're not accidentally walking an empty tree
@@ -177,4 +278,3 @@ test("the invariant test touches every .ts module under gsd/ (sanity check)", ()
177
278
  assert.ok(rels.includes("memory-store.ts"), "walker must include memory-store.ts");
178
279
  assert.ok(rels.includes("workflow-manifest.ts"), "walker must include workflow-manifest.ts");
179
280
  });
180
-
@@ -74,6 +74,33 @@ describe("stale queued milestone selection (#3470)", () => {
74
74
  assert.equal(m070Entry!.status, "active", "M070 should be active in registry");
75
75
  });
76
76
 
77
+ test("queued milestone with roadmap projection but no DB slices stays deferred", async () => {
78
+ base = createFixtureBase();
79
+ openDatabase(":memory:");
80
+
81
+ // M068: queued shell with a stale ROADMAP projection, but no CONTEXT and no DB slices.
82
+ insertMilestone({ id: "M068", title: "Queued Roadmap Projection", status: "queued" });
83
+ writeFile(base, "milestones/M068/M068-ROADMAP.md", "# M068\n\n## Slices\n\n- [ ] **S99: Stale Slice**");
84
+
85
+ // M070: real active milestone — context, roadmap, slices, tasks
86
+ insertMilestone({ id: "M070", title: "Real Active", status: "active" });
87
+ insertSlice({ id: "S01", milestoneId: "M070", title: "Slice One", status: "active", risk: "low", depends: [] });
88
+ insertTask({ id: "T01", sliceId: "S01", milestoneId: "M070", title: "Task One", status: "pending" });
89
+
90
+ writeFile(base, "milestones/M070/M070-CONTEXT.md", "# M070: Real Active\n\nThis is the real milestone.");
91
+ writeFile(base, "milestones/M070/M070-ROADMAP.md", "# M070: Real Active\n\n## Slices\n\n- [ ] **S01: Slice One**");
92
+ writeFile(base, "milestones/M070/slices/S01/S01-PLAN.md", "# S01: Slice One\n\n## Tasks\n\n- [ ] **T01: Task One**");
93
+
94
+ invalidateStateCache();
95
+ const state = await deriveStateFromDb(base);
96
+
97
+ assert.equal(state.activeMilestone?.id, "M070", "ROADMAP-only queued milestone must not block active M070");
98
+
99
+ const m068Entry = state.registry.find((e: any) => e.id === "M068");
100
+ assert.ok(m068Entry, "M068 should still appear in registry");
101
+ assert.equal(m068Entry!.status, "pending", "M068 should stay pending without CONTEXT or DB slices");
102
+ });
103
+
77
104
  test("queued milestone WITH context file can still be selected as active", async () => {
78
105
  base = createFixtureBase();
79
106
  openDatabase(":memory:");
@@ -364,6 +364,7 @@ test("effective unit isolation follows degraded branch fallback", () => {
364
364
 
365
365
  test("discuss-to-auto handoff defaults to step mode unless explicitly disabled", () => {
366
366
  const guidedFlowSrc = readGsdFile("guided-flow.ts");
367
+ const discussionHandoffSrc = readGsdFile("discussion-handoff.ts");
367
368
  const workflowSrc = readGsdFile("commands/handlers/workflow.ts");
368
369
 
369
370
  assert.ok(
@@ -371,7 +372,7 @@ test("discuss-to-auto handoff defaults to step mode unless explicitly disabled",
371
372
  "guided-flow must not hardcode step: false on pending auto-start entries",
372
373
  );
373
374
  assert.match(
374
- guidedFlowSrc,
375
+ discussionHandoffSrc,
375
376
  /scheduleAutoStartAfterIdle\(ctx, pi, basePath, false, \{ step: step \?\? true \}\)/,
376
377
  "checkAutoStartAfterDiscuss should default missing step flags to step mode",
377
378
  );
@@ -141,6 +141,41 @@ for (const customType of ["gsd-discuss", "gsd-run"] as const) {
141
141
  });
142
142
  }
143
143
 
144
+ for (const unitType of ["execute-task", "execute-task-simple", "reactive-execute"] as const) {
145
+ test(`${unitType}: resolves gsd_task_complete via alias gsd_complete_task when only alias is registered`, () => {
146
+ // Simulates the MCP transport registering gsd_complete_task (alias) instead of gsd_task_complete.
147
+ // adjust_tool_set strips aliases from providerCompatible, so gsd_complete_task is only present
148
+ // in registeredToolNames. resolveScopedToolNames must still surface it so the agent can complete tasks.
149
+ const base: string[] = [...FULL_REGISTERED_TOOLS];
150
+ const aliasOnlyRegistered = base
151
+ .filter((name) => name !== "gsd_task_complete")
152
+ .concat("gsd_complete_task");
153
+ const aliasStrippedActive = aliasOnlyRegistered.filter((name) => name !== "gsd_complete_task");
154
+
155
+ const result = buildMinimalAutoGsdToolSet(aliasStrippedActive, unitType, aliasOnlyRegistered);
156
+
157
+ assert.ok(
158
+ result.includes("gsd_task_complete") || result.includes("gsd_complete_task"),
159
+ `${unitType} missing gsd_task_complete / gsd_complete_task — agent cannot complete tasks`,
160
+ );
161
+ });
162
+
163
+ test(`${unitType}: alias does not duplicate canonical when both are in the active set`, () => {
164
+ // When both canonical and alias are registered/active, only the canonical should be surfaced.
165
+ const bothPresent: string[] = [...FULL_REGISTERED_TOOLS, "gsd_complete_task"];
166
+
167
+ const result = buildMinimalAutoGsdToolSet(bothPresent, unitType, bothPresent);
168
+
169
+ const hasCanonical = result.includes("gsd_task_complete");
170
+ const hasAlias = result.includes("gsd_complete_task");
171
+ assert.ok(hasCanonical || hasAlias, `${unitType} missing completion tool`);
172
+ assert.ok(
173
+ !(hasCanonical && hasAlias),
174
+ `${unitType} surfaces both gsd_task_complete and gsd_complete_task — alias should not duplicate canonical`,
175
+ );
176
+ });
177
+ }
178
+
144
179
  test("discuss-milestone two-stage scoping matches adjust_tool_set request scope", () => {
145
180
  const activeTools = simulateDiscussAllowlistFilter(FULL_REGISTERED_TOOLS);
146
181
  const dispatchScoped = buildMinimalAutoGsdToolSet(
@@ -5,6 +5,10 @@ import { test } from 'node:test';
5
5
  import assert from 'node:assert/strict';
6
6
  import { registerDbTools } from '../bootstrap/db-tools.ts';
7
7
  import { getLegacyTelemetry, resetLegacyTelemetry } from '../legacy-telemetry.ts';
8
+ import {
9
+ WORKFLOW_TOOL_ALIAS_PAIRS,
10
+ WORKFLOW_TOOL_CONTRACTS,
11
+ } from '../workflow-tool-surface.ts';
8
12
 
9
13
 
10
14
  // ─── Mock PI ──────────────────────────────────────────────────────────────────
@@ -17,49 +21,38 @@ function makeMockPi() {
17
21
  } as any;
18
22
  }
19
23
 
20
- // ─── Rename map ───────────────────────────────────────────────────────────────
21
-
22
- const RENAME_MAP: Array<{ canonical: string; alias: string }> = [
23
- { canonical: "gsd_decision_save", alias: "gsd_save_decision" },
24
- { canonical: "gsd_requirement_update", alias: "gsd_update_requirement" },
25
- { canonical: "gsd_requirement_save", alias: "gsd_save_requirement" },
26
- { canonical: "gsd_summary_save", alias: "gsd_save_summary" },
27
- { canonical: "gsd_milestone_generate_id", alias: "gsd_generate_milestone_id" },
28
- { canonical: "gsd_task_complete", alias: "gsd_complete_task" },
29
- { canonical: "gsd_slice_complete", alias: "gsd_complete_slice" },
30
- { canonical: "gsd_plan_milestone", alias: "gsd_milestone_plan" },
31
- { canonical: "gsd_plan_slice", alias: "gsd_slice_plan" },
32
- { canonical: "gsd_plan_task", alias: "gsd_task_plan" },
33
- { canonical: "gsd_replan_slice", alias: "gsd_slice_replan" },
34
- { canonical: "gsd_reassess_roadmap", alias: "gsd_roadmap_reassess" },
35
- { canonical: "gsd_complete_milestone", alias: "gsd_milestone_complete" },
36
- { canonical: "gsd_validate_milestone", alias: "gsd_milestone_validate" },
37
- { canonical: "gsd_task_reopen", alias: "gsd_reopen_task" },
38
- { canonical: "gsd_slice_reopen", alias: "gsd_reopen_slice" },
39
- { canonical: "gsd_milestone_reopen", alias: "gsd_reopen_milestone" },
40
- ];
41
-
42
- const STANDALONE_TOOLS = [
43
- "gsd_save_gate_result",
44
- "gsd_skip_slice",
45
- "gsd_uat_result_save",
46
- ];
47
-
48
24
  // ─── Registration count ──────────────────────────────────────────────────────
49
25
 
50
26
  console.log('\n── Tool naming: registration count ──');
51
27
 
52
28
  const pi = makeMockPi();
53
29
  registerDbTools(pi);
54
-
30
+ const toolByName = new Map<string, any>(pi.tools.map((tool: any) => [tool.name, tool]));
31
+ const registeredCanonicalNames = new Set<string>(
32
+ WORKFLOW_TOOL_CONTRACTS
33
+ .map((tool) => tool.canonicalName)
34
+ .filter((name) => toolByName.has(name)),
35
+ );
36
+ const RENAME_MAP = WORKFLOW_TOOL_ALIAS_PAIRS.filter(({ canonical }) =>
37
+ registeredCanonicalNames.has(canonical),
38
+ );
39
+ const STANDALONE_TOOLS = WORKFLOW_TOOL_CONTRACTS
40
+ .filter((tool) => registeredCanonicalNames.has(tool.canonicalName) && tool.aliases.length === 0)
41
+ .map((tool) => tool.canonicalName);
42
+ const expectedRegisteredNames = [
43
+ ...STANDALONE_TOOLS,
44
+ ...RENAME_MAP.flatMap(({ canonical, alias }) => [canonical, alias]),
45
+ ].sort();
46
+
47
+ assert.equal(pi.tools.length, toolByName.size, 'Tool registration should not produce duplicate names');
55
48
  assert.deepStrictEqual(
56
- pi.tools.length,
57
- RENAME_MAP.length * 2 + STANDALONE_TOOLS.length,
58
- 'Should register canonical/alias tool pairs plus standalone DB tools',
49
+ [...toolByName.keys()].sort(),
50
+ expectedRegisteredNames,
51
+ 'Should register only workflow surface tools and their declared aliases',
59
52
  );
60
53
 
61
54
  for (const name of STANDALONE_TOOLS) {
62
- assert.ok(pi.tools.some((t: any) => t.name === name), `Standalone tool "${name}" should be registered`);
55
+ assert.ok(toolByName.has(name), `Standalone tool "${name}" should be registered`);
63
56
  }
64
57
 
65
58
  // ─── Both names exist for each pair ──────────────────────────────────────────
@@ -67,8 +60,8 @@ for (const name of STANDALONE_TOOLS) {
67
60
  console.log('\n── Tool naming: canonical and alias names exist ──');
68
61
 
69
62
  for (const { canonical, alias } of RENAME_MAP) {
70
- const canonicalTool = pi.tools.find((t: any) => t.name === canonical);
71
- const aliasTool = pi.tools.find((t: any) => t.name === alias);
63
+ const canonicalTool = toolByName.get(canonical);
64
+ const aliasTool = toolByName.get(alias);
72
65
 
73
66
  assert.ok(canonicalTool !== undefined, `Canonical tool "${canonical}" should be registered`);
74
67
  assert.ok(aliasTool !== undefined, `Alias tool "${alias}" should be registered`);
@@ -79,8 +72,8 @@ for (const { canonical, alias } of RENAME_MAP) {
79
72
  console.log('\n── Tool naming: alias execute wrapper ──');
80
73
 
81
74
  for (const { canonical, alias } of RENAME_MAP) {
82
- const canonicalTool = pi.tools.find((t: any) => t.name === canonical);
83
- const aliasTool = pi.tools.find((t: any) => t.name === alias);
75
+ const canonicalTool = toolByName.get(canonical);
76
+ const aliasTool = toolByName.get(alias);
84
77
 
85
78
  if (canonicalTool && aliasTool) {
86
79
  assert.ok(
@@ -91,8 +84,8 @@ for (const { canonical, alias } of RENAME_MAP) {
91
84
  }
92
85
 
93
86
  test("alias execute increments legacy MCP alias telemetry before delegating", async () => {
94
- const canonicalTool = pi.tools.find((t: any) => t.name === "gsd_decision_save");
95
- const aliasTool = pi.tools.find((t: any) => t.name === "gsd_save_decision");
87
+ const canonicalTool = toolByName.get("gsd_decision_save");
88
+ const aliasTool = toolByName.get("gsd_save_decision");
96
89
  assert.ok(canonicalTool);
97
90
  assert.ok(aliasTool);
98
91
 
@@ -120,7 +113,7 @@ test("alias execute increments legacy MCP alias telemetry before delegating", as
120
113
  console.log('\n── Tool naming: alias descriptions ──');
121
114
 
122
115
  for (const { canonical, alias } of RENAME_MAP) {
123
- const aliasTool = pi.tools.find((t: any) => t.name === alias);
116
+ const aliasTool = toolByName.get(alias);
124
117
 
125
118
  if (aliasTool) {
126
119
  assert.ok(
@@ -135,7 +128,7 @@ for (const { canonical, alias } of RENAME_MAP) {
135
128
  console.log('\n── Tool naming: canonical promptGuidelines use canonical name ──');
136
129
 
137
130
  for (const { canonical } of RENAME_MAP) {
138
- const canonicalTool = pi.tools.find((t: any) => t.name === canonical);
131
+ const canonicalTool = toolByName.get(canonical);
139
132
 
140
133
  if (canonicalTool) {
141
134
  const guidelinesText = canonicalTool.promptGuidelines.join(' ');
@@ -151,7 +144,7 @@ for (const { canonical } of RENAME_MAP) {
151
144
  console.log('\n── Tool naming: alias promptGuidelines redirect to canonical ──');
152
145
 
153
146
  for (const { canonical, alias } of RENAME_MAP) {
154
- const aliasTool = pi.tools.find((t: any) => t.name === alias);
147
+ const aliasTool = toolByName.get(alias);
155
148
 
156
149
  if (aliasTool) {
157
150
  const guidelinesText = aliasTool.promptGuidelines.join(' ');
@@ -66,6 +66,9 @@ describe("uat-policy", () => {
66
66
  it("detects direct and MCP-shaped browser tool surfaces", () => {
67
67
  assert.equal(hasUatBrowserToolSurface(["read", "browser_navigate"]), true);
68
68
  assert.equal(hasUatBrowserToolSurface(["read", "mcp__gsd-browser__browser_navigate"]), true);
69
+ assert.equal(hasUatBrowserToolSurface(["read", "mcp__gsd-browser__*"]), true);
70
+ assert.equal(hasUatBrowserToolSurface(["read", "mcp__browser-uat__*"]), true);
71
+ assert.equal(hasUatBrowserToolSurface(["read", "mcp__gsd-workflow__*"]), false);
69
72
  assert.equal(hasUatBrowserToolSurface(["read", "gsd_uat_exec"]), false);
70
73
  assert.equal(hasUatBrowserToolSurface(undefined), false);
71
74
  });
@@ -89,6 +92,26 @@ describe("uat-policy", () => {
89
92
  }),
90
93
  null,
91
94
  );
95
+ assert.equal(
96
+ getUatBrowserToolSupportError({
97
+ uatType: "human-experience",
98
+ activeTools: ["read", "gsd_uat_exec"],
99
+ registeredTools: ["browser_navigate"],
100
+ milestoneId: "M001",
101
+ sliceId: "S01",
102
+ }),
103
+ null,
104
+ );
105
+ assert.equal(
106
+ getUatBrowserToolSupportError({
107
+ uatType: "human-experience",
108
+ activeTools: ["read", "gsd_uat_exec"],
109
+ registeredTools: ["mcp__gsd-browser__*"],
110
+ milestoneId: "M001",
111
+ sliceId: "S01",
112
+ }),
113
+ null,
114
+ );
92
115
 
93
116
  const error = getUatBrowserToolSupportError({
94
117
  uatType: "browser-executable",
@@ -8,6 +8,7 @@ import { join } from "node:path";
8
8
  import { tmpdir } from "node:os";
9
9
 
10
10
  import {
11
+ composeContractedUnitContext,
11
12
  composeContextModeInstructions,
12
13
  composeInlinedContext,
13
14
  composeUnitContext,
@@ -15,6 +16,7 @@ import {
15
16
  type ArtifactResolver,
16
17
  type ExcerptResolver,
17
18
  } from "../unit-context-composer.ts";
19
+ import { compileUnitContextContract } from "../tool-contract.ts";
18
20
  import type {
19
21
  ArtifactKey,
20
22
  BaseResolverContext,
@@ -268,6 +270,21 @@ test("#4782 phase 2: buildReassessRoadmapPrompt emits composer-shaped context wi
268
270
  assert.ok(!prompt.includes("Slice Context (from discussion)"));
269
271
  });
270
272
 
273
+ test("execute-task prompt surfaces contract-declared on-demand slice research", async (t) => {
274
+ const base = makeFixtureBase();
275
+ t.after(() => cleanup(base));
276
+ invalidateAllCaches();
277
+
278
+ seed(base, "M001");
279
+ writeArtifacts(base);
280
+
281
+ const prompt = await buildExecuteTaskPrompt("M001", "S01", "First", "T01", "Task", base);
282
+
283
+ assert.match(prompt, /## On-demand Context/);
284
+ assert.match(prompt, /\.gsd\/milestones\/M001\/slices\/S01\/S01-RESEARCH\.md/);
285
+ assert.match(prompt, /Read it only if the inlined task plan, slice plan excerpt, and carry-forward context do not explain/);
286
+ });
287
+
271
288
  test("Context Mode resume injection: eligible prompts include one bounded snapshot block above inlined context", async (t) => {
272
289
  const base = makeFixtureBase();
273
290
  t.after(() => cleanup(base));
@@ -370,6 +387,36 @@ test("#4924 v2 composer: returns empty sections for unknown unit type", async ()
370
387
  assert.deepEqual(out, { prepend: "", inline: "" });
371
388
  });
372
389
 
390
+ test("Unit Context Contract composer exposes keyed blocks and on-demand artifacts", async () => {
391
+ const result = compileUnitContextContract("execute-task");
392
+ assert.equal(result.ok, true);
393
+ if (!result.ok) return;
394
+
395
+ const calls: ArtifactKey[] = [];
396
+ const out = await composeContractedUnitContext(result.contract, {
397
+ base: { ...fakeBase, unitType: "stale-unit", taskId: "T01" },
398
+ resolveArtifact: async (key) => {
399
+ calls.push(key);
400
+ return `BODY:${key}`;
401
+ },
402
+ });
403
+
404
+ assert.deepEqual(calls, [
405
+ "task-plan",
406
+ "slice-plan",
407
+ "prior-task-summaries",
408
+ "templates",
409
+ ]);
410
+ assert.deepEqual(out.blocks.map((block) => [block.key, block.mode]), [
411
+ ["task-plan", "inline"],
412
+ ["slice-plan", "inline"],
413
+ ["prior-task-summaries", "inline"],
414
+ ["templates", "inline"],
415
+ ]);
416
+ assert.deepEqual(out.onDemand, ["slice-research"]);
417
+ assert.match(out.inline, /BODY:task-plan\n\n---\n\nBODY:slice-plan/);
418
+ });
419
+
373
420
  test("#4924 v2 composer: omitting resolveArtifact skips inline keys without erroring", async () => {
374
421
  const out = await composeUnitContext("reassess-roadmap", { base: fakeBase });
375
422
  assert.strictEqual(out.inline, "");
@@ -2,7 +2,11 @@ import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
3
 
4
4
  import * as userInputBoundary from "../user-input-boundary.ts";
5
- import { isAwaitingUserInput, shouldPauseForUserApprovalQuestion } from "../user-input-boundary.ts";
5
+ import {
6
+ isAwaitingUserInput,
7
+ messageHasPendingAskUserQuestionsTool,
8
+ shouldPauseForUserApprovalQuestion,
9
+ } from "../user-input-boundary.ts";
6
10
 
7
11
  test("lastAssistantText extracts the latest assistant text block content", () => {
8
12
  const lastAssistantText = (userInputBoundary as {
@@ -73,6 +77,87 @@ test("isAwaitingUserInput does not trigger on thinking-block approval phrases",
73
77
  assert.equal(shouldPauseForUserApprovalQuestion("discuss-requirements", messages), false);
74
78
  });
75
79
 
80
+ test("messageHasPendingAskUserQuestionsTool detects in-flight structured question tools", () => {
81
+ // state: "running" with no externalResult → still in-flight
82
+ assert.equal(
83
+ messageHasPendingAskUserQuestionsTool({
84
+ role: "assistant",
85
+ content: [
86
+ { type: "text", text: "Which direction?" },
87
+ { type: "toolCall", name: "mcp__gsd-workflow__ask_user_questions", state: "running" },
88
+ ],
89
+ }),
90
+ true,
91
+ );
92
+
93
+ // no state, no externalResult — streaming block that hasn't completed yet
94
+ assert.equal(
95
+ messageHasPendingAskUserQuestionsTool({
96
+ role: "assistant",
97
+ content: [
98
+ { type: "toolCall", name: "ask_user_questions" },
99
+ ],
100
+ }),
101
+ true,
102
+ );
103
+
104
+ // state: "completed" — legacy state-based completion
105
+ assert.equal(
106
+ messageHasPendingAskUserQuestionsTool({
107
+ role: "assistant",
108
+ content: [
109
+ { type: "toolCall", name: "ask_user_questions", state: "completed" },
110
+ ],
111
+ }),
112
+ false,
113
+ );
114
+
115
+ // externalResult present — Claude Code signals completion via externalResult, not state
116
+ assert.equal(
117
+ messageHasPendingAskUserQuestionsTool({
118
+ role: "assistant",
119
+ content: [
120
+ { type: "toolCall", name: "ask_user_questions", externalResult: { content: [], isError: false } },
121
+ ],
122
+ }),
123
+ false,
124
+ );
125
+ assert.equal(
126
+ messageHasPendingAskUserQuestionsTool({
127
+ role: "assistant",
128
+ content: [
129
+ {
130
+ type: "toolCall",
131
+ name: "ask_user_questions",
132
+ externalResult: { content: [{ type: "text", text: "answer" }], isError: false },
133
+ },
134
+ ],
135
+ }),
136
+ false,
137
+ );
138
+
139
+ // serverToolUse shape (claude-code-cli MCP path) — no externalResult → in-flight
140
+ assert.equal(
141
+ messageHasPendingAskUserQuestionsTool({
142
+ role: "assistant",
143
+ content: [
144
+ { type: "serverToolUse", name: "mcp__gsd-workflow__ask_user_questions" },
145
+ ],
146
+ }),
147
+ true,
148
+ );
149
+ // serverToolUse shape — externalResult present → completed
150
+ assert.equal(
151
+ messageHasPendingAskUserQuestionsTool({
152
+ role: "assistant",
153
+ content: [
154
+ { type: "serverToolUse", name: "ask_user_questions", externalResult: { content: [], isError: false } },
155
+ ],
156
+ }),
157
+ false,
158
+ );
159
+ });
160
+
76
161
  test("isAwaitingUserInput still triggers on text-block question marks when thinking is also present", () => {
77
162
  // When thinking + text are both present and the text asks a question, it should still pause.
78
163
  const messages = [
@@ -12,6 +12,7 @@ import { clearPathCache } from "../paths.ts";
12
12
  import {
13
13
  openDatabase,
14
14
  closeDatabase,
15
+ insertAssessment,
15
16
  insertMilestone,
16
17
  insertSlice,
17
18
  } from "../gsd-db.ts";
@@ -222,6 +223,44 @@ describe("validate-milestone stuck-loop guard (#4094)", () => {
222
223
  assert.equal(s.pendingVerificationRetry, null);
223
224
  });
224
225
 
226
+ test("continues when DB pass overrides stale worktree needs-attention after /gsd verdict", async () => {
227
+ insertMilestone({ id: "M001" });
228
+ insertSlice({ id: "S01", milestoneId: "M001", title: "Slice 1", status: "complete" });
229
+ writeWorktreeValidationFile("needs-attention");
230
+
231
+ const worktreeValidationPath = join(
232
+ tempDir,
233
+ ".gsd",
234
+ "worktrees",
235
+ "M001",
236
+ ".gsd",
237
+ "milestones",
238
+ "M001",
239
+ "M001-VALIDATION.md",
240
+ );
241
+ insertAssessment({
242
+ path: worktreeValidationPath,
243
+ milestoneId: "M001",
244
+ sliceId: null,
245
+ taskId: null,
246
+ status: "pass",
247
+ scope: "milestone-validation",
248
+ fullContent: "---\nverdict: pass\n---\n\n# Validation\nManually overridden via /gsd verdict\n",
249
+ });
250
+ invalidateAllCaches();
251
+
252
+ const ctx = makeMockCtx();
253
+ const pi = makeMockPi();
254
+ const pauseAutoMock = mock.fn(async () => {});
255
+ const s = makeMockSession(tempDir, "validate-milestone", "M001");
256
+
257
+ const result = await runPostUnitVerification({ s, ctx, pi } as VerificationContext, pauseAutoMock);
258
+
259
+ assert.equal(result, "continue");
260
+ assert.equal(pauseAutoMock.mock.callCount(), 0);
261
+ assert.equal(ctx.ui.notify.mock.callCount(), 0);
262
+ });
263
+
225
264
  test("retries when no VALIDATION file exists yet", async () => {
226
265
  insertMilestone({ id: "M001" });
227
266
  insertSlice({ id: "S01", milestoneId: "M001", title: "Slice 1", status: "complete" });