@opengsd/gsd-pi 1.2.0-dev.955e4da0 → 1.2.0-dev.fb12b103

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 (378) hide show
  1. package/dist/cli-style.d.ts +17 -0
  2. package/dist/cli-style.js +28 -0
  3. package/dist/cli.js +1 -1
  4. package/dist/headless-events.d.ts +4 -2
  5. package/dist/headless-events.js +7 -29
  6. package/dist/models-resolver.d.ts +3 -13
  7. package/dist/models-resolver.js +3 -22
  8. package/dist/resource-loader.js +2 -14
  9. package/dist/resources/.managed-resources-content-hash +1 -1
  10. package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
  11. package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
  12. package/dist/resources/extensions/async-jobs/index.js +65 -0
  13. package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
  14. package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
  15. package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
  16. package/dist/resources/extensions/bg-shell/overlay.js +9 -6
  17. package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
  18. package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
  19. package/dist/resources/extensions/bg-shell/utilities.js +3 -0
  20. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +209 -88
  21. package/dist/resources/extensions/browser-tools/engine/selection.js +73 -5
  22. package/dist/resources/extensions/browser-tools/index.js +69 -12
  23. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +30 -4
  24. package/dist/resources/extensions/gsd/auto/orchestrator.js +7 -5
  25. package/dist/resources/extensions/gsd/auto-dispatch.js +12 -1
  26. package/dist/resources/extensions/gsd/auto-model-selection.js +25 -6
  27. package/dist/resources/extensions/gsd/auto-post-unit.js +11 -2
  28. package/dist/resources/extensions/gsd/auto-prompts.js +15 -10
  29. package/dist/resources/extensions/gsd/auto-start.js +15 -10
  30. package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
  31. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +7 -16
  32. package/dist/resources/extensions/gsd/auto-worktree.js +30 -90
  33. package/dist/resources/extensions/gsd/auto.js +4 -13
  34. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +3 -2
  35. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +23 -6
  36. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
  37. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +122 -20
  38. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +6 -2
  39. package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
  40. package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
  41. package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
  42. package/dist/resources/extensions/gsd/captures.js +4 -6
  43. package/dist/resources/extensions/gsd/constants.js +0 -2
  44. package/dist/resources/extensions/gsd/crash-recovery.js +4 -12
  45. package/dist/resources/extensions/gsd/doctor-environment.js +2 -6
  46. package/dist/resources/extensions/gsd/doctor-format.js +9 -6
  47. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +13 -15
  48. package/dist/resources/extensions/gsd/error-classifier.js +9 -0
  49. package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
  50. package/dist/resources/extensions/gsd/guidance.js +98 -0
  51. package/dist/resources/extensions/gsd/guided-flow.js +17 -2
  52. package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
  53. package/dist/resources/extensions/gsd/mcp-tool-name.js +5 -13
  54. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
  55. package/dist/resources/extensions/gsd/migrate/safety.js +4 -1
  56. package/dist/resources/extensions/gsd/notification-store.js +11 -4
  57. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +6 -4
  58. package/dist/resources/extensions/gsd/paths.js +27 -0
  59. package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
  60. package/dist/resources/extensions/gsd/preferences-models.js +14 -48
  61. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  62. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  63. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  64. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  65. package/dist/resources/extensions/gsd/prompts/run-uat.md +1 -1
  66. package/dist/resources/extensions/gsd/prompts/system.md +5 -2
  67. package/dist/resources/extensions/gsd/provider-error-guidance.js +1 -5
  68. package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
  69. package/dist/resources/extensions/gsd/publication.js +87 -0
  70. package/dist/resources/extensions/gsd/recovery-classification.js +37 -94
  71. package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
  72. package/dist/resources/extensions/gsd/state.js +1 -20
  73. package/dist/resources/extensions/gsd/stop-notice.js +57 -0
  74. package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
  75. package/dist/resources/extensions/gsd/tools/exec-tool.js +9 -7
  76. package/dist/resources/extensions/gsd/tools/plan-slice.js +12 -6
  77. package/dist/resources/extensions/gsd/uat-policy.js +2 -1
  78. package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
  79. package/dist/resources/extensions/gsd/unit-context-composer.js +74 -1
  80. package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
  81. package/dist/resources/extensions/gsd/unit-registry.js +337 -0
  82. package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -182
  83. package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
  84. package/dist/resources/extensions/gsd/workflow-tool-surface.js +1 -1
  85. package/dist/resources/extensions/gsd/worktree-git-recovery.js +15 -9
  86. package/dist/resources/extensions/gsd/worktree-root.js +11 -0
  87. package/dist/resources/extensions/gsd/worktree-session-state.js +4 -5
  88. package/dist/resources/extensions/search-the-web/native-search.js +5 -3
  89. package/dist/resources/extensions/shared/browser-contract.js +59 -0
  90. package/dist/resources/extensions/shared/gsd-browser-cli.js +96 -5
  91. package/dist/resources/shared/package.json +3 -0
  92. package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
  93. package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
  94. package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
  95. package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
  96. package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  97. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  98. package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  99. package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
  100. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  101. package/dist/web/standalone/.next/BUILD_ID +1 -1
  102. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  103. package/dist/web/standalone/.next/build-manifest.json +3 -3
  104. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  105. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  112. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  113. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  115. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  122. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  124. package/dist/web/standalone/.next/server/app/index.html +1 -1
  125. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  132. package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
  133. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  134. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  136. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  137. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  138. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  139. package/dist/web/standalone/.next/static/chunks/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
  140. package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
  141. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  142. package/dist/web/standalone/node_modules/postcss/lib/container.js +18 -26
  143. package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +14 -47
  144. package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
  145. package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
  146. package/dist/web/standalone/node_modules/postcss/lib/input.js +29 -54
  147. package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +37 -47
  148. package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +9 -26
  149. package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +55 -57
  150. package/dist/web/standalone/node_modules/postcss/lib/node.js +31 -99
  151. package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
  152. package/dist/web/standalone/node_modules/postcss/lib/parser.js +9 -10
  153. package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
  154. package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +11 -30
  155. package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
  156. package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
  157. package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
  158. package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +28 -69
  159. package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +2 -6
  160. package/dist/web/standalone/node_modules/postcss/package.json +48 -48
  161. package/dist/web/standalone/package.json +1 -1
  162. package/dist/worktree-cli.js +3 -6
  163. package/dist/worktree-status-banner.js +7 -15
  164. package/package.json +1 -1
  165. package/packages/cloud-mcp-gateway/package.json +2 -2
  166. package/packages/contracts/dist/rpc.d.ts +1 -0
  167. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  168. package/packages/contracts/dist/rpc.js.map +1 -1
  169. package/packages/contracts/dist/workflow.d.ts +4 -0
  170. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  171. package/packages/contracts/dist/workflow.js.map +1 -1
  172. package/packages/contracts/package.json +1 -1
  173. package/packages/daemon/package.json +4 -4
  174. package/packages/gsd-agent-core/package.json +5 -5
  175. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  176. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  177. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
  178. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  179. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  180. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +7 -0
  181. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  182. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  183. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
  184. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  185. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  186. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
  187. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  188. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  189. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
  190. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  191. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  192. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
  193. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  194. package/packages/gsd-agent-modes/package.json +7 -7
  195. package/packages/mcp-server/dist/cli.js +6 -3
  196. package/packages/mcp-server/dist/cli.js.map +1 -1
  197. package/packages/mcp-server/dist/workflow-tools.d.ts +8 -0
  198. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  199. package/packages/mcp-server/dist/workflow-tools.js +17 -1
  200. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  201. package/packages/mcp-server/package.json +3 -3
  202. package/packages/native/package.json +1 -1
  203. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts +1 -0
  204. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
  205. package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
  206. package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
  207. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  208. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  209. package/packages/pi-agent-core/dist/index.js +3 -0
  210. package/packages/pi-agent-core/dist/index.js.map +1 -1
  211. package/packages/pi-agent-core/package.json +1 -1
  212. package/packages/pi-ai/dist/models.generated.d.ts +94 -382
  213. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  214. package/packages/pi-ai/dist/models.generated.js +149 -422
  215. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  216. package/packages/pi-ai/package.json +1 -1
  217. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
  218. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  219. package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
  220. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  221. package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
  222. package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
  223. package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
  224. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
  225. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  226. package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
  227. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  228. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  229. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  230. package/packages/pi-coding-agent/dist/index.js +1 -1
  231. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  232. package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
  233. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  234. package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
  235. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  236. package/packages/pi-coding-agent/package.json +7 -7
  237. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  238. package/packages/pi-tui/dist/tui.js +9 -0
  239. package/packages/pi-tui/dist/tui.js.map +1 -1
  240. package/packages/pi-tui/package.json +2 -2
  241. package/packages/rpc-client/package.json +2 -2
  242. package/pkg/package.json +1 -1
  243. package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
  244. package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
  245. package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
  246. package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
  247. package/src/resources/extensions/async-jobs/index.ts +79 -0
  248. package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
  249. package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
  250. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
  251. package/src/resources/extensions/bg-shell/overlay.ts +9 -5
  252. package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
  253. package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
  254. package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
  255. package/src/resources/extensions/bg-shell/utilities.ts +3 -0
  256. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
  257. package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
  258. package/src/resources/extensions/browser-tools/index.ts +71 -13
  259. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
  260. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +29 -1
  261. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
  262. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +34 -4
  263. package/src/resources/extensions/gsd/auto/orchestrator.ts +7 -5
  264. package/src/resources/extensions/gsd/auto-dispatch.ts +12 -0
  265. package/src/resources/extensions/gsd/auto-model-selection.ts +25 -5
  266. package/src/resources/extensions/gsd/auto-post-unit.ts +13 -2
  267. package/src/resources/extensions/gsd/auto-prompts.ts +40 -26
  268. package/src/resources/extensions/gsd/auto-start.ts +15 -10
  269. package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
  270. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +10 -17
  271. package/src/resources/extensions/gsd/auto-worktree.ts +30 -93
  272. package/src/resources/extensions/gsd/auto.ts +8 -15
  273. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +3 -5
  274. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +23 -6
  275. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
  276. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +151 -15
  277. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +6 -2
  278. package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
  279. package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
  280. package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
  281. package/src/resources/extensions/gsd/captures.ts +4 -6
  282. package/src/resources/extensions/gsd/constants.ts +0 -3
  283. package/src/resources/extensions/gsd/crash-recovery.ts +3 -9
  284. package/src/resources/extensions/gsd/doctor-environment.ts +2 -7
  285. package/src/resources/extensions/gsd/doctor-format.ts +12 -7
  286. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +13 -15
  287. package/src/resources/extensions/gsd/error-classifier.ts +11 -0
  288. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  289. package/src/resources/extensions/gsd/guidance.ts +139 -0
  290. package/src/resources/extensions/gsd/guided-flow.ts +16 -2
  291. package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
  292. package/src/resources/extensions/gsd/mcp-tool-name.ts +6 -11
  293. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
  294. package/src/resources/extensions/gsd/migrate/safety.ts +4 -1
  295. package/src/resources/extensions/gsd/notification-store.ts +26 -3
  296. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +6 -4
  297. package/src/resources/extensions/gsd/paths.ts +33 -0
  298. package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
  299. package/src/resources/extensions/gsd/preferences-models.ts +12 -47
  300. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  301. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  302. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  303. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  304. package/src/resources/extensions/gsd/prompts/run-uat.md +1 -1
  305. package/src/resources/extensions/gsd/prompts/system.md +5 -2
  306. package/src/resources/extensions/gsd/provider-error-guidance.ts +4 -9
  307. package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
  308. package/src/resources/extensions/gsd/publication.ts +122 -0
  309. package/src/resources/extensions/gsd/recovery-classification.ts +42 -96
  310. package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
  311. package/src/resources/extensions/gsd/state.ts +4 -21
  312. package/src/resources/extensions/gsd/stop-notice.ts +75 -0
  313. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +22 -0
  314. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +16 -19
  315. package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
  316. package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
  317. package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
  318. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +66 -1
  319. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +22 -0
  320. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +8 -7
  321. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
  322. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
  323. package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
  324. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
  325. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
  326. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
  327. package/src/resources/extensions/gsd/tests/guidance.test.ts +125 -0
  328. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +53 -11
  329. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +73 -58
  330. package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
  331. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
  332. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
  333. package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
  334. package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
  335. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
  336. package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
  337. package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
  338. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +157 -0
  339. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +1 -0
  340. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
  341. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +76 -0
  342. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +8 -0
  343. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +155 -0
  344. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +24 -29
  345. package/src/resources/extensions/gsd/tests/unit-closeout.test.ts +209 -0
  346. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +67 -2
  347. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
  348. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
  349. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
  350. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +2 -2
  351. package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
  352. package/src/resources/extensions/gsd/tools/exec-tool.ts +8 -7
  353. package/src/resources/extensions/gsd/tools/plan-slice.ts +12 -6
  354. package/src/resources/extensions/gsd/uat-policy.ts +2 -1
  355. package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
  356. package/src/resources/extensions/gsd/unit-context-composer.ts +111 -1
  357. package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
  358. package/src/resources/extensions/gsd/unit-registry.ts +412 -0
  359. package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -192
  360. package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
  361. package/src/resources/extensions/gsd/workflow-tool-surface.ts +4 -1
  362. package/src/resources/extensions/gsd/worktree-git-recovery.ts +15 -9
  363. package/src/resources/extensions/gsd/worktree-root.ts +12 -0
  364. package/src/resources/extensions/gsd/worktree-session-state.ts +3 -5
  365. package/src/resources/extensions/search-the-web/native-search.ts +5 -3
  366. package/src/resources/extensions/shared/browser-contract.ts +66 -0
  367. package/src/resources/extensions/shared/gsd-browser-cli.ts +119 -5
  368. package/src/resources/shared/package.json +3 -0
  369. package/src/resources/skills/create-skill/references/executable-code.md +1 -1
  370. package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
  371. package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
  372. package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
  373. package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  374. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  375. package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  376. package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
  377. /package/dist/web/standalone/.next/static/{C24pqUd-aru-l0Dp0gLZP → mU4QIDlpVHDdjDpeEKh5W}/_buildManifest.js +0 -0
  378. /package/dist/web/standalone/.next/static/{C24pqUd-aru-l0Dp0gLZP → mU4QIDlpVHDdjDpeEKh5W}/_ssgManifest.js +0 -0
@@ -0,0 +1,163 @@
1
+ // gsd-pi — ADR-033 Unit Registry parity guard.
2
+ //
3
+ // Pins every view derived from UNIT_REGISTRY to the exact values the
4
+ // hand-maintained tables held before the registry existed. A failure here
5
+ // means a registry edit changed a derived surface — intended changes update
6
+ // the pinned expectation in the same diff.
7
+
8
+ import test from "node:test";
9
+ import assert from "node:assert/strict";
10
+
11
+ import {
12
+ KNOWN_UNIT_TYPES,
13
+ UNIT_REGISTRY,
14
+ EXECUTE_TASK_UNIT_TYPES,
15
+ SECTION_CLOSE_GATE_UNIT_TYPES,
16
+ getUnitDescriptor,
17
+ getUnitPhaseChain,
18
+ } from "../unit-registry.ts";
19
+ import {
20
+ AUTO_UNIT_SCOPED_TOOLS,
21
+ UNIT_TOOL_CONTRACTS,
22
+ getUnitToolSurfaceContract,
23
+ } from "../unit-tool-contracts.ts";
24
+ import { UNIT_MANIFESTS } from "../unit-context-manifest.ts";
25
+ import { phaseChainForUnit } from "../preferences-models.ts";
26
+
27
+ // ─── Pinned pre-registry values ───────────────────────────────────────────
28
+
29
+ const EXPECTED_KNOWN_UNIT_TYPES = [
30
+ "research-milestone",
31
+ "plan-milestone",
32
+ "discuss-milestone",
33
+ "validate-milestone",
34
+ "complete-milestone",
35
+ "research-slice",
36
+ "plan-slice",
37
+ "refine-slice",
38
+ "replan-slice",
39
+ "complete-slice",
40
+ "reassess-roadmap",
41
+ "execute-task",
42
+ "reactive-execute",
43
+ "run-uat",
44
+ "gate-evaluate",
45
+ "rewrite-docs",
46
+ "triage-captures",
47
+ "quick-task",
48
+ "workflow-preferences",
49
+ "discuss-project",
50
+ "discuss-requirements",
51
+ "research-decision",
52
+ "research-project",
53
+ ];
54
+
55
+ // The contract table carried two keys KNOWN_UNIT_TYPES never had (variants)
56
+ // and lacked two it did have (sidecars without contracts).
57
+ const EXPECTED_CONTRACT_ONLY_TYPES = ["discuss-slice", "execute-task-simple"];
58
+ const EXPECTED_CONTRACT_LESS_TYPES = ["triage-captures", "quick-task"];
59
+
60
+ const EXPECTED_EXECUTE_TASK_SET = ["execute-task", "execute-task-simple", "reactive-execute"];
61
+ const EXPECTED_SECTION_CLOSE_SET = [
62
+ ...EXPECTED_EXECUTE_TASK_SET,
63
+ "complete-slice",
64
+ "validate-milestone",
65
+ ];
66
+
67
+ const EXPECTED_PHASE_CHAINS: Record<string, string[] | undefined> = {
68
+ "research-milestone": ["research"],
69
+ "research-slice": ["research"],
70
+ "research-project": ["research"],
71
+ "plan-milestone": ["planning"],
72
+ "plan-slice": ["planning"],
73
+ "refine-slice": ["planning"],
74
+ "replan-slice": ["planning"],
75
+ "discuss-milestone": ["discuss", "planning"],
76
+ "discuss-slice": ["discuss", "planning"],
77
+ "discuss-project": ["discuss", "planning"],
78
+ "discuss-requirements": ["discuss", "planning"],
79
+ "workflow-preferences": ["discuss", "planning"],
80
+ "research-decision": ["discuss", "planning"],
81
+ "execute-task": ["execution"],
82
+ "reactive-execute": ["execution"],
83
+ "execute-task-simple": ["execution_simple", "execution"],
84
+ "complete-slice": ["completion"],
85
+ "complete-milestone": ["completion"],
86
+ "worktree-merge": ["completion"],
87
+ "run-uat": ["uat", "completion"],
88
+ "reassess-roadmap": ["validation", "planning"],
89
+ "rewrite-docs": ["validation", "planning"],
90
+ "gate-evaluate": ["validation", "planning"],
91
+ "validate-milestone": ["validation", "planning"],
92
+ "triage-captures": undefined,
93
+ "quick-task": undefined,
94
+ subagent: ["subagent"],
95
+ "subagent/scout": ["subagent"],
96
+ "no-such-unit": undefined,
97
+ };
98
+
99
+ // ─── Derived-view parity ──────────────────────────────────────────────────
100
+
101
+ test("KNOWN_UNIT_TYPES derives exactly the pre-registry list, in order", () => {
102
+ assert.deepEqual([...KNOWN_UNIT_TYPES], EXPECTED_KNOWN_UNIT_TYPES);
103
+ });
104
+
105
+ test("UNIT_TOOL_CONTRACTS keeps the pre-registry key set, asymmetries included", () => {
106
+ const contractKeys = Object.keys(UNIT_TOOL_CONTRACTS);
107
+ for (const variant of EXPECTED_CONTRACT_ONLY_TYPES) {
108
+ assert.ok(contractKeys.includes(variant), `variant ${variant} must keep its contract`);
109
+ assert.ok(!KNOWN_UNIT_TYPES.includes(variant as never), `${variant} must stay out of KNOWN_UNIT_TYPES`);
110
+ }
111
+ for (const sidecar of EXPECTED_CONTRACT_LESS_TYPES) {
112
+ assert.ok(!contractKeys.includes(sidecar), `${sidecar} must stay contract-less`);
113
+ assert.equal(getUnitToolSurfaceContract(sidecar), undefined);
114
+ }
115
+ const expectedKeys = [
116
+ ...EXPECTED_KNOWN_UNIT_TYPES.filter((t) => !EXPECTED_CONTRACT_LESS_TYPES.includes(t)),
117
+ ...EXPECTED_CONTRACT_ONLY_TYPES,
118
+ ].sort();
119
+ assert.deepEqual([...contractKeys].sort(), expectedKeys);
120
+ });
121
+
122
+ test("scope-class Sets match the pre-registry hand-maintained Sets", () => {
123
+ assert.deepEqual([...EXECUTE_TASK_UNIT_TYPES].sort(), [...EXPECTED_EXECUTE_TASK_SET].sort());
124
+ assert.deepEqual([...SECTION_CLOSE_GATE_UNIT_TYPES].sort(), [...EXPECTED_SECTION_CLOSE_SET].sort());
125
+ });
126
+
127
+ test("phaseChainForUnit matches the pre-registry switch for every known input", () => {
128
+ for (const [unitType, expected] of Object.entries(EXPECTED_PHASE_CHAINS)) {
129
+ assert.deepEqual(
130
+ phaseChainForUnit(unitType),
131
+ expected,
132
+ `phase chain for ${unitType}`,
133
+ );
134
+ }
135
+ });
136
+
137
+ test("AUTO_UNIT_SCOPED_TOOLS mirrors each contract's allowed tools", () => {
138
+ for (const [unitType, contract] of Object.entries(UNIT_TOOL_CONTRACTS)) {
139
+ assert.deepEqual(AUTO_UNIT_SCOPED_TOOLS[unitType], contract.allowedGsdTools);
140
+ }
141
+ assert.deepEqual(
142
+ Object.keys(AUTO_UNIT_SCOPED_TOOLS).sort(),
143
+ Object.keys(UNIT_TOOL_CONTRACTS).sort(),
144
+ );
145
+ });
146
+
147
+ // ─── Registry-internal coherence ──────────────────────────────────────────
148
+
149
+ test("every primary unit type has a manifest; manifests cover nothing else", () => {
150
+ const manifestKeys = Object.keys(UNIT_MANIFESTS).sort();
151
+ assert.deepEqual(manifestKeys, [...KNOWN_UNIT_TYPES].sort());
152
+ });
153
+
154
+ test("every registry row is reachable through the descriptor accessor", () => {
155
+ for (const unitType of Object.keys(UNIT_REGISTRY)) {
156
+ const descriptor = getUnitDescriptor(unitType);
157
+ assert.ok(descriptor, `descriptor for ${unitType}`);
158
+ assert.ok(["primary", "variant"].includes(descriptor.kind));
159
+ assert.ok(["execute-task", "section-close", "standard"].includes(descriptor.scopeClass));
160
+ assert.equal(getUnitPhaseChain(unitType), descriptor.phaseChain);
161
+ }
162
+ assert.equal(getUnitDescriptor("no-such-unit"), undefined);
163
+ });
@@ -15,6 +15,10 @@ function scaffoldProject(root: string, pkg: Record<string, unknown>): void {
15
15
  writeFileSync(join(root, "package.json"), JSON.stringify(pkg, null, 2));
16
16
  }
17
17
 
18
+ const LEGACY_ENGINE = { engine: "legacy", source: "probe", reason: "test" } as const;
19
+ const MANAGED_ENGINE = { engine: "gsd-browser", source: "probe", reason: "test" } as const;
20
+ const OFF_ENGINE = { engine: "off", source: "env", reason: "test" } as const;
21
+
18
22
  describe("web-app-uat guidance", () => {
19
23
  test("returns null for non-web projects", () => {
20
24
  const root = mkdtempSync(join(tmpdir(), "gsd-web-uat-"));
@@ -36,15 +40,54 @@ describe("web-app-uat guidance", () => {
36
40
  scripts: { dev: "vite" },
37
41
  });
38
42
  assert.equal(detectWebApp(root), true);
39
- const block = buildWebAppUatGuidanceBlock(root);
43
+ const block = buildWebAppUatGuidanceBlock(root, LEGACY_ENGINE);
40
44
  assert.ok(block);
41
45
  assert.match(block!, /browser-executable/);
46
+ assert.match(block!, /Playwright-backed `browser_\*` tools/);
42
47
  assert.match(block!, /Playwright scaffolding/);
43
48
  } finally {
44
49
  rmSync(root, { recursive: true, force: true });
45
50
  }
46
51
  });
47
52
 
53
+ test("describes the managed gsd-browser engine when it is the resolved backing", () => {
54
+ const root = mkdtempSync(join(tmpdir(), "gsd-web-uat-"));
55
+ try {
56
+ scaffoldProject(root, {
57
+ dependencies: { react: "19.0.0" },
58
+ scripts: { dev: "vite" },
59
+ });
60
+ const block = buildWebAppUatGuidanceBlock(root, MANAGED_ENGINE);
61
+ assert.ok(block);
62
+ assert.match(block!, /managed gsd-browser engine/);
63
+ assert.match(block!, /browser-executable/);
64
+ assert.doesNotMatch(block!, /Playwright-backed/);
65
+ } finally {
66
+ rmSync(root, { recursive: true, force: true });
67
+ }
68
+ });
69
+
70
+ test("steers to runtime-executable UAT when browser tools are off", () => {
71
+ const root = mkdtempSync(join(tmpdir(), "gsd-web-uat-"));
72
+ try {
73
+ scaffoldProject(root, {
74
+ dependencies: { react: "19.0.0" },
75
+ scripts: { dev: "vite" },
76
+ });
77
+ const block = buildWebAppUatGuidanceBlock(root, OFF_ENGINE);
78
+ assert.ok(block);
79
+ assert.match(block!, /browser tools are disabled/);
80
+ assert.doesNotMatch(block!, /- `browser-executable`/);
81
+ // mixed/live-runtime require browser tools per UAT_MODE_POLICIES, so the
82
+ // bullet must drop out too — recommending them would dead-end at dispatch.
83
+ assert.doesNotMatch(block!, /- `mixed`/);
84
+ assert.doesNotMatch(block!, /interactive `browser_\*` checks/);
85
+ assert.match(block!, /runtime-executable/);
86
+ } finally {
87
+ rmSync(root, { recursive: true, force: true });
88
+ }
89
+ });
90
+
48
91
  test("detects existing Playwright and npm script", () => {
49
92
  const root = mkdtempSync(join(tmpdir(), "gsd-web-uat-"));
50
93
  try {
@@ -495,8 +495,8 @@ test("workflow MCP launch config reaches mutation tools over stdio", async () =>
495
495
  estimate: "10m",
496
496
  files: ["src/resources/extensions/gsd/workflow-mcp.ts"],
497
497
  verify: "node --test",
498
- inputs: [".gsd/milestones/M001/M001-ROADMAP.md"],
499
- expectedOutput: ["S01-PLAN.md", "T01-PLAN.md"],
498
+ inputs: [],
499
+ expectedOutput: ["src/bridge-status.md"],
500
500
  },
501
501
  ],
502
502
  },
@@ -528,8 +528,8 @@ test("executePlanSlice writes task planning state and rendered plan artifacts",
528
528
  estimate: "15m",
529
529
  files: ["src/resources/extensions/gsd/tools/workflow-tool-executors.ts"],
530
530
  verify: "node --test",
531
- inputs: [".gsd/milestones/M001/M001-ROADMAP.md"],
532
- expectedOutput: ["S01-PLAN.md", "T01-PLAN.md"],
531
+ inputs: [],
532
+ expectedOutput: ["src/bridge-status.md"],
533
533
  },
534
534
  ],
535
535
  }, base));
@@ -0,0 +1,76 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Tool Contract module's runtime face — verify the live SDK tool surface covers a Unit's required workflow tools.
3
+
4
+ import { mcpToolMatchesBaseName } from "./mcp-tool-name.js";
5
+ import { getRequiredWorkflowToolsForUnit } from "./unit-tool-contracts.js";
6
+ import { isWorkflowToolSurfaceName } from "./workflow-tool-surface.js";
7
+
8
+ /**
9
+ * Stable phrase recognized as transient by auto-tool-tracking's
10
+ * isToolUnavailableError and error-classifier's transient buckets,
11
+ * which build their matchers from this constant.
12
+ */
13
+ export const TOOL_SURFACE_NOT_READY = "workflow tool surface not ready";
14
+
15
+ /** MCP server statuses that will not self-heal within the session. */
16
+ const TERMINAL_MCP_SERVER_STATUSES = new Set(["failed", "needs-auth", "disabled"]);
17
+
18
+ export interface LiveToolSurfaceObservation {
19
+ /** Tool names the session reported at init (MCP tools appear as mcp__<server>__<tool>). */
20
+ tools: readonly string[];
21
+ /** MCP server connection statuses the session reported at init. */
22
+ mcpServers: readonly { name: string; status: string }[];
23
+ }
24
+
25
+ /**
26
+ * Verify the live tool surface observed at SDK session init covers the Unit's
27
+ * required workflow tools. Complements the static pre-dispatch gate
28
+ * (getWorkflowTransportSupportError), which only proves the MCP launch config
29
+ * is discoverable — the workflow server connects asynchronously after session
30
+ * start, so the static gate cannot see whether the tools actually registered.
31
+ *
32
+ * Returns a transient, recovery-classifiable error (kind tool-unavailable →
33
+ * retry) when the workflow server failed or has not yet registered a required
34
+ * tool, so dispatch aborts before the first model turn instead of letting the
35
+ * Unit improvise around "No such tool available". Returns null when no
36
+ * workflow server is part of this session (native tool path), when the Unit
37
+ * requires no workflow tools, or when the surface is ready.
38
+ */
39
+ export function getToolSurfaceReadinessError(input: {
40
+ unitType: string | undefined;
41
+ workflowServerName: string | undefined;
42
+ observation: LiveToolSurfaceObservation;
43
+ }): string | null {
44
+ const { unitType, workflowServerName, observation } = input;
45
+ if (!unitType || !workflowServerName) return null;
46
+
47
+ const required = getRequiredWorkflowToolsForUnit(unitType).filter(isWorkflowToolSurfaceName);
48
+ if (required.length === 0) return null;
49
+
50
+ const server = observation.mcpServers.find((entry) => entry.name === workflowServerName);
51
+ if (!server) {
52
+ return `${TOOL_SURFACE_NOT_READY} for ${unitType}: MCP server "${workflowServerName}" is absent from the init surface (not yet connected): ${required.join(", ")}`;
53
+ }
54
+
55
+ // The SDK does not wait for MCP servers before init — a still-connecting
56
+ // server reports "pending" there routinely, then registers within seconds,
57
+ // usually well before the Unit's first workflow tool call. Aborting on
58
+ // "pending" would fail the common healthy session, so it passes through;
59
+ // a genuine miss after pass-through still surfaces in-session as
60
+ // "No such tool available" and classifies tool-unavailable → bounded retry.
61
+ // Only statuses that cannot self-heal abort here.
62
+ if (server.status !== "connected" && !TERMINAL_MCP_SERVER_STATUSES.has(server.status)) {
63
+ return null;
64
+ }
65
+
66
+ const missing = required.filter(
67
+ (tool) => !observation.tools.some((name) => name === tool || mcpToolMatchesBaseName(name, tool)),
68
+ );
69
+ if (missing.length === 0) return null;
70
+
71
+ const serverDetail =
72
+ server.status === "connected"
73
+ ? `MCP server "${workflowServerName}" is connected but has not registered`
74
+ : `MCP server "${workflowServerName}" status is "${server.status}" and it has not registered`;
75
+ return `${TOOL_SURFACE_NOT_READY} for ${unitType}: ${serverDetail}: ${missing.join(", ")}`;
76
+ }
@@ -11,7 +11,7 @@ import {
11
11
  import { realpathSync } from "node:fs";
12
12
  import path from "node:path";
13
13
  import { isContextModeEnabled, type ContextModeConfig } from "../preferences-types.js";
14
- import { findWorktreeSegment } from "../worktree-root.js";
14
+ import { projectRootFromWorktreePath } from "../worktree-root.js";
15
15
  import { contextModeDisabledResult, type ToolExecutionResult } from "./context-mode-tool-result.js";
16
16
 
17
17
  export interface ExecToolParams {
@@ -202,12 +202,9 @@ function normalizeScanPath(value: string): string {
202
202
 
203
203
  function parseWorktreeBase(baseDir: string): { originalRoot: string; worktreeRoot: string } | null {
204
204
  const normalizedBase = normalizeScanPath(baseDir);
205
- const segment = findWorktreeSegment(normalizedBase);
206
- if (!segment || segment.gsdIdx <= 0) return null;
207
- return {
208
- originalRoot: normalizedBase.slice(0, segment.gsdIdx),
209
- worktreeRoot: normalizedBase,
210
- };
205
+ const originalRoot = projectRootFromWorktreePath(normalizedBase);
206
+ if (!originalRoot) return null;
207
+ return { originalRoot, worktreeRoot: normalizedBase };
211
208
  }
212
209
 
213
210
  function pathInside(parent: string, target: string): boolean {
@@ -427,6 +424,7 @@ function formatResult(result: ExecSandboxResult): ToolExecutionResult {
427
424
  exit_code: result.exit_code,
428
425
  signal: result.signal,
429
426
  timed_out: result.timed_out,
427
+ force_resolved: result.force_resolved,
430
428
  duration_ms: result.duration_ms,
431
429
  stdout_bytes: result.stdout_bytes,
432
430
  stderr_bytes: result.stderr_bytes,
@@ -441,6 +439,9 @@ function formatResult(result: ExecSandboxResult): ToolExecutionResult {
441
439
  }
442
440
 
443
441
  function formatExit(result: ExecSandboxResult): string {
442
+ // force_resolved means a non-closing (D-state) child was force-resolved past its
443
+ // hard deadline rather than observed exiting; distinguish it from a clean timeout.
444
+ if (result.force_resolved) return "timeout(force-killed)";
444
445
  if (result.timed_out) return "timeout";
445
446
  if (result.signal) return `signal:${result.signal}`;
446
447
  if (result.exit_code === null) return "null";
@@ -26,8 +26,9 @@ import { writeManifest } from "../workflow-manifest.js";
26
26
  import { appendEvent } from "../workflow-events.js";
27
27
  import { logWarning } from "../workflow-logger.js";
28
28
  import { validatePathOnlyPlanningFields, validatePlanningPathScope } from "../planning-path-scope.js";
29
- import { checkFilePathConsistency, checkTaskOrdering } from "../pre-execution-checks.js";
29
+ import { runTaskPathChecks } from "../pre-execution-checks.js";
30
30
  import type { TaskRow } from "../db-task-slice-rows.js";
31
+ import { resolveWorktreeProjectRoot } from "../worktree-root.js";
31
32
  import { buildTaskFileName, gsdProjectionRoot } from "../paths.js";
32
33
  import { loadEffectiveGSDPreferences } from "../preferences.js";
33
34
  import { createRepositoryRegistryFromPreferences, defaultRepositoryTargets, type RepositoryRegistry } from "../repository-registry.js";
@@ -268,11 +269,16 @@ function validateTaskPathsBeforePersist(
268
269
  const additionalRoots = allowedRoots
269
270
  .map((root) => resolve(root))
270
271
  .filter((root) => root !== baseRoot);
271
- const context = additionalRoots.length > 0 ? { additionalRoots } : undefined;
272
- const checks = [
273
- ...checkFilePathConsistency(taskRows, basePath, context),
274
- ...checkTaskOrdering(taskRows, basePath, context),
275
- ];
272
+ const resolvedCanonicalRoot = resolve(resolveWorktreeProjectRoot(basePath));
273
+ const canonicalProjectRoot = resolvedCanonicalRoot !== baseRoot ? resolvedCanonicalRoot : undefined;
274
+ const hasContext = additionalRoots.length > 0 || canonicalProjectRoot !== undefined;
275
+ const context = hasContext
276
+ ? {
277
+ ...(additionalRoots.length > 0 ? { additionalRoots } : {}),
278
+ ...(canonicalProjectRoot !== undefined ? { canonicalProjectRoot } : {}),
279
+ }
280
+ : undefined;
281
+ const checks = runTaskPathChecks(taskRows, basePath, context);
276
282
  const blocking = checks.filter((check) => !check.passed && check.blocking);
277
283
 
278
284
  if (blocking.length === 0) return null;
@@ -1,6 +1,7 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Central UAT mode policy for dispatch, tool presentation, and result validation.
3
3
 
4
+ import { hasBrowserContractPrefix } from "../shared/browser-contract.js";
4
5
  import { extractUatType } from "./files.js";
5
6
  import type { UatType } from "./files.js";
6
7
  import { hasBrowserRequiredText } from "./browser-evidence.js";
@@ -126,7 +127,7 @@ export function uatTypeIncludesBrowser(uatType: string | undefined): boolean {
126
127
  export function isUatBrowserToolName(toolName: string): boolean {
127
128
  const parsed = parseMcpToolName(toolName);
128
129
  const canonicalName = parsed?.toolName ?? toolName;
129
- if (canonicalName.startsWith("browser_")) return true;
130
+ if (hasBrowserContractPrefix(canonicalName)) return true;
130
131
  return parsed?.toolName === "*" && parsed.serverName.toLowerCase().includes("browser");
131
132
  }
132
133
 
@@ -0,0 +1,201 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Unit Closeout module — durable completion pipeline behind one seam (ADR-032).
3
+ //
4
+ // `closeUnit` owns what makes a Unit's completion durable. This pass ships the
5
+ // **Interactive Closeout adapter** path: commit the work and compute the
6
+ // Closeout Git Verdict, failing closed (loudly) instead of silently when a
7
+ // non-`none` `git.isolation` preference was never honoured by the session.
8
+ // Motivating failure (2026-06-10): an interactive session under
9
+ // `git.isolation: worktree` completed a milestone with every source file
10
+ // untracked on the integration branch — no commit, no merge, no warning.
11
+ //
12
+ // The interactive adapter only fires on milestone boundaries — the durability
13
+ // gap is the milestone close, and committing at every task/slice would sweep a
14
+ // developer's unrelated working-tree changes. `closeUnit` itself stays general
15
+ // over all boundaries for the pending Auto Closeout adapter re-seat.
16
+ //
17
+ // The auto loop keeps its existing closeout pipeline for now (the Auto
18
+ // Closeout adapter re-seat is the documented next step in ADR-032); the
19
+ // interactive trigger in bootstrap/register-hooks.ts is a no-op while
20
+ // `isAutoActive()`, so auto-mode behaviour is untouched.
21
+ //
22
+ // Re-entrancy is naturally safe: a re-fired completion commits an already-clean
23
+ // tree, which yields `nothing-to-commit`, and `appendNotification` carries its
24
+ // own dedup window — so `closeUnit` keeps no result cache of its own.
25
+
26
+ import { appendNotification, type NotifySeverity } from "./notification-store.js";
27
+ import { readStringField } from "./auto-unit-tool-scope.js";
28
+ import { MILESTONE_BRANCH_PREFIX } from "./branch-patterns.js";
29
+ import { nativeGetCurrentBranch } from "./native-git-bridge.js";
30
+ import { getIsolationMode } from "./preferences.js";
31
+ import { autoCommitCurrentBranch } from "./worktree.js";
32
+ import { logWarning } from "./workflow-logger.js";
33
+
34
+ export type CloseoutBoundary = "task" | "slice" | "milestone";
35
+ export type CloseoutOutcome = "complete" | "failed" | "skipped";
36
+
37
+ /**
38
+ * What git state the closeout found and did.
39
+ *
40
+ * - `committed` — work committed on the current branch (expected under
41
+ * `isolation: none`, and for task/slice boundaries).
42
+ * - `nothing-to-commit` — working tree was already clean.
43
+ * - `milestone-branch` — milestone boundary closed on a `milestone/<MID>`
44
+ * branch; the merge stays owned by worktree tooling.
45
+ * - `isolation-bypassed` — milestone boundary closed outside a milestone
46
+ * worktree/branch while `git.isolation` is
47
+ * `worktree`/`branch`: committed where the work sits
48
+ * and surfaced a Needs Attention notice instead of
49
+ * completing silently.
50
+ * - `commit-failed` — the commit attempt threw; surfaced, never thrown.
51
+ */
52
+ export type CloseoutGitVerdict =
53
+ | "committed"
54
+ | "nothing-to-commit"
55
+ | "milestone-branch"
56
+ | "isolation-bypassed"
57
+ | "commit-failed";
58
+
59
+ export interface UnitCloseoutRequest {
60
+ basePath: string;
61
+ unitType: string;
62
+ /** "M001" | "M001/S01" | "M001/S01/T01" */
63
+ unitId: string;
64
+ boundary: CloseoutBoundary;
65
+ outcome: CloseoutOutcome;
66
+ }
67
+
68
+ export interface UnitCloseoutResult {
69
+ gitVerdict: CloseoutGitVerdict;
70
+ commitMessage: string | null;
71
+ /** The user-facing Needs Attention / status notice, when one was emitted. */
72
+ notice?: string;
73
+ }
74
+
75
+ /** Seam for tests; production callers use the defaults. */
76
+ export interface UnitCloseoutDeps {
77
+ isolationMode(basePath: string): "none" | "worktree" | "branch";
78
+ currentBranch(basePath: string): string | null;
79
+ commit(basePath: string, unitType: string, unitId: string): string | null;
80
+ notify(message: string, severity: NotifySeverity): void;
81
+ }
82
+
83
+ const defaultDeps: UnitCloseoutDeps = {
84
+ isolationMode: (basePath) => getIsolationMode(basePath),
85
+ currentBranch: (basePath) => {
86
+ try {
87
+ return nativeGetCurrentBranch(basePath);
88
+ } catch {
89
+ return null;
90
+ }
91
+ },
92
+ commit: (basePath, unitType, unitId) => autoCommitCurrentBranch(basePath, unitType, unitId),
93
+ notify: (message, severity) => appendNotification(message, severity),
94
+ };
95
+
96
+ export function closeUnit(request: UnitCloseoutRequest, deps: UnitCloseoutDeps = defaultDeps): UnitCloseoutResult {
97
+ let commitMessage: string | null = null;
98
+ let gitVerdict: CloseoutGitVerdict;
99
+ let notice: string | undefined;
100
+
101
+ try {
102
+ commitMessage = deps.commit(request.basePath, request.unitType, request.unitId);
103
+ gitVerdict = commitMessage === null ? "nothing-to-commit" : "committed";
104
+ } catch (err) {
105
+ gitVerdict = "commit-failed";
106
+ notice = `Unit closeout commit failed for ${request.unitId}: ${err instanceof Error ? err.message : String(err)}`;
107
+ logWarning("engine", notice);
108
+ deps.notify(notice, "error");
109
+ }
110
+
111
+ if (request.boundary === "milestone" && gitVerdict !== "commit-failed") {
112
+ const isolation = deps.isolationMode(request.basePath);
113
+ if (isolation !== "none") {
114
+ const branch = deps.currentBranch(request.basePath);
115
+ if (branch?.startsWith(MILESTONE_BRANCH_PREFIX)) {
116
+ gitVerdict = "milestone-branch";
117
+ notice =
118
+ `Milestone ${request.unitId} completed on ${branch}. ` +
119
+ `Merge it to the integration branch with the worktree tooling (/gsd worktree merge).`;
120
+ deps.notify(notice, "info");
121
+ } else {
122
+ gitVerdict = "isolation-bypassed";
123
+ notice =
124
+ `Needs attention: milestone ${request.unitId} completed outside a milestone worktree/branch ` +
125
+ `while git.isolation is "${isolation}" — the isolation preference was not honoured this session. ` +
126
+ (commitMessage
127
+ ? `Work was committed directly on "${branch ?? "the current branch"}".`
128
+ : `The working tree had nothing left to commit on "${branch ?? "the current branch"}".`);
129
+ logWarning("engine", notice);
130
+ deps.notify(notice, "warning");
131
+ }
132
+ }
133
+ }
134
+
135
+ return { gitVerdict, commitMessage, notice };
136
+ }
137
+
138
+ // ─── Interactive Closeout adapter (tool-observation trigger) ─────────────
139
+
140
+ // Canonical closeout tool → boundary. Aliases are canonicalized by the hook.
141
+ // Only the milestone boundary is wired interactively: it is the durability gap
142
+ // that motivated ADR-032, and committing at every task/slice would sweep a
143
+ // developer's unrelated working-tree changes. `closeUnit` still handles every
144
+ // boundary for the pending Auto Closeout adapter re-seat.
145
+ const CLOSEOUT_TOOL_BOUNDARIES: Record<string, CloseoutBoundary> = {
146
+ gsd_complete_milestone: "milestone",
147
+ };
148
+
149
+ // Commit attribution uses the canonical unit types so interactive closeout
150
+ // commits carry the same GSD-Unit evidence trailers the verification prompts
151
+ // look for.
152
+ const BOUNDARY_UNIT_TYPES: Record<CloseoutBoundary, string> = {
153
+ task: "execute-task",
154
+ slice: "complete-slice",
155
+ milestone: "complete-milestone",
156
+ };
157
+
158
+ export function isUnitCloseoutTool(canonicalToolName: string): boolean {
159
+ return canonicalToolName in CLOSEOUT_TOOL_BOUNDARIES;
160
+ }
161
+
162
+ function readId(input: unknown, camel: string, snake: string): string | undefined {
163
+ const value = readStringField(input, camel, snake);
164
+ return value && value.length > 0 ? value : undefined;
165
+ }
166
+
167
+ /**
168
+ * Interactive Closeout adapter entry, called from the host's tool-observation
169
+ * hook for successful closeout tool calls when auto-mode is NOT active.
170
+ * Returns null when the tool input doesn't identify a unit.
171
+ */
172
+ export function runInteractiveUnitCloseout(
173
+ args: { basePath: string; canonicalToolName: string; input: unknown },
174
+ deps: UnitCloseoutDeps = defaultDeps,
175
+ ): UnitCloseoutResult | null {
176
+ const boundary = CLOSEOUT_TOOL_BOUNDARIES[args.canonicalToolName];
177
+ if (!boundary) return null;
178
+
179
+ const milestoneId = readId(args.input, "milestoneId", "milestone_id");
180
+ if (!milestoneId) return null;
181
+ const sliceId = readId(args.input, "sliceId", "slice_id");
182
+ const taskId = readId(args.input, "taskId", "task_id");
183
+
184
+ let unitId = milestoneId;
185
+ if (boundary !== "milestone") {
186
+ if (!sliceId) return null;
187
+ unitId = boundary === "slice" ? `${milestoneId}/${sliceId}` : `${milestoneId}/${sliceId}/${taskId ?? ""}`;
188
+ if (boundary === "task" && !taskId) return null;
189
+ }
190
+
191
+ return closeUnit(
192
+ {
193
+ basePath: args.basePath,
194
+ unitType: BOUNDARY_UNIT_TYPES[boundary],
195
+ unitId,
196
+ boundary,
197
+ outcome: "complete",
198
+ },
199
+ deps,
200
+ );
201
+ }