@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
@@ -21,6 +21,7 @@ import { join } from "node:path";
21
21
  import {
22
22
  extractPackageReferences,
23
23
  checkFilePathConsistency,
24
+ checkPlanningArtifactReferences,
24
25
  checkTaskOrdering,
25
26
  checkInterfaceContracts,
26
27
  checkVerificationCommands,
@@ -973,7 +974,12 @@ describe("runPreExecutionChecks", () => {
973
974
  }
974
975
  });
975
976
 
976
- test("resolves .gsd metadata inputs from canonical project root in worktree mode (#5492)", async () => {
977
+ // Supersedes #5492: .gsd metadata inputs used to be accepted in worktree mode
978
+ // by resolving from the canonical project root. Task inputs are source files
979
+ // only (CONTEXT.md "Task Input") — planning artifacts are now blocked with a
980
+ // removal message regardless of where they resolve. The canonical-root
981
+ // resolution itself remains for merged-but-unsynced source files.
982
+ test("blocks .gsd metadata inputs even when resolvable from canonical project root in worktree mode", async () => {
977
983
  const projectRoot = join(tmpdir(), `pre-exec-project-root-${Date.now()}`);
978
984
  const worktreeRoot = join(tmpdir(), `pre-exec-worktree-root-${Date.now()}`);
979
985
  mkdirSync(join(projectRoot, ".gsd"), { recursive: true });
@@ -990,6 +996,35 @@ describe("runPreExecutionChecks", () => {
990
996
  }),
991
997
  ];
992
998
 
999
+ const result = await runPreExecutionChecks(tasks, worktreeRoot, {
1000
+ canonicalProjectRoot: projectRoot,
1001
+ });
1002
+ assert.equal(result.status, "fail");
1003
+ assert.equal(result.checks.length, 1);
1004
+ assert.ok(result.checks[0].message.includes("preloaded as context"));
1005
+ } finally {
1006
+ rmSync(projectRoot, { recursive: true, force: true });
1007
+ rmSync(worktreeRoot, { recursive: true, force: true });
1008
+ }
1009
+ });
1010
+
1011
+ test("resolves source-file inputs from canonical project root in worktree mode (#5492)", async () => {
1012
+ const projectRoot = join(tmpdir(), `pre-exec-project-root-src-${Date.now()}`);
1013
+ const worktreeRoot = join(tmpdir(), `pre-exec-worktree-root-src-${Date.now()}`);
1014
+ mkdirSync(join(projectRoot, "src"), { recursive: true });
1015
+ mkdirSync(worktreeRoot, { recursive: true });
1016
+ writeFileSync(join(projectRoot, "src", "merged.ts"), "// merged upstream");
1017
+
1018
+ try {
1019
+ const tasks = [
1020
+ createTask({
1021
+ id: "T01",
1022
+ files: [],
1023
+ inputs: ["src/merged.ts"],
1024
+ expected_output: [],
1025
+ }),
1026
+ ];
1027
+
993
1028
  const result = await runPreExecutionChecks(tasks, worktreeRoot, {
994
1029
  canonicalProjectRoot: projectRoot,
995
1030
  });
@@ -2263,3 +2298,160 @@ describe("checkFilePathConsistency quote-wrapped annotation (#3747)", () => {
2263
2298
  );
2264
2299
  });
2265
2300
  });
2301
+
2302
+ // ─── Planning Artifact Reference Tests ───────────────────────────────────────
2303
+
2304
+ describe("checkPlanningArtifactReferences", () => {
2305
+ function withTempDir(run: (tempDir: string) => void): void {
2306
+ const tempDir = join(tmpdir(), `pre-exec-artifact-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
2307
+ mkdirSync(tempDir, { recursive: true });
2308
+ try {
2309
+ run(tempDir);
2310
+ } finally {
2311
+ rmSync(tempDir, { recursive: true, force: true });
2312
+ }
2313
+ }
2314
+
2315
+ test("blocks .gsd/ paths in inputs even when the file exists", () => {
2316
+ withTempDir((tempDir) => {
2317
+ const artifactDir = join(tempDir, ".gsd", "milestones", "M001");
2318
+ mkdirSync(artifactDir, { recursive: true });
2319
+ writeFileSync(join(artifactDir, "M001-CONTEXT.md"), "# context");
2320
+
2321
+ const tasks = [
2322
+ createTask({ id: "T01", inputs: [".gsd/milestones/M001/M001-CONTEXT.md"] }),
2323
+ ];
2324
+
2325
+ const results = checkPlanningArtifactReferences(tasks, tempDir);
2326
+ assert.equal(results.length, 1);
2327
+ assert.equal(results[0].blocking, true);
2328
+ assert.ok(results[0].message.includes("preloaded as context"));
2329
+ });
2330
+ });
2331
+
2332
+ test("blocks bare artifact names that do not resolve to a real file, with the truthful message", () => {
2333
+ withTempDir((tempDir) => {
2334
+ const tasks = [createTask({ id: "T01", inputs: ["M001-CONTEXT.md"] })];
2335
+
2336
+ const results = checkPlanningArtifactReferences(tasks, tempDir);
2337
+ assert.equal(results.length, 1);
2338
+ assert.ok(results[0].message.includes("preloaded as context"));
2339
+ assert.ok(!results[0].message.includes("doesn't exist"));
2340
+
2341
+ // The consistency check must not double-report the same entry with the
2342
+ // misleading "doesn't exist" message.
2343
+ const consistency = checkFilePathConsistency(tasks, tempDir);
2344
+ assert.deepEqual(consistency, []);
2345
+ });
2346
+ });
2347
+
2348
+ test("allows a bare artifact-style name that exists as a real source file", () => {
2349
+ withTempDir((tempDir) => {
2350
+ writeFileSync(join(tempDir, "M001-CONTEXT.md"), "# tracked source file");
2351
+
2352
+ const tasks = [createTask({ id: "T01", inputs: ["M001-CONTEXT.md"] })];
2353
+ assert.deepEqual(checkPlanningArtifactReferences(tasks, tempDir), []);
2354
+ });
2355
+ });
2356
+
2357
+ test("leaves artifact-style names with directory components to the existence checks", () => {
2358
+ withTempDir((tempDir) => {
2359
+ const tasks = [createTask({ id: "T01", inputs: ["tests/fixtures/M001-CONTEXT.md"] })];
2360
+
2361
+ assert.deepEqual(checkPlanningArtifactReferences(tasks, tempDir), []);
2362
+ const consistency = checkFilePathConsistency(tasks, tempDir);
2363
+ assert.equal(consistency.length, 1);
2364
+ assert.ok(consistency[0].message.includes("doesn't exist"));
2365
+ });
2366
+ });
2367
+
2368
+ test("blocks .planning/ and .audits/ paths in files", () => {
2369
+ withTempDir((tempDir) => {
2370
+ const tasks = [
2371
+ createTask({ id: "T01", files: [".planning/codebase/STACK.md", ".audits/security.md"] }),
2372
+ ];
2373
+
2374
+ const results = checkPlanningArtifactReferences(tasks, tempDir);
2375
+ assert.equal(results.length, 2);
2376
+ assert.ok(results.every((r) => r.blocking && r.message.includes("never task files")));
2377
+ });
2378
+ });
2379
+
2380
+ test("blocks .gsd/ paths in expectedOutput with the workflow-tools message and no ordering duplicate", () => {
2381
+ withTempDir((tempDir) => {
2382
+ const tasks = [
2383
+ createTask({
2384
+ id: "T01",
2385
+ sequence: 0,
2386
+ expected_output: [".gsd/milestones/M001/M001-SUMMARY.md"],
2387
+ }),
2388
+ createTask({
2389
+ id: "T02",
2390
+ sequence: 1,
2391
+ inputs: [".gsd/milestones/M001/M001-SUMMARY.md"],
2392
+ }),
2393
+ ];
2394
+
2395
+ const results = checkPlanningArtifactReferences(tasks, tempDir);
2396
+ assert.equal(results.length, 2);
2397
+ const outputFinding = results.find((r) => r.message.includes("expectedOutput"));
2398
+ assert.ok(outputFinding);
2399
+ assert.ok(outputFinding.message.includes("written by workflow tools"));
2400
+
2401
+ assert.deepEqual(checkTaskOrdering(tasks, tempDir), []);
2402
+ });
2403
+ });
2404
+
2405
+ test("skips prose, sentinels, and runtime-only entries", () => {
2406
+ withTempDir((tempDir) => {
2407
+ const tasks = [
2408
+ createTask({
2409
+ id: "T01",
2410
+ inputs: ["none", "Current enum shape", "server logs (runtime)"],
2411
+ }),
2412
+ ];
2413
+
2414
+ assert.deepEqual(checkPlanningArtifactReferences(tasks, tempDir), []);
2415
+ });
2416
+ });
2417
+
2418
+ test("runPreExecutionChecks surfaces artifact findings as blocking failures", async () => {
2419
+ const tempDir = join(tmpdir(), `pre-exec-artifact-run-${Date.now()}`);
2420
+ mkdirSync(tempDir, { recursive: true });
2421
+ try {
2422
+ const tasks = [createTask({ id: "T01", inputs: ["M001-CONTEXT.md"] })];
2423
+ const result: PreExecutionResult = await runPreExecutionChecks(tasks, tempDir);
2424
+ assert.equal(result.status, "fail");
2425
+ assert.ok(
2426
+ result.checks.some((c) => !c.passed && c.blocking && c.message.includes("preloaded as context")),
2427
+ );
2428
+ } finally {
2429
+ rmSync(tempDir, { recursive: true, force: true });
2430
+ }
2431
+ });
2432
+
2433
+ test("allows a bare artifact-style name that exists only at canonicalProjectRoot (not at worktree basePath)", () => {
2434
+ withTempDir((canonicalRoot) => {
2435
+ withTempDir((worktreeRoot) => {
2436
+ writeFileSync(join(canonicalRoot, "M001-CONTEXT.md"), "# tracked source file");
2437
+ const tasks = [createTask({ id: "T01", inputs: ["M001-CONTEXT.md"] })];
2438
+ assert.deepEqual(
2439
+ checkPlanningArtifactReferences(tasks, worktreeRoot, { canonicalProjectRoot: canonicalRoot }),
2440
+ [],
2441
+ );
2442
+ });
2443
+ });
2444
+ });
2445
+
2446
+ test("blocks .GSD/ paths with mixed casing (case-insensitive metadata dir match)", () => {
2447
+ withTempDir((tempDir) => {
2448
+ const tasks = [
2449
+ createTask({ id: "T01", inputs: [".GSD/milestones/M001/M001-CONTEXT.md"] }),
2450
+ ];
2451
+ const results = checkPlanningArtifactReferences(tasks, tempDir);
2452
+ assert.equal(results.length, 1);
2453
+ assert.equal(results[0].blocking, true);
2454
+ assert.ok(results[0].message.includes("preloaded as context"));
2455
+ });
2456
+ });
2457
+ });
@@ -3,10 +3,10 @@ import assert from "node:assert/strict";
3
3
 
4
4
  import { classifyError, isTransient } from "../error-classifier.ts";
5
5
  import {
6
- formatProviderErrorGuidance,
7
6
  resolveProviderErrorGuidance,
8
7
  unitTypeToPrefsPhaseKey,
9
8
  } from "../provider-error-guidance.ts";
9
+ import { formatGuidance } from "../guidance.ts";
10
10
 
11
11
  test("classifyError: Cloud Code Assist 400 invalid argument is model-error", () => {
12
12
  const result = classifyError(
@@ -75,8 +75,8 @@ test("resolveProviderErrorGuidance suggests gemini-3-flash for antigravity pro-h
75
75
  assert.ok(guidance.steps.some((step) => step.includes("fallbacks")));
76
76
  });
77
77
 
78
- test("formatProviderErrorGuidance numbers steps", () => {
79
- const text = formatProviderErrorGuidance({
78
+ test("formatGuidance numbers steps", () => {
79
+ const text = formatGuidance({
80
80
  summary: "Provider error on test/model.",
81
81
  steps: ["Change model", "Run /gsd next"],
82
82
  });
@@ -0,0 +1,120 @@
1
+ // gsd-pi — ADR-034 Publication module tests.
2
+ //
3
+ // Exercises publishMilestone against real local git fixtures (a bare repo as
4
+ // the remote) — no network, no gh. The PR path is only tested up to its
5
+ // non-fatal failure contract, since createDraftPullRequestFromEvidence shells
6
+ // out to gh.
7
+
8
+ import test from "node:test";
9
+ import assert from "node:assert/strict";
10
+ import { rmSync } from "node:fs";
11
+ import { join } from "node:path";
12
+
13
+ import { gitRemoteExists, publishMilestone } from "../publication.ts";
14
+ import { git, makeTempDir, makeTempRepo } from "./test-utils.ts";
15
+
16
+ function makeRepoWithBareRemote(): { repo: string; bare: string; cleanup: () => void } {
17
+ const repo = makeTempRepo("gsd-publication-test-");
18
+ const bare = join(makeTempDir("gsd-publication-remote-"), "remote.git");
19
+ git(repo, "init", "--bare", bare);
20
+ git(repo, "remote", "add", "origin", bare);
21
+ return {
22
+ repo,
23
+ bare,
24
+ cleanup: () => {
25
+ rmSync(repo, { recursive: true, force: true });
26
+ rmSync(bare, { recursive: true, force: true });
27
+ },
28
+ };
29
+ }
30
+
31
+ const NO_PUBLISH_PREFS = { autoPush: false, autoPr: false };
32
+
33
+ function makeRequest(repo: string, prefs: { autoPush: boolean; autoPr: boolean; remote?: string; prTargetBranch?: string }) {
34
+ return {
35
+ basePath: repo,
36
+ milestoneId: "M001",
37
+ milestoneTitle: "Test milestone",
38
+ integrationBranch: "main",
39
+ milestoneBranch: "milestone/M001",
40
+ sliceSummaries: ["### S01\nSlice one"],
41
+ nothingToCommit: false,
42
+ prefs,
43
+ };
44
+ }
45
+
46
+ test("gitRemoteExists distinguishes configured from missing remotes", () => {
47
+ const { repo, cleanup } = makeRepoWithBareRemote();
48
+ try {
49
+ assert.equal(gitRemoteExists(repo, "origin"), true);
50
+ assert.equal(gitRemoteExists(repo, "upstream"), false);
51
+ } finally {
52
+ cleanup();
53
+ }
54
+ });
55
+
56
+ test("auto-push pushes the integration branch to the remote", () => {
57
+ const { repo, bare, cleanup } = makeRepoWithBareRemote();
58
+ try {
59
+ const result = publishMilestone(makeRequest(repo, { autoPush: true, autoPr: false }));
60
+ assert.equal(result.pushed, true);
61
+ assert.equal(result.prCreated, false);
62
+ const remoteHeads = git(repo, "ls-remote", "--heads", bare);
63
+ assert.match(remoteHeads, /refs\/heads\/main/);
64
+ } finally {
65
+ cleanup();
66
+ }
67
+ });
68
+
69
+ test("auto-push is suppressed when auto-PR owns the remote interaction", () => {
70
+ const { repo, bare, cleanup } = makeRepoWithBareRemote();
71
+ try {
72
+ git(repo, "branch", "milestone/M001");
73
+ const result = publishMilestone(makeRequest(repo, { autoPush: true, autoPr: true }));
74
+ // PR creation pushes the milestone branch, then fails non-fatally at gh.
75
+ assert.equal(result.pushed, false);
76
+ assert.equal(result.prCreated, false);
77
+ assert.equal(result.prUrl, undefined);
78
+ const remoteHeads = git(repo, "ls-remote", "--heads", bare);
79
+ assert.match(remoteHeads, /refs\/heads\/milestone\/M001/);
80
+ assert.doesNotMatch(remoteHeads, /refs\/heads\/main/);
81
+ } finally {
82
+ cleanup();
83
+ }
84
+ });
85
+
86
+ test("nothing-to-commit short-circuits all publication", () => {
87
+ const { repo, bare, cleanup } = makeRepoWithBareRemote();
88
+ try {
89
+ const result = publishMilestone({
90
+ ...makeRequest(repo, { autoPush: true, autoPr: false }),
91
+ nothingToCommit: true,
92
+ });
93
+ assert.deepEqual(result, { pushed: false, prCreated: false });
94
+ const remoteHeads = git(repo, "ls-remote", "--heads", bare);
95
+ assert.equal(remoteHeads.trim(), "");
96
+ } finally {
97
+ cleanup();
98
+ }
99
+ });
100
+
101
+ test("missing remote makes publication a silent no-op", () => {
102
+ const { repo, cleanup } = makeRepoWithBareRemote();
103
+ try {
104
+ git(repo, "remote", "remove", "origin");
105
+ const result = publishMilestone(makeRequest(repo, { autoPush: true, autoPr: true }));
106
+ assert.deepEqual(result, { pushed: false, prCreated: false });
107
+ } finally {
108
+ cleanup();
109
+ }
110
+ });
111
+
112
+ test("publication disabled returns the empty result without touching git", () => {
113
+ const { repo, cleanup } = makeRepoWithBareRemote();
114
+ try {
115
+ const result = publishMilestone(makeRequest(repo, NO_PUBLISH_PREFS));
116
+ assert.deepEqual(result, { pushed: false, prCreated: false });
117
+ } finally {
118
+ cleanup();
119
+ }
120
+ });
@@ -14,6 +14,8 @@ import { deriveState, invalidateStateCache } from "../state.ts";
14
14
  import {
15
15
  getPendingGate,
16
16
  loadWriteGateSnapshot,
17
+ markApprovalGateVerified,
18
+ markDepthVerified,
17
19
  resetWriteGateState,
18
20
  setPendingGate,
19
21
  shouldBlockContextArtifactSave,
@@ -892,3 +894,158 @@ test("register-hooks agent_end does not re-arm deferred gate after workflow MCP
892
894
  pendingGateId: null,
893
895
  });
894
896
  });
897
+
898
+ // ── External-engine post-hoc gate replay (write-gate two-process sync) ──────
899
+ // On claude-code-cli, pi ingests the SDK turn's tool blocks after the workflow
900
+ // MCP child already executed them. The depth gate can therefore arrive at
901
+ // tool_execution_start AFTER the child verified it and allowed the CONTEXT
902
+ // save; re-arming then wipes the verification and permanently blocks the
903
+ // discuss→auto handoff.
904
+
905
+ function makeHookHarness(): {
906
+ handlers: Map<string, Array<(event: any, ctx?: any) => Promise<any> | any>>;
907
+ pi: any;
908
+ } {
909
+ const handlers = new Map<string, Array<(event: any, ctx?: any) => Promise<any> | any>>();
910
+ const pi = {
911
+ on(event: string, handler: (event: any, ctx?: any) => Promise<any> | any) {
912
+ const existing = handlers.get(event) ?? [];
913
+ existing.push(handler);
914
+ handlers.set(event, existing);
915
+ },
916
+ } as any;
917
+ return { handlers, pi };
918
+ }
919
+
920
+ test("tool_execution_start does not re-arm a depth gate the MCP child already verified", async (t) => {
921
+ const dir = makeTempDir("posthoc-no-rearm");
922
+ resetWriteGateState(dir);
923
+ t.after(() => {
924
+ resetWriteGateState(dir);
925
+ rmSync(dir, { recursive: true, force: true });
926
+ });
927
+
928
+ const { handlers, pi } = makeHookHarness();
929
+ registerHooks(pi, []);
930
+ const ctx = { cwd: dir, ui: { notify: () => undefined } } as any;
931
+
932
+ // The child verified the gate and allowed the CONTEXT save before the host
933
+ // ever saw the tool block.
934
+ markApprovalGateVerified("depth_verification_M002_confirm", dir);
935
+ markDepthVerified("M002", dir);
936
+
937
+ for (const handler of handlers.get("tool_execution_start") ?? []) {
938
+ await handler({
939
+ toolCallId: "t-depth",
940
+ toolName: "mcp__gsd-workflow__ask_user_questions",
941
+ args: { questions: [{ id: "depth_verification_M002_confirm" }] },
942
+ }, ctx);
943
+ }
944
+
945
+ assert.equal(getPendingGate(dir), null, "post-hoc replay must not re-arm a verified gate");
946
+ const snapshot = loadWriteGateSnapshot(dir);
947
+ assert.ok(
948
+ snapshot.verifiedDepthMilestones.includes("M002"),
949
+ "re-arm wipes verifiedDepthMilestones — the verification must survive the replay",
950
+ );
951
+ assert.equal(
952
+ shouldBlockContextArtifactSave("CONTEXT", "M002", null, dir).block,
953
+ false,
954
+ "context saves must stay unlocked after the replayed tool_execution_start",
955
+ );
956
+ });
957
+
958
+ test("tool_execution_start still arms an unverified depth gate", async (t) => {
959
+ const dir = makeTempDir("live-arm");
960
+ resetWriteGateState(dir);
961
+ t.after(() => {
962
+ resetWriteGateState(dir);
963
+ rmSync(dir, { recursive: true, force: true });
964
+ });
965
+
966
+ const { handlers, pi } = makeHookHarness();
967
+ registerHooks(pi, []);
968
+ const ctx = { cwd: dir, ui: { notify: () => undefined } } as any;
969
+
970
+ for (const handler of handlers.get("tool_execution_start") ?? []) {
971
+ await handler({
972
+ toolCallId: "t-depth",
973
+ toolName: "ask_user_questions",
974
+ args: { questions: [{ id: "depth_verification_M002_confirm" }] },
975
+ }, ctx);
976
+ }
977
+
978
+ assert.equal(getPendingGate(dir), "depth_verification_M002_confirm");
979
+ });
980
+
981
+ test("tool_result verifies the gate from result.structuredContent when event.details is missing", async (t) => {
982
+ const dir = makeTempDir("structured-fallback");
983
+ resetWriteGateState(dir);
984
+ t.after(() => {
985
+ resetWriteGateState(dir);
986
+ rmSync(dir, { recursive: true, force: true });
987
+ });
988
+
989
+ const { handlers, pi } = makeHookHarness();
990
+ registerHooks(pi, []);
991
+ const ctx = { cwd: dir, ui: { notify: () => undefined } } as any;
992
+
993
+ setPendingGate("depth_verification_M002_confirm", dir);
994
+
995
+ const questions = [{
996
+ id: "depth_verification_M002_confirm",
997
+ options: [
998
+ { label: "Yes, you got it (Recommended)" },
999
+ { label: "Not quite — let me clarify" },
1000
+ ],
1001
+ }];
1002
+ for (const handler of handlers.get("tool_result") ?? []) {
1003
+ await handler({
1004
+ toolCallId: "t-depth",
1005
+ toolName: "mcp__gsd-workflow__ask_user_questions",
1006
+ input: { questions },
1007
+ // External MCP relay: no pi-native details, structured payload on result.
1008
+ result: {
1009
+ content: [{ type: "text", text: "answered" }],
1010
+ structuredContent: {
1011
+ questions,
1012
+ response: {
1013
+ answers: {
1014
+ depth_verification_M002_confirm: { selected: "Yes, you got it (Recommended)", notes: "" },
1015
+ },
1016
+ },
1017
+ cancelled: false,
1018
+ },
1019
+ },
1020
+ }, ctx);
1021
+ }
1022
+
1023
+ assert.equal(getPendingGate(dir), null, "structured fallback must clear the pending gate");
1024
+ assert.ok(loadWriteGateSnapshot(dir).verifiedDepthMilestones.includes("M002"));
1025
+ });
1026
+
1027
+ test("tool_result without details or structured content leaves the gate pending without crashing", async (t) => {
1028
+ const dir = makeTempDir("no-details");
1029
+ resetWriteGateState(dir);
1030
+ t.after(() => {
1031
+ resetWriteGateState(dir);
1032
+ rmSync(dir, { recursive: true, force: true });
1033
+ });
1034
+
1035
+ const { handlers, pi } = makeHookHarness();
1036
+ registerHooks(pi, []);
1037
+ const ctx = { cwd: dir, ui: { notify: () => undefined } } as any;
1038
+
1039
+ setPendingGate("depth_verification_M002_confirm", dir);
1040
+
1041
+ for (const handler of handlers.get("tool_result") ?? []) {
1042
+ await handler({
1043
+ toolCallId: "t-depth",
1044
+ toolName: "ask_user_questions",
1045
+ input: { questions: [{ id: "depth_verification_M002_confirm" }] },
1046
+ result: { content: [{ type: "text", text: "answered" }] },
1047
+ }, ctx);
1048
+ }
1049
+
1050
+ assert.equal(getPendingGate(dir), "depth_verification_M002_confirm");
1051
+ });
@@ -164,6 +164,7 @@ test("Recovery Classification covers ADR-015 failure families", () => {
164
164
  const cases = [
165
165
  ["invalid tool schema enum", "tool-schema", "stop"],
166
166
  ["Tool Contract failure: complete-slice cannot use gsd_uat_result_save", "tool-contract", "stop"],
167
+ ["No such tool available: mcp__gsd-workflow__gsd_uat_exec", "tool-unavailable", "retry"],
167
168
  ["deterministic policy rejection", "deterministic-policy", "stop"],
168
169
  ["cannot legally advance because required UAT Assessment artifact is missing", "lifecycle-progression", "stop"],
169
170
  ["stale worker lease", "stale-worker", "stop"],
@@ -0,0 +1,70 @@
1
+ // GSD Extension — Stop Notice module tests
2
+ // Locks the emitter↔detector round-trip: every notice the formatters produce
3
+ // must be recognized by the classifiers the headless host uses for exit codes.
4
+
5
+ import { describe, test } from "node:test";
6
+ import assert from "node:assert/strict";
7
+
8
+ import {
9
+ formatStopNoticePrefix,
10
+ isBlockedStopReason,
11
+ stopNoticeDisplayReason,
12
+ stopNoticeKind,
13
+ isTerminalNotice,
14
+ isPauseNotice,
15
+ isBlockedNoticeMessage,
16
+ isManualResolutionNotice,
17
+ PAUSED_NOTICE_PREFIXES,
18
+ TERMINAL_NOTICE_PREFIXES,
19
+ } from "../stop-notice.js";
20
+
21
+ describe("stop notice formatting", () => {
22
+ test("plain stop has no reason suffix", () => {
23
+ assert.equal(formatStopNoticePrefix(), "Auto-mode stopped");
24
+ assert.equal(formatStopNoticePrefix(null), "Auto-mode stopped");
25
+ });
26
+
27
+ test("reason is appended after an em-dash", () => {
28
+ assert.equal(formatStopNoticePrefix("user request"), "Auto-mode stopped — user request");
29
+ });
30
+
31
+ test("Blocked: marker switches the prefix and is stripped from display", () => {
32
+ assert.equal(formatStopNoticePrefix("Blocked: validation gate"), "Auto-mode blocked — validation gate");
33
+ assert.equal(stopNoticeKind("Blocked: x"), "blocked");
34
+ assert.equal(stopNoticeKind("stop"), "stopped");
35
+ assert.ok(isBlockedStopReason("blocked: lowercase too"));
36
+ assert.equal(stopNoticeDisplayReason("Blocked: spaced "), "spaced");
37
+ });
38
+ });
39
+
40
+ describe("emitter↔detector round-trip", () => {
41
+ test("formatted stop notices classify as terminal", () => {
42
+ for (const reason of [undefined, "user request"]) {
43
+ const message = formatStopNoticePrefix(reason).toLowerCase();
44
+ assert.ok(isTerminalNotice(message), `not terminal: ${message}`);
45
+ }
46
+ });
47
+
48
+ test("pause prefixes classify as pause and as blocked (operator intervention)", () => {
49
+ for (const prefix of PAUSED_NOTICE_PREFIXES) {
50
+ assert.ok(isPauseNotice(`${prefix}: provider error`));
51
+ assert.ok(isBlockedNoticeMessage(`${prefix}: provider error`));
52
+ }
53
+ });
54
+
55
+ test("idempotent-advance pauses are non-blocking", () => {
56
+ assert.equal(isBlockedNoticeMessage("auto-mode paused (idempotent advance: unit already active)"), false);
57
+ });
58
+
59
+ test("manual-resolution notices classify as blocked", () => {
60
+ const message = "merge conflict — resolve manually and re-run /gsd auto";
61
+ assert.ok(isManualResolutionNotice(message));
62
+ assert.ok(isBlockedNoticeMessage(message));
63
+ });
64
+
65
+ test("terminal prefixes cover the known stop vocabulary", () => {
66
+ for (const message of ["auto-mode stopped.", "auto-mode complete", "auto-mode idle", "no active milestone"]) {
67
+ assert.ok(TERMINAL_NOTICE_PREFIXES.some((prefix) => message.startsWith(prefix)), message);
68
+ }
69
+ });
70
+ });