@opengsd/gsd-pi 1.2.0-dev.84c56d87 → 1.2.0-dev.9ad8ae33

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 (460) hide show
  1. package/dist/headless-events.js +7 -5
  2. package/dist/mcp-server.js +2 -1
  3. package/dist/resource-loader.d.ts +10 -5
  4. package/dist/resource-loader.js +121 -6
  5. package/dist/resources/.managed-resources-content-hash +1 -1
  6. package/dist/resources/GSD-WORKFLOW.md +5 -4
  7. package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
  8. package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
  9. package/dist/resources/extensions/async-jobs/index.js +65 -0
  10. package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
  11. package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
  12. package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
  13. package/dist/resources/extensions/bg-shell/overlay.js +9 -6
  14. package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
  15. package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
  16. package/dist/resources/extensions/gsd/auto/custom-verify-retry-store.js +17 -2
  17. package/dist/resources/extensions/gsd/auto/detect-stuck.js +33 -13
  18. package/dist/resources/extensions/gsd/auto/dispatch-history.js +105 -0
  19. package/dist/resources/extensions/gsd/auto/dispatch-key.js +37 -0
  20. package/dist/resources/extensions/gsd/auto/loop.js +4 -1
  21. package/dist/resources/extensions/gsd/auto/orchestrator.js +89 -54
  22. package/dist/resources/extensions/gsd/auto/phases.js +49 -6
  23. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  24. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -34
  25. package/dist/resources/extensions/gsd/auto-dispatch.js +50 -58
  26. package/dist/resources/extensions/gsd/auto-model-selection.js +36 -13
  27. package/dist/resources/extensions/gsd/auto-post-unit.js +30 -12
  28. package/dist/resources/extensions/gsd/auto-prompts.js +78 -19
  29. package/dist/resources/extensions/gsd/auto-start.js +35 -15
  30. package/dist/resources/extensions/gsd/auto-unit-closeout.js +45 -21
  31. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +5 -4
  32. package/dist/resources/extensions/gsd/auto-verification.js +23 -30
  33. package/dist/resources/extensions/gsd/auto-worktree.js +14 -1
  34. package/dist/resources/extensions/gsd/auto.js +37 -1
  35. package/dist/resources/extensions/gsd/blocked-models.js +28 -0
  36. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +26 -6
  37. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +23 -6
  38. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -2
  39. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +145 -50
  40. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +302 -80
  41. package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
  42. package/dist/resources/extensions/gsd/closeout-wizard.js +92 -0
  43. package/dist/resources/extensions/gsd/commands/context.js +16 -2
  44. package/dist/resources/extensions/gsd/commands-handlers.js +46 -3
  45. package/dist/resources/extensions/gsd/consent-question.js +353 -0
  46. package/dist/resources/extensions/gsd/consent-verdict.js +63 -0
  47. package/dist/resources/extensions/gsd/constants.js +0 -2
  48. package/dist/resources/extensions/gsd/crash-recovery.js +8 -3
  49. package/dist/resources/extensions/gsd/db/queries.js +26 -0
  50. package/dist/resources/extensions/gsd/db-writer.js +8 -17
  51. package/dist/resources/extensions/gsd/dispatch-guard.js +10 -35
  52. package/dist/resources/extensions/gsd/doctor-engine-checks.js +5 -5
  53. package/dist/resources/extensions/gsd/doctor-git-checks.js +2 -18
  54. package/dist/resources/extensions/gsd/engine-hook-contract.js +70 -0
  55. package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
  56. package/dist/resources/extensions/gsd/files.js +33 -19
  57. package/dist/resources/extensions/gsd/gsd-command-home.js +22 -12
  58. package/dist/resources/extensions/gsd/gsd-db.js +2 -1
  59. package/dist/resources/extensions/gsd/guidance.js +60 -0
  60. package/dist/resources/extensions/gsd/guided-flow.js +6 -3
  61. package/dist/resources/extensions/gsd/markdown-renderer.js +10 -0
  62. package/dist/resources/extensions/gsd/milestone-closeout.js +85 -24
  63. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +2 -2
  64. package/dist/resources/extensions/gsd/milestone-reopen-events.js +3 -5
  65. package/dist/resources/extensions/gsd/parsers-legacy.js +16 -4
  66. package/dist/resources/extensions/gsd/preferences-models.js +2 -2
  67. package/dist/resources/extensions/gsd/projection-flush.js +7 -0
  68. package/dist/resources/extensions/gsd/prompts/complete-slice.md +3 -3
  69. package/dist/resources/extensions/gsd/prompts/execute-task.md +1 -1
  70. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  71. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  72. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -1
  73. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  74. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  75. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  76. package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  77. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  78. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  79. package/dist/resources/extensions/gsd/prompts/run-uat.md +7 -5
  80. package/dist/resources/extensions/gsd/prompts/system.md +5 -2
  81. package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  82. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
  83. package/dist/resources/extensions/gsd/reactive-graph.js +8 -1
  84. package/dist/resources/extensions/gsd/roadmap-slices.js +25 -3
  85. package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
  86. package/dist/resources/extensions/gsd/session-lock.js +1 -1
  87. package/dist/resources/extensions/gsd/state.js +5 -0
  88. package/dist/resources/extensions/gsd/tool-contract.js +14 -3
  89. package/dist/resources/extensions/gsd/tool-presentation-plan.js +4 -4
  90. package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
  91. package/dist/resources/extensions/gsd/tools/complete-slice.js +22 -12
  92. package/dist/resources/extensions/gsd/tools/complete-task.js +3 -2
  93. package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -0
  94. package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -2
  95. package/dist/resources/extensions/gsd/tools/plan-task.js +2 -2
  96. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +2 -2
  97. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
  98. package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -2
  99. package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -2
  100. package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -2
  101. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +67 -2
  102. package/dist/resources/extensions/gsd/uat-policy.js +40 -15
  103. package/dist/resources/extensions/gsd/unit-context-composer.js +65 -0
  104. package/dist/resources/extensions/gsd/verdict-parser.js +1 -1
  105. package/dist/resources/extensions/gsd/verification-verdict.js +2 -1
  106. package/dist/resources/extensions/gsd/workflow-event-ledger.js +91 -0
  107. package/dist/resources/extensions/gsd/workflow-event-vocabulary.js +46 -0
  108. package/dist/resources/extensions/gsd/workflow-events.js +6 -18
  109. package/dist/resources/extensions/gsd/workflow-reconcile.js +21 -56
  110. package/dist/resources/extensions/gsd/worktree-lifecycle.js +3 -2
  111. package/dist/resources/extensions/gsd/worktree-manager.js +7 -1
  112. package/dist/resources/extensions/gsd/worktree.js +8 -1
  113. package/dist/resources/extensions/shared/gsd-browser-cli.js +45 -3
  114. package/dist/resources/shared/gsd-browser-path-sync.js +214 -0
  115. package/dist/resources/shared/package-manager-detection.js +1 -1
  116. package/dist/resources/shared/package.json +3 -0
  117. package/dist/resources/skills/create-skill/SKILL.md +3 -0
  118. package/dist/resources/skills/create-skill/references/skill-structure.md +1 -0
  119. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  120. package/dist/update-check.d.ts +2 -0
  121. package/dist/update-check.js +24 -1
  122. package/dist/update-cmd.js +20 -3
  123. package/dist/web/standalone/.next/BUILD_ID +1 -1
  124. package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
  125. package/dist/web/standalone/.next/build-manifest.json +3 -3
  126. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  127. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  128. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  129. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  135. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  136. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  137. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  144. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  146. package/dist/web/standalone/.next/server/app/index.html +1 -1
  147. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  148. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  149. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  150. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  151. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  153. package/dist/web/standalone/.next/server/app-paths-manifest.json +6 -6
  154. package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
  155. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  156. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  158. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  159. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  160. package/dist/web/standalone/.next/static/chunks/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
  161. package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
  162. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  163. package/dist/web/standalone/node_modules/postcss/lib/container.js +26 -18
  164. package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +47 -14
  165. package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
  166. package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
  167. package/dist/web/standalone/node_modules/postcss/lib/input.js +54 -29
  168. package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +47 -37
  169. package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +26 -9
  170. package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +57 -55
  171. package/dist/web/standalone/node_modules/postcss/lib/node.js +99 -31
  172. package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
  173. package/dist/web/standalone/node_modules/postcss/lib/parser.js +10 -9
  174. package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
  175. package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +30 -11
  176. package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
  177. package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
  178. package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
  179. package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +69 -28
  180. package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +6 -2
  181. package/dist/web/standalone/node_modules/postcss/package.json +48 -48
  182. package/package.json +2 -2
  183. package/packages/cloud-mcp-gateway/package.json +2 -2
  184. package/packages/contracts/dist/rpc.d.ts +1 -0
  185. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  186. package/packages/contracts/dist/rpc.js.map +1 -1
  187. package/packages/contracts/package.json +1 -1
  188. package/packages/daemon/package.json +4 -4
  189. package/packages/gsd-agent-core/package.json +5 -5
  190. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  191. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  192. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +5 -0
  193. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  194. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  195. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +7 -0
  196. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  197. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  198. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
  199. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  200. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  201. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
  202. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  203. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  204. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
  205. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  206. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  207. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
  208. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  209. package/packages/gsd-agent-modes/package.json +7 -7
  210. package/packages/mcp-server/dist/cli.js +10 -5
  211. package/packages/mcp-server/dist/cli.js.map +1 -1
  212. package/packages/mcp-server/dist/moonshot-tool-schema.d.ts +29 -0
  213. package/packages/mcp-server/dist/moonshot-tool-schema.d.ts.map +1 -0
  214. package/packages/mcp-server/dist/moonshot-tool-schema.js +50 -0
  215. package/packages/mcp-server/dist/moonshot-tool-schema.js.map +1 -0
  216. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  217. package/packages/mcp-server/dist/server.js +4 -0
  218. package/packages/mcp-server/dist/server.js.map +1 -1
  219. package/packages/mcp-server/dist/workflow-tools.d.ts +18 -18
  220. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  221. package/packages/mcp-server/dist/workflow-tools.js +99 -38
  222. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  223. package/packages/mcp-server/package.json +5 -4
  224. package/packages/native/package.json +1 -1
  225. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts +1 -0
  226. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
  227. package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
  228. package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
  229. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  230. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  231. package/packages/pi-agent-core/dist/index.js +3 -0
  232. package/packages/pi-agent-core/dist/index.js.map +1 -1
  233. package/packages/pi-agent-core/package.json +1 -1
  234. package/packages/pi-ai/README.md +1 -0
  235. package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
  236. package/packages/pi-ai/dist/image-models.generated.js +6 -6
  237. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  238. package/packages/pi-ai/dist/index.d.ts +2 -0
  239. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  240. package/packages/pi-ai/dist/index.js +2 -0
  241. package/packages/pi-ai/dist/index.js.map +1 -1
  242. package/packages/pi-ai/dist/models.generated.d.ts +419 -221
  243. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  244. package/packages/pi-ai/dist/models.generated.js +460 -261
  245. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  246. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  247. package/packages/pi-ai/dist/providers/anthropic.js +12 -7
  248. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  249. package/packages/pi-ai/dist/providers/google-shared.d.ts +5 -0
  250. package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
  251. package/packages/pi-ai/dist/providers/google-shared.js +12 -3
  252. package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
  253. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  254. package/packages/pi-ai/dist/providers/openai-completions.js +7 -3
  255. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  256. package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts +9 -0
  257. package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts.map +1 -0
  258. package/packages/pi-ai/dist/utils/moonshot-tool-schema.js +34 -0
  259. package/packages/pi-ai/dist/utils/moonshot-tool-schema.js.map +1 -0
  260. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  261. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +6 -2
  262. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  263. package/packages/pi-ai/package.json +3 -2
  264. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
  265. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
  267. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
  269. package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
  270. package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
  271. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
  272. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  273. package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
  274. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  275. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  276. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  277. package/packages/pi-coding-agent/dist/index.js +1 -1
  278. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  279. package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
  280. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  281. package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
  282. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  283. package/packages/pi-coding-agent/package.json +7 -7
  284. package/packages/pi-tui/package.json +2 -2
  285. package/packages/rpc-client/package.json +2 -2
  286. package/pkg/package.json +1 -1
  287. package/src/resources/GSD-WORKFLOW.md +5 -4
  288. package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
  289. package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
  290. package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
  291. package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
  292. package/src/resources/extensions/async-jobs/index.ts +79 -0
  293. package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
  294. package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
  295. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
  296. package/src/resources/extensions/bg-shell/overlay.ts +9 -5
  297. package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
  298. package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
  299. package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
  300. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +40 -1
  301. package/src/resources/extensions/gsd/auto/custom-verify-retry-store.ts +21 -3
  302. package/src/resources/extensions/gsd/auto/detect-stuck.ts +32 -9
  303. package/src/resources/extensions/gsd/auto/dispatch-history.ts +152 -0
  304. package/src/resources/extensions/gsd/auto/dispatch-key.ts +39 -0
  305. package/src/resources/extensions/gsd/auto/loop.ts +4 -1
  306. package/src/resources/extensions/gsd/auto/orchestrator.ts +98 -56
  307. package/src/resources/extensions/gsd/auto/phases.ts +65 -26
  308. package/src/resources/extensions/gsd/auto/session.ts +3 -0
  309. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +18 -48
  310. package/src/resources/extensions/gsd/auto-dispatch.ts +48 -61
  311. package/src/resources/extensions/gsd/auto-model-selection.ts +41 -12
  312. package/src/resources/extensions/gsd/auto-post-unit.ts +33 -12
  313. package/src/resources/extensions/gsd/auto-prompts.ts +115 -35
  314. package/src/resources/extensions/gsd/auto-start.ts +36 -18
  315. package/src/resources/extensions/gsd/auto-unit-closeout.ts +83 -28
  316. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +4 -4
  317. package/src/resources/extensions/gsd/auto-verification.ts +26 -28
  318. package/src/resources/extensions/gsd/auto-worktree.ts +14 -1
  319. package/src/resources/extensions/gsd/auto.ts +44 -1
  320. package/src/resources/extensions/gsd/blocked-models.ts +49 -0
  321. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -5
  322. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +23 -6
  323. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -2
  324. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +163 -55
  325. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +350 -86
  326. package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
  327. package/src/resources/extensions/gsd/closeout-wizard.ts +102 -0
  328. package/src/resources/extensions/gsd/commands/context.ts +16 -2
  329. package/src/resources/extensions/gsd/commands-handlers.ts +46 -3
  330. package/src/resources/extensions/gsd/consent-question.ts +431 -0
  331. package/src/resources/extensions/gsd/consent-verdict.ts +86 -0
  332. package/src/resources/extensions/gsd/constants.ts +0 -3
  333. package/src/resources/extensions/gsd/crash-recovery.ts +10 -2
  334. package/src/resources/extensions/gsd/db/queries.ts +37 -0
  335. package/src/resources/extensions/gsd/db-writer.ts +11 -19
  336. package/src/resources/extensions/gsd/dispatch-guard.ts +8 -31
  337. package/src/resources/extensions/gsd/doctor-engine-checks.ts +5 -4
  338. package/src/resources/extensions/gsd/doctor-git-checks.ts +2 -19
  339. package/src/resources/extensions/gsd/engine-hook-contract.ts +79 -0
  340. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  341. package/src/resources/extensions/gsd/files.ts +33 -12
  342. package/src/resources/extensions/gsd/gsd-command-home.ts +13 -3
  343. package/src/resources/extensions/gsd/gsd-db.ts +4 -3
  344. package/src/resources/extensions/gsd/guidance.ts +78 -0
  345. package/src/resources/extensions/gsd/guided-flow.ts +21 -26
  346. package/src/resources/extensions/gsd/markdown-renderer.ts +11 -0
  347. package/src/resources/extensions/gsd/milestone-closeout.ts +109 -24
  348. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +2 -2
  349. package/src/resources/extensions/gsd/milestone-reopen-events.ts +3 -6
  350. package/src/resources/extensions/gsd/parsers-legacy.ts +16 -4
  351. package/src/resources/extensions/gsd/preferences-models.ts +2 -1
  352. package/src/resources/extensions/gsd/projection-flush.ts +20 -0
  353. package/src/resources/extensions/gsd/prompts/complete-slice.md +3 -3
  354. package/src/resources/extensions/gsd/prompts/execute-task.md +1 -1
  355. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  356. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  357. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -1
  358. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  359. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  360. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  361. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  362. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  363. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  364. package/src/resources/extensions/gsd/prompts/run-uat.md +7 -5
  365. package/src/resources/extensions/gsd/prompts/system.md +5 -2
  366. package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  367. package/src/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
  368. package/src/resources/extensions/gsd/reactive-graph.ts +11 -1
  369. package/src/resources/extensions/gsd/roadmap-slices.ts +28 -3
  370. package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
  371. package/src/resources/extensions/gsd/session-lock.ts +1 -1
  372. package/src/resources/extensions/gsd/state.ts +5 -0
  373. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +97 -1
  374. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +198 -26
  375. package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +65 -3
  376. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +236 -0
  377. package/src/resources/extensions/gsd/tests/blocked-models.test.ts +19 -0
  378. package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
  379. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  380. package/src/resources/extensions/gsd/tests/consent-question.test.ts +351 -0
  381. package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +67 -0
  382. package/src/resources/extensions/gsd/tests/db-writer.test.ts +15 -4
  383. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +10 -10
  384. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
  385. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +12 -2
  386. package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +273 -0
  387. package/src/resources/extensions/gsd/tests/doctor-git-checks-terminal.test.ts +73 -0
  388. package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
  389. package/src/resources/extensions/gsd/tests/engine-hook-contract.test.ts +148 -0
  390. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
  391. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
  392. package/src/resources/extensions/gsd/tests/gsd-command-home.test.ts +120 -0
  393. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +27 -0
  394. package/src/resources/extensions/gsd/tests/guidance.test.ts +23 -0
  395. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +2 -6
  396. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +199 -0
  397. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
  398. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +95 -4
  399. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
  400. package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
  401. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +18 -0
  402. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +138 -0
  403. package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +242 -0
  404. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +63 -2
  405. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +124 -6
  406. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +68 -0
  407. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +19 -1
  408. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +17 -0
  409. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +41 -0
  410. package/src/resources/extensions/gsd/tests/tool-unavailable-retry.test.ts +33 -0
  411. package/src/resources/extensions/gsd/tests/transport-gate-double-complete.test.ts +139 -0
  412. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +88 -0
  413. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +44 -0
  414. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +8 -0
  415. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +2 -0
  416. package/src/resources/extensions/gsd/tests/workflow-events.test.ts +19 -0
  417. package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +20 -0
  418. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +273 -38
  419. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +22 -0
  420. package/src/resources/extensions/gsd/tests/worktree.test.ts +18 -0
  421. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +358 -0
  422. package/src/resources/extensions/gsd/tests/write-gate.test.ts +67 -1
  423. package/src/resources/extensions/gsd/tool-contract.ts +38 -3
  424. package/src/resources/extensions/gsd/tool-presentation-plan.ts +4 -4
  425. package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
  426. package/src/resources/extensions/gsd/tools/complete-slice.ts +22 -12
  427. package/src/resources/extensions/gsd/tools/complete-task.ts +3 -2
  428. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -0
  429. package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -2
  430. package/src/resources/extensions/gsd/tools/plan-task.ts +2 -2
  431. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +2 -2
  432. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
  433. package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -2
  434. package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -2
  435. package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -2
  436. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +81 -2
  437. package/src/resources/extensions/gsd/uat-policy.ts +60 -15
  438. package/src/resources/extensions/gsd/unit-context-composer.ts +99 -0
  439. package/src/resources/extensions/gsd/verdict-parser.ts +1 -1
  440. package/src/resources/extensions/gsd/verification-verdict.ts +4 -2
  441. package/src/resources/extensions/gsd/workflow-event-ledger.ts +131 -0
  442. package/src/resources/extensions/gsd/workflow-event-vocabulary.ts +59 -0
  443. package/src/resources/extensions/gsd/workflow-events.ts +12 -20
  444. package/src/resources/extensions/gsd/workflow-reconcile.ts +29 -62
  445. package/src/resources/extensions/gsd/worktree-lifecycle.ts +3 -8
  446. package/src/resources/extensions/gsd/worktree-manager.ts +6 -1
  447. package/src/resources/extensions/gsd/worktree.ts +7 -1
  448. package/src/resources/extensions/shared/gsd-browser-cli.ts +54 -3
  449. package/src/resources/shared/gsd-browser-path-sync.ts +273 -0
  450. package/src/resources/shared/package-manager-detection.ts +1 -1
  451. package/src/resources/shared/package.json +3 -0
  452. package/src/resources/skills/create-skill/SKILL.md +3 -0
  453. package/src/resources/skills/create-skill/references/skill-structure.md +1 -0
  454. package/dist/resources/extensions/gsd/user-input-boundary.js +0 -218
  455. package/dist/resources/skills/gsd-browser/SKILL.md +0 -41
  456. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +0 -173
  457. package/src/resources/extensions/gsd/user-input-boundary.ts +0 -216
  458. package/src/resources/skills/gsd-browser/SKILL.md +0 -41
  459. /package/dist/web/standalone/.next/static/{AOpDeK_gJHU8OZjRo31gQ → FBNo5cT_chy7YNoAQsU3o}/_buildManifest.js +0 -0
  460. /package/dist/web/standalone/.next/static/{AOpDeK_gJHU8OZjRo31gQ → FBNo5cT_chy7YNoAQsU3o}/_ssgManifest.js +0 -0
@@ -1,12 +1,13 @@
1
1
  import test from "node:test";
2
2
  import assert from "node:assert/strict";
3
- import { mkdtempSync, mkdirSync, rmSync } from "node:fs";
3
+ import { mkdtempSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  import { tmpdir } from "node:os";
6
6
 
7
- import { checkRemoteAutoSession } from "../auto.ts";
7
+ import { checkRemoteAutoSession, forceStopAutoRemote } from "../auto.ts";
8
8
  import { openDatabase, closeDatabase, _getAdapter } from "../gsd-db.ts";
9
- import { registerAutoWorker } from "../db/auto-workers.ts";
9
+ import { getAutoWorker, registerAutoWorker } from "../db/auto-workers.ts";
10
+ import { claimMilestoneLease, getMilestoneLease } from "../db/milestone-leases.ts";
10
11
  import { normalizeRealPath } from "../paths.ts";
11
12
  import { readCrashLock } from "../crash-recovery.ts";
12
13
 
@@ -35,6 +36,29 @@ function setWorkerPid(workerId: string, pid: number): void {
35
36
  ).run({ ":pid": pid, ":worker_id": workerId });
36
37
  }
37
38
 
39
+ function insertMilestone(id: string): void {
40
+ const db = _getAdapter()!;
41
+ db.prepare(
42
+ `INSERT INTO milestones (id, title, status, created_at)
43
+ VALUES (:id, :title, 'active', :created_at)`,
44
+ ).run({
45
+ ":id": id,
46
+ ":title": id,
47
+ ":created_at": new Date().toISOString(),
48
+ });
49
+ }
50
+
51
+ function writeLegacyLock(base: string, pid: number): void {
52
+ const now = new Date().toISOString();
53
+ writeFileSync(join(base, ".gsd", "auto.lock"), JSON.stringify({
54
+ pid,
55
+ startedAt: now,
56
+ unitType: "execute-task",
57
+ unitId: "M001/S01/T01",
58
+ unitStartedAt: now,
59
+ }));
60
+ }
61
+
38
62
  function findDeadPidCandidate(): number {
39
63
  const candidates = [99_999, 199_999, 299_999, 399_999];
40
64
  for (const pid of candidates) {
@@ -62,3 +86,41 @@ test("checkRemoteAutoSession clears stale lock state when lock PID is dead", (t)
62
86
  assert.deepEqual(remote, { running: false });
63
87
  assert.equal(readCrashLock(base), null, "stale lock should be cleared by remote session check");
64
88
  });
89
+
90
+ test("forceStopAutoRemote escalates a live remote PID and releases worker state", (t) => {
91
+ const base = makeBase();
92
+ t.after(() => cleanup(base));
93
+
94
+ openDatabase(join(base, ".gsd", "gsd.db"));
95
+ const workerId = registerAutoWorker({ projectRootRealpath: normalizeRealPath(base) });
96
+ const pid = 424_242;
97
+ setWorkerPid(workerId, pid);
98
+ insertMilestone("M001");
99
+ writeLegacyLock(base, pid);
100
+ const lease = claimMilestoneLease(workerId, "M001");
101
+ assert.equal(lease.ok, true, "precondition: worker holds a milestone lease");
102
+
103
+ const signals: Array<NodeJS.Signals | 0> = [];
104
+ const originalKill = process.kill;
105
+ process.kill = ((target: number, signal?: NodeJS.Signals | number) => {
106
+ assert.equal(target, pid);
107
+ signals.push((signal ?? 0) as NodeJS.Signals | 0);
108
+ return true;
109
+ }) as typeof process.kill;
110
+ t.after(() => {
111
+ process.kill = originalKill;
112
+ });
113
+
114
+ const result = forceStopAutoRemote(base);
115
+
116
+ assert.deepEqual(result, { found: true, pid });
117
+ assert.ok(signals.includes("SIGTERM"), "force stop should request graceful termination first");
118
+ assert.ok(signals.includes("SIGKILL"), "force stop should escalate when the PID is still alive");
119
+ assert.equal(getAutoWorker(workerId)?.status, "stopping");
120
+ assert.equal(
121
+ getMilestoneLease("M001")?.status,
122
+ "released",
123
+ "force stop should release held milestone leases",
124
+ );
125
+ assert.equal(readCrashLock(base), null, "force stop should remove the visible remote lock");
126
+ });
@@ -118,6 +118,51 @@ function makeRepoWithMultipleStrandedMilestones(): string {
118
118
  return base;
119
119
  }
120
120
 
121
+ function makeRepoWithOnlySiblingStrandedAndLockedActive(): string {
122
+ // Locked milestone (M002) is the active row but has NO stranded
123
+ // milestone branch. A sibling milestone (M001) has a stranded branch.
124
+ // A parallel worker locked to M002 must skip the sibling's stranded
125
+ // action entirely — neither block on it nor adopt it.
126
+ const base = mkdtempSync(join(tmpdir(), "gsd-locked-no-stranded-bootstrap-"));
127
+ mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
128
+ mkdirSync(join(base, ".gsd", "milestones", "M002"), { recursive: true });
129
+ // M002 has CONTEXT so bootstrap's pre-planning gate doesn't route to
130
+ // showSmartEntry and the test reaches the post-lock session-init path.
131
+ writeFileSync(
132
+ join(base, ".gsd", "milestones", "M002", "M002-CONTEXT.md"),
133
+ "# M002 context\n",
134
+ );
135
+ writeFileSync(
136
+ join(base, ".gsd", "PREFERENCES.md"),
137
+ "---\ngit:\n isolation: \"none\"\n---\n",
138
+ );
139
+ runGit(base, ["init"]);
140
+ runGit(base, ["config", "user.email", "test@test.com"]);
141
+ runGit(base, ["config", "user.name", "Test"]);
142
+ writeFileSync(join(base, "README.md"), "# test\n");
143
+ runGit(base, ["add", "-A"]);
144
+ runGit(base, ["commit", "-m", "init"]);
145
+ runGit(base, ["branch", "-M", "main"]);
146
+
147
+ // Sibling M001 has stranded work on milestone/M001.
148
+ runGit(base, ["checkout", "-b", "milestone/M001"]);
149
+ writeFileSync(join(base, "m001.txt"), "sibling stranded work\n");
150
+ runGit(base, ["add", "-A"]);
151
+ runGit(base, ["commit", "-m", "feat: M001 in progress"]);
152
+ runGit(base, ["checkout", "main"]);
153
+
154
+ // M002 has no stranded branch at all.
155
+ openDatabase(join(base, ".gsd", "gsd.db"));
156
+ // Both milestones are open so the stranded audit produces a blocking
157
+ // action for the sibling (M001). M002 is the lock target and active
158
+ // row; getActiveMilestoneId honors the lock regardless of M001 order.
159
+ insertMilestone({ id: "M001", title: "Sibling milestone", status: "pending" });
160
+ insertMilestone({ id: "M002", title: "Locked milestone", status: "active" });
161
+ closeDatabase();
162
+
163
+ return base;
164
+ }
165
+
121
166
  function makeRepoWithActiveMismatchAndStrandedTarget(): string {
122
167
  const base = mkdtempSync(join(tmpdir(), "gsd-targeted-stranded-bootstrap-"));
123
168
  mkdirSync(join(base, ".gsd", "milestones", "M001"), { recursive: true });
@@ -455,6 +500,197 @@ test("bootstrap blocks active stranded recovery when another open milestone also
455
500
  }
456
501
  });
457
502
 
503
+ test("parallel worker recovers its locked stranded milestone despite stranded siblings", async () => {
504
+ const base = makeRepoWithMultipleStrandedMilestones();
505
+ const previousCwd = process.cwd();
506
+ const previousLock = process.env.GSD_MILESTONE_LOCK;
507
+ const previousWorker = process.env.GSD_PARALLEL_WORKER;
508
+ const s = new AutoSession();
509
+ const adoptCalls: Array<{ milestoneId: string; mode: string }> = [];
510
+ const notifications: Array<{ message: string; level?: string }> = [];
511
+
512
+ try {
513
+ process.env.GSD_PARALLEL_WORKER = "1";
514
+ process.env.GSD_MILESTONE_LOCK = "M002";
515
+
516
+ const ready = await bootstrapAutoSession(
517
+ s,
518
+ makeCtx(notifications) as any,
519
+ {
520
+ getThinkingLevel: () => "medium",
521
+ getActiveTools: () => [],
522
+ events: { emit: () => {} },
523
+ } as any,
524
+ base,
525
+ false,
526
+ false,
527
+ {
528
+ shouldUseWorktreeIsolation: () => false,
529
+ registerSigtermHandler: () => {},
530
+ registerAutoWorkerForSession: () => {},
531
+ lockBase: () => base,
532
+ buildLifecycle: () => ({
533
+ adoptSessionRoot: (sessionBase: string, originalBase?: string) => {
534
+ s.basePath = sessionBase;
535
+ if (originalBase !== undefined) {
536
+ s.originalBasePath = originalBase;
537
+ } else if (!s.originalBasePath) {
538
+ s.originalBasePath = sessionBase;
539
+ }
540
+ },
541
+ enterMilestone: () => ({ ok: true, mode: "none", path: base }),
542
+ adoptStrandedMilestone: (
543
+ milestoneId: string,
544
+ sessionBase: string,
545
+ _ctx: unknown,
546
+ opts: { mode: "worktree" | "branch" },
547
+ ) => {
548
+ adoptCalls.push({ milestoneId, mode: opts.mode });
549
+ s.basePath = sessionBase;
550
+ s.originalBasePath = sessionBase;
551
+ s.strandedRecoveryIsolationMode = opts.mode;
552
+ return { ok: true, mode: opts.mode, path: sessionBase };
553
+ },
554
+ adoptOrphanWorktree: <T extends { merged: boolean }>(
555
+ _mid: string,
556
+ _base: string,
557
+ run: () => T,
558
+ ): T => run(),
559
+ }) as any,
560
+ },
561
+ {
562
+ classification: "none",
563
+ lock: null,
564
+ pausedSession: null,
565
+ state: null,
566
+ recovery: null,
567
+ recoveryPrompt: null,
568
+ recoveryToolCallCount: 0,
569
+ artifactSatisfied: false,
570
+ hasResumableDiskState: false,
571
+ isBootstrapCrash: false,
572
+ },
573
+ );
574
+
575
+ const messages = notifications.map((entry) => entry.message).join("\n");
576
+ assert.equal(ready, true);
577
+ assert.deepEqual(adoptCalls, [{ milestoneId: "M002", mode: "branch" }]);
578
+ assert.equal(s.currentMilestoneId, "M002");
579
+ assert.match(messages, /Resuming saved milestone work for M002/);
580
+ assert.doesNotMatch(messages, /blocks auto-mode before M002/);
581
+ assert.doesNotMatch(messages, /\/gsd auto M001/);
582
+ } finally {
583
+ if (previousLock === undefined) delete process.env.GSD_MILESTONE_LOCK;
584
+ else process.env.GSD_MILESTONE_LOCK = previousLock;
585
+ if (previousWorker === undefined) delete process.env.GSD_PARALLEL_WORKER;
586
+ else process.env.GSD_PARALLEL_WORKER = previousWorker;
587
+ try {
588
+ closeDatabase();
589
+ } catch {}
590
+ process.chdir(previousCwd);
591
+ rmSync(base, { recursive: true, force: true });
592
+ }
593
+ });
594
+
595
+ test("locked worker with no own stranded action does not adopt sibling stranded action", async () => {
596
+ const base = makeRepoWithOnlySiblingStrandedAndLockedActive();
597
+ const previousCwd = process.cwd();
598
+ const previousLock = process.env.GSD_MILESTONE_LOCK;
599
+ const previousWorker = process.env.GSD_PARALLEL_WORKER;
600
+ const s = new AutoSession();
601
+ const adoptCalls: Array<{ milestoneId: string; mode: string }> = [];
602
+ const enterCalls: string[] = [];
603
+ const notifications: Array<{ message: string; level?: string }> = [];
604
+
605
+ try {
606
+ process.env.GSD_PARALLEL_WORKER = "1";
607
+ process.env.GSD_MILESTONE_LOCK = "M002";
608
+
609
+ const ready = await bootstrapAutoSession(
610
+ s,
611
+ makeCtx(notifications) as any,
612
+ {
613
+ getThinkingLevel: () => "medium",
614
+ getActiveTools: () => [],
615
+ events: { emit: () => {} },
616
+ } as any,
617
+ base,
618
+ false,
619
+ false,
620
+ {
621
+ shouldUseWorktreeIsolation: () => false,
622
+ registerSigtermHandler: () => {},
623
+ registerAutoWorkerForSession: () => {},
624
+ lockBase: () => base,
625
+ buildLifecycle: () => ({
626
+ adoptSessionRoot: (sessionBase: string, originalBase?: string) => {
627
+ s.basePath = sessionBase;
628
+ if (originalBase !== undefined) {
629
+ s.originalBasePath = originalBase;
630
+ } else if (!s.originalBasePath) {
631
+ s.originalBasePath = sessionBase;
632
+ }
633
+ },
634
+ enterMilestone: (mid: string) => {
635
+ enterCalls.push(mid);
636
+ return { ok: true, mode: "none", path: base };
637
+ },
638
+ adoptStrandedMilestone: (
639
+ milestoneId: string,
640
+ sessionBase: string,
641
+ _ctx: unknown,
642
+ opts: { mode: "worktree" | "branch" },
643
+ ) => {
644
+ adoptCalls.push({ milestoneId, mode: opts.mode });
645
+ s.basePath = sessionBase;
646
+ s.originalBasePath = sessionBase;
647
+ s.strandedRecoveryIsolationMode = opts.mode;
648
+ return { ok: true, mode: opts.mode, path: sessionBase };
649
+ },
650
+ adoptOrphanWorktree: <T extends { merged: boolean }>(
651
+ _mid: string,
652
+ _base: string,
653
+ run: () => T,
654
+ ): T => run(),
655
+ }) as any,
656
+ },
657
+ {
658
+ classification: "none",
659
+ lock: null,
660
+ pausedSession: null,
661
+ state: null,
662
+ recovery: null,
663
+ recoveryPrompt: null,
664
+ recoveryToolCallCount: 0,
665
+ artifactSatisfied: false,
666
+ hasResumableDiskState: false,
667
+ isBootstrapCrash: false,
668
+ },
669
+ );
670
+
671
+ const messages = notifications.map((entry) => entry.message).join("\n");
672
+ assert.equal(ready, true);
673
+ // Must not adopt M001 (the sibling stranded action) — the locked
674
+ // worker has no stranded action of its own, so adoption should not
675
+ // run at all. enterMilestone for M002 is also gated off by
676
+ // isolation=none with no stranded recoveryMode (#742 regression).
677
+ assert.deepEqual(adoptCalls, []);
678
+ assert.equal(s.currentMilestoneId, "M002");
679
+ assert.doesNotMatch(messages, /Resuming saved milestone work for M001/);
680
+ assert.doesNotMatch(messages, /blocks auto-mode before M002/);
681
+ } finally {
682
+ if (previousLock === undefined) delete process.env.GSD_MILESTONE_LOCK;
683
+ else process.env.GSD_MILESTONE_LOCK = previousLock;
684
+ if (previousWorker === undefined) delete process.env.GSD_PARALLEL_WORKER;
685
+ else process.env.GSD_PARALLEL_WORKER = previousWorker;
686
+ try {
687
+ closeDatabase();
688
+ } catch {}
689
+ process.chdir(previousCwd);
690
+ rmSync(base, { recursive: true, force: true });
691
+ }
692
+ });
693
+
458
694
  test("bootstrap honors explicit solo milestone lock when recovering stranded target worktree", async () => {
459
695
  const base = makeRepoWithActiveMismatchAndStrandedTarget();
460
696
  const previousCwd = process.cwd();
@@ -8,7 +8,10 @@ import { join } from "node:path";
8
8
 
9
9
  import {
10
10
  blockModel,
11
+ blockModelUntil,
12
+ clearTemporaryModelBlocksForTest,
11
13
  isModelBlocked,
14
+ isModelTemporarilyUnavailable,
12
15
  loadBlockedModels,
13
16
  } from "../blocked-models.ts";
14
17
 
@@ -96,3 +99,19 @@ test("blocked-models: file created under .gsd/runtime/", () => {
96
99
  rmSync(base, { recursive: true, force: true });
97
100
  }
98
101
  });
102
+
103
+ test("blocked-models: temporary rate-limit blocks expire without persisting", () => {
104
+ const base = mkBase();
105
+ try {
106
+ clearTemporaryModelBlocksForTest();
107
+ blockModelUntil(base, "openai-codex", "gpt-5.5", Date.now() + 60_000, "session limit");
108
+ assert.equal(isModelTemporarilyUnavailable(base, "openai-codex", "gpt-5.5"), true);
109
+ assert.equal(loadBlockedModels(base).length, 0, "rate-limit windows must not persist as account blocks");
110
+
111
+ blockModelUntil(base, "openai-codex", "gpt-5.5", Date.now() - 1, "expired");
112
+ assert.equal(isModelTemporarilyUnavailable(base, "openai-codex", "gpt-5.5"), false);
113
+ } finally {
114
+ clearTemporaryModelBlocksForTest();
115
+ rmSync(base, { recursive: true, force: true });
116
+ }
117
+ });
@@ -0,0 +1,144 @@
1
+ import test from "node:test";
2
+ import assert from "node:assert/strict";
3
+
4
+ import {
5
+ prepareBrowserDaemonForUat,
6
+ shouldWarmBrowserDaemonForUat,
7
+ } from "../browser-daemon-auto-prep.ts";
8
+ import { commitBrowserEngineResolution } from "../../browser-tools/engine/selection.ts";
9
+ import { resolveGsdBrowserCliAvailability } from "../../shared/gsd-browser-cli.ts";
10
+
11
+ const GSD_BROWSER_ENGINE = { GSD_BROWSER_ENGINE: "gsd-browser" } as const;
12
+
13
+ test("shouldWarmBrowserDaemonForUat skips artifact-driven UAT", () => {
14
+ assert.equal(
15
+ shouldWarmBrowserDaemonForUat({
16
+ uatType: "artifact-driven",
17
+ sessionProvider: "claude-code",
18
+ projectRoot: "/tmp/project",
19
+ }),
20
+ false,
21
+ );
22
+ });
23
+
24
+ test("shouldWarmBrowserDaemonForUat enables Claude Code browser UAT when gsd-browser is available", (t) => {
25
+ const availability = resolveGsdBrowserCliAvailability();
26
+ if (!availability.available) {
27
+ t.skip("bundled gsd-browser CLI unavailable");
28
+ }
29
+
30
+ assert.equal(
31
+ shouldWarmBrowserDaemonForUat({
32
+ uatType: "browser-executable",
33
+ sessionProvider: "claude-code",
34
+ sessionAuthMode: "externalCli",
35
+ projectRoot: "/tmp/project",
36
+ env: GSD_BROWSER_ENGINE,
37
+ }),
38
+ true,
39
+ );
40
+ });
41
+
42
+ test("shouldWarmBrowserDaemonForUat enables warm-up for Claude Code oauth/apiKey when engine is gsd-browser", (t) => {
43
+ const availability = resolveGsdBrowserCliAvailability();
44
+ if (!availability.available) {
45
+ t.skip("bundled gsd-browser CLI unavailable");
46
+ }
47
+
48
+ for (const sessionAuthMode of ["oauth", "apiKey"] as const) {
49
+ assert.equal(
50
+ shouldWarmBrowserDaemonForUat({
51
+ uatType: "browser-executable",
52
+ sessionProvider: "claude-code",
53
+ sessionAuthMode,
54
+ sessionBaseUrl: "https://api.anthropic.com",
55
+ projectRoot: "/tmp/project",
56
+ env: GSD_BROWSER_ENGINE,
57
+ }),
58
+ true,
59
+ `expected warm-up for sessionAuthMode=${sessionAuthMode}`,
60
+ );
61
+ }
62
+ });
63
+
64
+ test("shouldWarmBrowserDaemonForUat skips legacy Playwright engine for Claude Code", () => {
65
+ assert.equal(
66
+ shouldWarmBrowserDaemonForUat({
67
+ uatType: "browser-executable",
68
+ sessionProvider: "claude-code",
69
+ sessionAuthMode: "oauth",
70
+ projectRoot: "/tmp/project",
71
+ env: { GSD_BROWSER_ENGINE: "legacy" },
72
+ }),
73
+ false,
74
+ );
75
+ });
76
+
77
+ test("shouldWarmBrowserDaemonForUat uses session-committed ambient engine for non-Claude providers", () => {
78
+ const projectRoot = "/tmp/ambient-engine-project";
79
+ commitBrowserEngineResolution(projectRoot, {
80
+ engine: "legacy",
81
+ source: "probe",
82
+ reason: "gsd-browser daemon connect failed (test); using legacy Playwright",
83
+ });
84
+
85
+ assert.equal(
86
+ shouldWarmBrowserDaemonForUat({
87
+ uatType: "browser-executable",
88
+ sessionProvider: "openai",
89
+ projectRoot,
90
+ }),
91
+ false,
92
+ );
93
+ });
94
+
95
+ test("shouldWarmBrowserDaemonForUat skips when browser MCP is disabled", () => {
96
+ assert.equal(
97
+ shouldWarmBrowserDaemonForUat({
98
+ uatType: "browser-executable",
99
+ sessionProvider: "claude-code",
100
+ projectRoot: "/tmp/project",
101
+ env: { GSD_BROWSER_MCP_ENABLED: "0" },
102
+ }),
103
+ false,
104
+ );
105
+ });
106
+
107
+ test("shouldWarmBrowserDaemonForUat skips when warm-up is disabled", () => {
108
+ assert.equal(
109
+ shouldWarmBrowserDaemonForUat({
110
+ uatType: "browser-executable",
111
+ sessionProvider: "claude-code",
112
+ projectRoot: "/tmp/project",
113
+ env: { GSD_BROWSER_WARMUP: "0" },
114
+ }),
115
+ false,
116
+ );
117
+ });
118
+
119
+ test("prepareBrowserDaemonForUat returns null when warm-up is not required", () => {
120
+ assert.equal(
121
+ prepareBrowserDaemonForUat({
122
+ uatType: "artifact-driven",
123
+ sessionProvider: "claude-code",
124
+ sessionAuthMode: "externalCli",
125
+ projectRoot: "/tmp/example-project",
126
+ }),
127
+ null,
128
+ );
129
+ });
130
+
131
+ test("prepareBrowserDaemonForUat returns actionable error when daemon start fails", () => {
132
+ const error = prepareBrowserDaemonForUat({
133
+ uatType: "browser-executable",
134
+ sessionProvider: "claude-code",
135
+ sessionAuthMode: "externalCli",
136
+ projectRoot: "/tmp/example-project",
137
+ env: {
138
+ ...GSD_BROWSER_ENGINE,
139
+ GSD_BROWSER_MCP_COMMAND: "/definitely/missing/gsd-browser",
140
+ },
141
+ });
142
+
143
+ assert.match(error ?? "", /gsd-browser daemon failed to start/i);
144
+ });
@@ -258,6 +258,48 @@ describe('complete-slice verification gate (#3580)', () => {
258
258
  }
259
259
  });
260
260
 
261
+ test('allows a browser UAT declared as a bare keyword under ## UAT Type (M006/S01 format drift)', async () => {
262
+ // Regression: the agent wrote `## UAT Type\nbrowser-executable` (no
263
+ // `- UAT mode:` bullet). The old parser defaulted that to artifact-driven
264
+ // and the gate rejected the slice in a loop.
265
+ const body = [
266
+ '## UAT Type',
267
+ 'browser-executable',
268
+ '',
269
+ '## Smoke Test',
270
+ '1. Open the page in a browser and perform add/edit/complete/delete once.',
271
+ ].join('\n');
272
+ const result = await handleCompleteSlice(
273
+ makeParams({ uatContent: body }),
274
+ basePath,
275
+ );
276
+ if ('error' in result) {
277
+ assert.doesNotMatch(
278
+ result.error,
279
+ /requires browser verification/i,
280
+ `bare browser-executable declaration must pass the browser gate, got: ${result.error}`,
281
+ );
282
+ }
283
+ });
284
+
285
+ test('explains the missing declaration when a browser UAT has no parseable UAT mode', async () => {
286
+ // When nothing was declared, the error must not claim the agent
287
+ // "declared artifact-driven" — it must show the expected bullet format.
288
+ const body = [
289
+ '## Smoke Test',
290
+ '1. Open the page in a browser and perform add/edit/complete/delete once.',
291
+ ].join('\n');
292
+ const result = await handleCompleteSlice(
293
+ makeParams({ uatContent: body }),
294
+ basePath,
295
+ );
296
+ assert.ok('error' in result, 'expected handler to reject an undeclared browser UAT');
297
+ const error = (result as { error: string }).error;
298
+ assert.match(error, /no parseable UAT mode declaration/i);
299
+ assert.match(error, /- UAT mode: browser-executable/);
300
+ assert.doesNotMatch(error, /but declares "UAT mode: artifact-driven"/);
301
+ });
302
+
261
303
  test('allows a browser UAT when it is declared mixed (mixed receives browser tools)', async () => {
262
304
  const body = BROWSER_UAT_BODY.replace('artifact-driven', 'mixed (artifact-driven + browser)');
263
305
  const result = await handleCompleteSlice(