@opengsd/gsd-pi 1.2.0-dev.5457a158 → 1.2.0-dev.6ccd27b3

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 (651) hide show
  1. package/dist/cli-model-override.d.ts +15 -0
  2. package/dist/cli-model-override.js +21 -0
  3. package/dist/cli.js +1 -18
  4. package/dist/headless-events.js +7 -5
  5. package/dist/loader.js +6 -4
  6. package/dist/mcp-server.js +2 -1
  7. package/dist/register-agent-bundles.d.ts +11 -2
  8. package/dist/register-agent-bundles.js +18 -4
  9. package/dist/resource-loader.d.ts +10 -5
  10. package/dist/resource-loader.js +121 -6
  11. package/dist/resources/.managed-resources-content-hash +1 -1
  12. package/dist/resources/GSD-WORKFLOW.md +5 -4
  13. package/dist/resources/extensions/ask-user-questions.js +3 -2
  14. package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
  15. package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
  16. package/dist/resources/extensions/async-jobs/index.js +65 -0
  17. package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
  18. package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
  19. package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
  20. package/dist/resources/extensions/bg-shell/overlay.js +9 -6
  21. package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
  22. package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
  23. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +209 -88
  24. package/dist/resources/extensions/browser-tools/engine/selection.js +73 -5
  25. package/dist/resources/extensions/browser-tools/index.js +69 -12
  26. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +450 -217
  27. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +33 -1
  28. package/dist/resources/extensions/gsd/auto/closeout.js +215 -0
  29. package/dist/resources/extensions/gsd/auto/custom-verify-retry-store.js +17 -2
  30. package/dist/resources/extensions/gsd/auto/detect-stuck.js +33 -13
  31. package/dist/resources/extensions/gsd/auto/dispatch-history.js +120 -0
  32. package/dist/resources/extensions/gsd/auto/dispatch-key.js +37 -0
  33. package/dist/resources/extensions/gsd/auto/dispatch.js +365 -0
  34. package/dist/resources/extensions/gsd/auto/finalize.js +347 -0
  35. package/dist/resources/extensions/gsd/auto/loop.js +7 -1
  36. package/dist/resources/extensions/gsd/auto/milestone-lease-reclaim.js +56 -0
  37. package/dist/resources/extensions/gsd/auto/orchestrator.js +174 -69
  38. package/dist/resources/extensions/gsd/auto/phase-helpers.js +146 -0
  39. package/dist/resources/extensions/gsd/auto/phases.js +17 -2329
  40. package/dist/resources/extensions/gsd/auto/pre-dispatch.js +534 -0
  41. package/dist/resources/extensions/gsd/auto/session.js +3 -0
  42. package/dist/resources/extensions/gsd/auto/unit-phase.js +694 -0
  43. package/dist/resources/extensions/gsd/auto/workflow-unit-dispatch.js +1 -1
  44. package/dist/resources/extensions/gsd/auto/worktree-safety-phase.js +125 -0
  45. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -34
  46. package/dist/resources/extensions/gsd/auto-dispatch.js +50 -58
  47. package/dist/resources/extensions/gsd/auto-model-selection.js +36 -13
  48. package/dist/resources/extensions/gsd/auto-post-unit.js +30 -12
  49. package/dist/resources/extensions/gsd/auto-prompts.js +78 -19
  50. package/dist/resources/extensions/gsd/auto-start.js +35 -15
  51. package/dist/resources/extensions/gsd/auto-unit-closeout.js +45 -21
  52. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +5 -4
  53. package/dist/resources/extensions/gsd/auto-verification.js +23 -30
  54. package/dist/resources/extensions/gsd/auto-worktree.js +15 -2
  55. package/dist/resources/extensions/gsd/auto.js +41 -2
  56. package/dist/resources/extensions/gsd/blocked-models.js +28 -0
  57. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +26 -6
  58. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +60 -13
  59. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -2
  60. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
  61. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +172 -59
  62. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +302 -80
  63. package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
  64. package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
  65. package/dist/resources/extensions/gsd/closeout-wizard.js +92 -0
  66. package/dist/resources/extensions/gsd/commands/context.js +16 -2
  67. package/dist/resources/extensions/gsd/commands-handlers.js +46 -3
  68. package/dist/resources/extensions/gsd/commands-mcp-status.js +2 -2
  69. package/dist/resources/extensions/gsd/commands-workflow-templates.js +9 -2
  70. package/dist/resources/extensions/gsd/consent-question.js +353 -0
  71. package/dist/resources/extensions/gsd/consent-verdict.js +63 -0
  72. package/dist/resources/extensions/gsd/constants.js +0 -2
  73. package/dist/resources/extensions/gsd/crash-recovery.js +8 -3
  74. package/dist/resources/extensions/gsd/db/queries.js +56 -0
  75. package/dist/resources/extensions/gsd/db-writer.js +8 -17
  76. package/dist/resources/extensions/gsd/dispatch-guard.js +10 -35
  77. package/dist/resources/extensions/gsd/doctor-engine-checks.js +5 -5
  78. package/dist/resources/extensions/gsd/doctor-environment.js +256 -125
  79. package/dist/resources/extensions/gsd/doctor-git-checks.js +2 -18
  80. package/dist/resources/extensions/gsd/engine-hook-contract.js +70 -0
  81. package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
  82. package/dist/resources/extensions/gsd/files.js +33 -19
  83. package/dist/resources/extensions/gsd/gsd-command-home.js +22 -12
  84. package/dist/resources/extensions/gsd/gsd-db.js +2 -1
  85. package/dist/resources/extensions/gsd/guidance.js +60 -0
  86. package/dist/resources/extensions/gsd/guided-flow.js +93 -4
  87. package/dist/resources/extensions/gsd/health-widget.js +87 -28
  88. package/dist/resources/extensions/gsd/markdown-renderer.js +10 -0
  89. package/dist/resources/extensions/gsd/mcp-bridge.js +10 -0
  90. package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
  91. package/dist/resources/extensions/gsd/milestone-closeout.js +85 -24
  92. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +2 -2
  93. package/dist/resources/extensions/gsd/milestone-reopen-events.js +3 -5
  94. package/dist/resources/extensions/gsd/milestone-settlement.js +2 -2
  95. package/dist/resources/extensions/gsd/notifications.js +12 -7
  96. package/dist/resources/extensions/gsd/parsers-legacy.js +16 -4
  97. package/dist/resources/extensions/gsd/preferences-models.js +2 -2
  98. package/dist/resources/extensions/gsd/projection-flush.js +7 -0
  99. package/dist/resources/extensions/gsd/prompts/complete-slice.md +4 -4
  100. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -2
  101. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  102. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  103. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -1
  104. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  105. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  106. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  107. package/dist/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  108. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  109. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  110. package/dist/resources/extensions/gsd/prompts/run-uat.md +9 -5
  111. package/dist/resources/extensions/gsd/prompts/system.md +5 -2
  112. package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  113. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
  114. package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -1
  115. package/dist/resources/extensions/gsd/reactive-graph.js +8 -1
  116. package/dist/resources/extensions/gsd/roadmap-slices.js +25 -3
  117. package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
  118. package/dist/resources/extensions/gsd/session-lock.js +1 -1
  119. package/dist/resources/extensions/gsd/skill-activation.js +3 -6
  120. package/dist/resources/extensions/gsd/state.js +11 -2
  121. package/dist/resources/extensions/gsd/tool-contract.js +14 -3
  122. package/dist/resources/extensions/gsd/tool-presentation-plan.js +4 -4
  123. package/dist/resources/extensions/gsd/tool-surface-readiness.js +83 -31
  124. package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
  125. package/dist/resources/extensions/gsd/tools/complete-slice.js +22 -12
  126. package/dist/resources/extensions/gsd/tools/complete-task.js +65 -2
  127. package/dist/resources/extensions/gsd/tools/exec-tool.js +5 -0
  128. package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -2
  129. package/dist/resources/extensions/gsd/tools/plan-task.js +2 -2
  130. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +2 -2
  131. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +2 -2
  132. package/dist/resources/extensions/gsd/tools/reopen-slice.js +2 -2
  133. package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -2
  134. package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -2
  135. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +67 -2
  136. package/dist/resources/extensions/gsd/uat-policy.js +42 -16
  137. package/dist/resources/extensions/gsd/unit-context-composer.js +65 -0
  138. package/dist/resources/extensions/gsd/unit-registry.js +41 -24
  139. package/dist/resources/extensions/gsd/verdict-parser.js +1 -1
  140. package/dist/resources/extensions/gsd/verification-verdict.js +2 -1
  141. package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
  142. package/dist/resources/extensions/gsd/workflow-event-ledger.js +91 -0
  143. package/dist/resources/extensions/gsd/workflow-event-vocabulary.js +46 -0
  144. package/dist/resources/extensions/gsd/workflow-events.js +6 -18
  145. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +2 -0
  146. package/dist/resources/extensions/gsd/workflow-mcp-readiness-cache.js +105 -0
  147. package/dist/resources/extensions/gsd/workflow-reconcile.js +21 -56
  148. package/dist/resources/extensions/gsd/worktree-lifecycle.js +3 -2
  149. package/dist/resources/extensions/gsd/worktree-manager.js +7 -1
  150. package/dist/resources/extensions/gsd/worktree-safety.js +28 -26
  151. package/dist/resources/extensions/gsd/worktree.js +8 -1
  152. package/dist/resources/extensions/mcp-client/manager.js +6 -1
  153. package/dist/resources/extensions/search-the-web/native-search.js +5 -3
  154. package/dist/resources/extensions/shared/browser-contract.js +59 -0
  155. package/dist/resources/extensions/shared/gsd-browser-cli.js +116 -6
  156. package/dist/resources/shared/gsd-browser-path-sync.js +214 -0
  157. package/dist/resources/shared/package-manager-detection.js +1 -1
  158. package/dist/resources/shared/package.json +3 -0
  159. package/dist/resources/skills/create-skill/SKILL.md +3 -0
  160. package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
  161. package/dist/resources/skills/create-skill/references/skill-structure.md +1 -0
  162. package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
  163. package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
  164. package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
  165. package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  166. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  167. package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  168. package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
  169. package/dist/runtime-checks.d.ts +10 -0
  170. package/dist/runtime-checks.js +27 -0
  171. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  172. package/dist/update-check.d.ts +2 -0
  173. package/dist/update-check.js +24 -1
  174. package/dist/update-cmd.js +20 -3
  175. package/dist/web/standalone/.next/BUILD_ID +1 -1
  176. package/dist/web/standalone/.next/app-path-routes-manifest.json +12 -12
  177. package/dist/web/standalone/.next/build-manifest.json +3 -3
  178. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  179. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  180. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  181. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  182. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  183. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  184. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  185. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  186. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  187. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  188. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  189. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  190. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  191. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  192. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  193. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  194. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  195. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  196. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  198. package/dist/web/standalone/.next/server/app/index.html +1 -1
  199. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  200. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  201. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  202. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  203. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  204. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  205. package/dist/web/standalone/.next/server/app-paths-manifest.json +12 -12
  206. package/dist/web/standalone/.next/server/chunks/8357.js +2 -2
  207. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  209. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  210. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  211. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  212. package/dist/web/standalone/.next/static/chunks/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
  213. package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
  214. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  215. package/dist/web/standalone/package.json +1 -1
  216. package/package.json +3 -3
  217. package/packages/cloud-mcp-gateway/package.json +2 -2
  218. package/packages/contracts/dist/rpc.d.ts +1 -0
  219. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  220. package/packages/contracts/dist/rpc.js.map +1 -1
  221. package/packages/contracts/package.json +1 -1
  222. package/packages/daemon/package.json +4 -4
  223. package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
  224. package/packages/gsd-agent-core/dist/sdk.js +6 -4
  225. package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
  226. package/packages/gsd-agent-core/package.json +5 -5
  227. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  228. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  229. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
  230. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  231. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +13 -0
  232. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  233. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +55 -6
  234. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  235. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +2 -0
  236. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  237. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +34 -5
  238. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  239. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  240. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +7 -0
  241. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  242. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  243. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
  244. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  245. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  246. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
  247. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  248. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +1 -0
  249. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  250. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +12 -0
  251. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  252. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  253. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
  254. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  255. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
  256. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +4 -0
  257. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
  258. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  259. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
  260. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  261. package/packages/gsd-agent-modes/package.json +7 -7
  262. package/packages/mcp-server/README.md +12 -3
  263. package/packages/mcp-server/dist/cli-runner.d.ts +40 -0
  264. package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -0
  265. package/packages/mcp-server/dist/cli-runner.js +137 -0
  266. package/packages/mcp-server/dist/cli-runner.js.map +1 -0
  267. package/packages/mcp-server/dist/cli.js +2 -53
  268. package/packages/mcp-server/dist/cli.js.map +1 -1
  269. package/packages/mcp-server/dist/moonshot-tool-schema.d.ts +29 -0
  270. package/packages/mcp-server/dist/moonshot-tool-schema.d.ts.map +1 -0
  271. package/packages/mcp-server/dist/moonshot-tool-schema.js +50 -0
  272. package/packages/mcp-server/dist/moonshot-tool-schema.js.map +1 -0
  273. package/packages/mcp-server/dist/pid-registry.d.ts +46 -0
  274. package/packages/mcp-server/dist/pid-registry.d.ts.map +1 -0
  275. package/packages/mcp-server/dist/pid-registry.js +452 -0
  276. package/packages/mcp-server/dist/pid-registry.js.map +1 -0
  277. package/packages/mcp-server/dist/probe-mode.d.ts +4 -0
  278. package/packages/mcp-server/dist/probe-mode.d.ts.map +1 -0
  279. package/packages/mcp-server/dist/probe-mode.js +10 -0
  280. package/packages/mcp-server/dist/probe-mode.js.map +1 -0
  281. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  282. package/packages/mcp-server/dist/server.js +4 -0
  283. package/packages/mcp-server/dist/server.js.map +1 -1
  284. package/packages/mcp-server/dist/stdio-watchdog.d.ts +8 -0
  285. package/packages/mcp-server/dist/stdio-watchdog.d.ts.map +1 -0
  286. package/packages/mcp-server/dist/stdio-watchdog.js +40 -0
  287. package/packages/mcp-server/dist/stdio-watchdog.js.map +1 -0
  288. package/packages/mcp-server/dist/workflow-tools.d.ts +18 -18
  289. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  290. package/packages/mcp-server/dist/workflow-tools.js +161 -81
  291. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  292. package/packages/mcp-server/package.json +5 -4
  293. package/packages/native/package.json +1 -1
  294. package/packages/pi-agent-core/dist/agent-loop.js +43 -2
  295. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  296. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts +1 -0
  297. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
  298. package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
  299. package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
  300. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  301. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  302. package/packages/pi-agent-core/dist/index.js +3 -0
  303. package/packages/pi-agent-core/dist/index.js.map +1 -1
  304. package/packages/pi-agent-core/package.json +1 -1
  305. package/packages/pi-ai/README.md +1 -0
  306. package/packages/pi-ai/dist/image-models.generated.d.ts +2 -2
  307. package/packages/pi-ai/dist/image-models.generated.js +6 -6
  308. package/packages/pi-ai/dist/image-models.generated.js.map +1 -1
  309. package/packages/pi-ai/dist/index.d.ts +2 -0
  310. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  311. package/packages/pi-ai/dist/index.js +2 -0
  312. package/packages/pi-ai/dist/index.js.map +1 -1
  313. package/packages/pi-ai/dist/models.generated.d.ts +239 -153
  314. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  315. package/packages/pi-ai/dist/models.generated.js +256 -145
  316. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  317. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  318. package/packages/pi-ai/dist/providers/anthropic.js +12 -7
  319. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  320. package/packages/pi-ai/dist/providers/google-shared.d.ts +5 -0
  321. package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
  322. package/packages/pi-ai/dist/providers/google-shared.js +12 -3
  323. package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
  324. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  325. package/packages/pi-ai/dist/providers/openai-completions.js +7 -3
  326. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  327. package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts +9 -0
  328. package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts.map +1 -0
  329. package/packages/pi-ai/dist/utils/moonshot-tool-schema.js +34 -0
  330. package/packages/pi-ai/dist/utils/moonshot-tool-schema.js.map +1 -0
  331. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  332. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +6 -2
  333. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  334. package/packages/pi-ai/package.json +3 -2
  335. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
  336. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  337. package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
  338. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  339. package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
  340. package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
  341. package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
  342. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  343. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  344. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  345. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  346. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
  347. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  348. package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
  349. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  350. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  351. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  352. package/packages/pi-coding-agent/dist/index.js +1 -1
  353. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  354. package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
  355. package/packages/pi-coding-agent/dist/theme/theme.js +45 -17
  356. package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
  357. package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
  358. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  359. package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
  360. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  361. package/packages/pi-coding-agent/package.json +7 -7
  362. package/packages/pi-tui/dist/index.d.ts +1 -1
  363. package/packages/pi-tui/dist/index.d.ts.map +1 -1
  364. package/packages/pi-tui/dist/index.js +1 -1
  365. package/packages/pi-tui/dist/index.js.map +1 -1
  366. package/packages/pi-tui/dist/terminal-image.d.ts +33 -0
  367. package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -1
  368. package/packages/pi-tui/dist/terminal-image.js +54 -2
  369. package/packages/pi-tui/dist/terminal-image.js.map +1 -1
  370. package/packages/pi-tui/dist/tui.d.ts +8 -0
  371. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  372. package/packages/pi-tui/dist/tui.js +72 -18
  373. package/packages/pi-tui/dist/tui.js.map +1 -1
  374. package/packages/pi-tui/dist/utils.d.ts.map +1 -1
  375. package/packages/pi-tui/dist/utils.js +110 -36
  376. package/packages/pi-tui/dist/utils.js.map +1 -1
  377. package/packages/pi-tui/package.json +2 -2
  378. package/packages/rpc-client/package.json +2 -2
  379. package/pkg/dist/theme/theme.d.ts.map +1 -1
  380. package/pkg/dist/theme/theme.js +45 -17
  381. package/pkg/dist/theme/theme.js.map +1 -1
  382. package/pkg/package.json +1 -1
  383. package/src/resources/GSD-WORKFLOW.md +5 -4
  384. package/src/resources/extensions/ask-user-questions.ts +7 -2
  385. package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
  386. package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
  387. package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
  388. package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
  389. package/src/resources/extensions/async-jobs/index.ts +79 -0
  390. package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
  391. package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
  392. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
  393. package/src/resources/extensions/bg-shell/overlay.ts +9 -5
  394. package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
  395. package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
  396. package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
  397. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
  398. package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
  399. package/src/resources/extensions/browser-tools/index.ts +71 -13
  400. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
  401. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +40 -1
  402. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
  403. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +534 -228
  404. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +672 -7
  405. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +38 -1
  406. package/src/resources/extensions/gsd/auto/closeout.ts +309 -0
  407. package/src/resources/extensions/gsd/auto/custom-verify-retry-store.ts +21 -3
  408. package/src/resources/extensions/gsd/auto/detect-stuck.ts +32 -9
  409. package/src/resources/extensions/gsd/auto/dispatch-history.ts +168 -0
  410. package/src/resources/extensions/gsd/auto/dispatch-key.ts +39 -0
  411. package/src/resources/extensions/gsd/auto/dispatch.ts +449 -0
  412. package/src/resources/extensions/gsd/auto/finalize.ts +445 -0
  413. package/src/resources/extensions/gsd/auto/loop.ts +7 -1
  414. package/src/resources/extensions/gsd/auto/milestone-lease-reclaim.ts +74 -0
  415. package/src/resources/extensions/gsd/auto/orchestrator.ts +193 -71
  416. package/src/resources/extensions/gsd/auto/phase-helpers.ts +199 -0
  417. package/src/resources/extensions/gsd/auto/phases.ts +58 -3022
  418. package/src/resources/extensions/gsd/auto/pre-dispatch.ts +704 -0
  419. package/src/resources/extensions/gsd/auto/session.ts +3 -0
  420. package/src/resources/extensions/gsd/auto/unit-phase.ts +910 -0
  421. package/src/resources/extensions/gsd/auto/workflow-unit-dispatch.ts +1 -1
  422. package/src/resources/extensions/gsd/auto/worktree-safety-phase.ts +149 -0
  423. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +18 -48
  424. package/src/resources/extensions/gsd/auto-dispatch.ts +48 -61
  425. package/src/resources/extensions/gsd/auto-model-selection.ts +41 -12
  426. package/src/resources/extensions/gsd/auto-post-unit.ts +33 -12
  427. package/src/resources/extensions/gsd/auto-prompts.ts +115 -35
  428. package/src/resources/extensions/gsd/auto-start.ts +36 -18
  429. package/src/resources/extensions/gsd/auto-unit-closeout.ts +83 -28
  430. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +4 -4
  431. package/src/resources/extensions/gsd/auto-verification.ts +26 -28
  432. package/src/resources/extensions/gsd/auto-worktree.ts +15 -2
  433. package/src/resources/extensions/gsd/auto.ts +49 -2
  434. package/src/resources/extensions/gsd/blocked-models.ts +49 -0
  435. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +34 -5
  436. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +79 -12
  437. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -2
  438. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
  439. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +211 -59
  440. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +350 -86
  441. package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
  442. package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
  443. package/src/resources/extensions/gsd/closeout-wizard.ts +102 -0
  444. package/src/resources/extensions/gsd/commands/context.ts +16 -2
  445. package/src/resources/extensions/gsd/commands-handlers.ts +46 -3
  446. package/src/resources/extensions/gsd/commands-mcp-status.ts +2 -2
  447. package/src/resources/extensions/gsd/commands-workflow-templates.ts +11 -4
  448. package/src/resources/extensions/gsd/consent-question.ts +431 -0
  449. package/src/resources/extensions/gsd/consent-verdict.ts +86 -0
  450. package/src/resources/extensions/gsd/constants.ts +0 -3
  451. package/src/resources/extensions/gsd/crash-recovery.ts +10 -2
  452. package/src/resources/extensions/gsd/db/queries.ts +66 -0
  453. package/src/resources/extensions/gsd/db-writer.ts +11 -19
  454. package/src/resources/extensions/gsd/dispatch-guard.ts +8 -31
  455. package/src/resources/extensions/gsd/doctor-engine-checks.ts +5 -4
  456. package/src/resources/extensions/gsd/doctor-environment.ts +267 -142
  457. package/src/resources/extensions/gsd/doctor-git-checks.ts +2 -19
  458. package/src/resources/extensions/gsd/engine-hook-contract.ts +79 -0
  459. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  460. package/src/resources/extensions/gsd/files.ts +33 -12
  461. package/src/resources/extensions/gsd/gsd-command-home.ts +13 -3
  462. package/src/resources/extensions/gsd/gsd-db.ts +4 -3
  463. package/src/resources/extensions/gsd/guidance.ts +78 -0
  464. package/src/resources/extensions/gsd/guided-flow.ts +145 -24
  465. package/src/resources/extensions/gsd/health-widget.ts +91 -27
  466. package/src/resources/extensions/gsd/markdown-renderer.ts +11 -0
  467. package/src/resources/extensions/gsd/mcp-bridge.ts +39 -0
  468. package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
  469. package/src/resources/extensions/gsd/milestone-closeout.ts +109 -24
  470. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +2 -2
  471. package/src/resources/extensions/gsd/milestone-reopen-events.ts +3 -6
  472. package/src/resources/extensions/gsd/milestone-settlement.ts +2 -2
  473. package/src/resources/extensions/gsd/notifications.ts +13 -6
  474. package/src/resources/extensions/gsd/parsers-legacy.ts +16 -4
  475. package/src/resources/extensions/gsd/preferences-models.ts +2 -1
  476. package/src/resources/extensions/gsd/projection-flush.ts +20 -0
  477. package/src/resources/extensions/gsd/prompts/complete-slice.md +4 -4
  478. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -2
  479. package/src/resources/extensions/gsd/prompts/plan-milestone.md +1 -1
  480. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  481. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -1
  482. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  483. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  484. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  485. package/src/resources/extensions/gsd/prompts/research-milestone.md +1 -1
  486. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  487. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  488. package/src/resources/extensions/gsd/prompts/run-uat.md +9 -5
  489. package/src/resources/extensions/gsd/prompts/system.md +5 -2
  490. package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  491. package/src/resources/extensions/gsd/prompts/validate-milestone.md +1 -1
  492. package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -1
  493. package/src/resources/extensions/gsd/reactive-graph.ts +11 -1
  494. package/src/resources/extensions/gsd/roadmap-slices.ts +28 -3
  495. package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
  496. package/src/resources/extensions/gsd/session-lock.ts +1 -1
  497. package/src/resources/extensions/gsd/skill-activation.ts +3 -6
  498. package/src/resources/extensions/gsd/state.ts +12 -1
  499. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +1 -1
  500. package/src/resources/extensions/gsd/tests/auto-blocked-remediation-message.test.ts +1 -1
  501. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +206 -22
  502. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +97 -1
  503. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +273 -37
  504. package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +1 -1
  505. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +51 -0
  506. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +2 -1
  507. package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +65 -3
  508. package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +236 -0
  509. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +169 -1
  510. package/src/resources/extensions/gsd/tests/blocked-models.test.ts +19 -0
  511. package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
  512. package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
  513. package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
  514. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  515. package/src/resources/extensions/gsd/tests/complete-task.test.ts +141 -5
  516. package/src/resources/extensions/gsd/tests/consent-question.test.ts +351 -0
  517. package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +67 -0
  518. package/src/resources/extensions/gsd/tests/db-writer.test.ts +15 -4
  519. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +12 -11
  520. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +36 -0
  521. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
  522. package/src/resources/extensions/gsd/tests/discuss-routing-fixes.test.ts +12 -2
  523. package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +328 -0
  524. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
  525. package/src/resources/extensions/gsd/tests/dist-redirect.mjs +8 -0
  526. package/src/resources/extensions/gsd/tests/doctor-git-checks-terminal.test.ts +73 -0
  527. package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
  528. package/src/resources/extensions/gsd/tests/engine-hook-contract.test.ts +148 -0
  529. package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +117 -91
  530. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +113 -0
  531. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
  532. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
  533. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
  534. package/src/resources/extensions/gsd/tests/gsd-command-home.test.ts +120 -0
  535. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +27 -0
  536. package/src/resources/extensions/gsd/tests/guidance.test.ts +23 -0
  537. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +18 -6
  538. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +7 -11
  539. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +35 -58
  540. package/src/resources/extensions/gsd/tests/integration/doctor-environment-async.test.ts +104 -0
  541. package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
  542. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +217 -0
  543. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +47 -16
  544. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
  545. package/src/resources/extensions/gsd/tests/mcp-readiness-preflight.test.ts +205 -0
  546. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +6 -5
  547. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +95 -4
  548. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +1 -1
  549. package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +1 -1
  550. package/src/resources/extensions/gsd/tests/milestone-settlement.test.ts +92 -0
  551. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +1 -1
  552. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
  553. package/src/resources/extensions/gsd/tests/notifications.test.ts +64 -9
  554. package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
  555. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +18 -0
  556. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +2 -2
  557. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +143 -0
  558. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +1 -1
  559. package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +242 -0
  560. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +3 -3
  561. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +63 -2
  562. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +10 -2
  563. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +124 -6
  564. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -4
  565. package/src/resources/extensions/gsd/tests/remote-notification-from-desktop.test.ts +31 -81
  566. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +68 -0
  567. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +26 -2
  568. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -17
  569. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +7 -3
  570. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +1 -1
  571. package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +17 -0
  572. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +80 -2
  573. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +184 -10
  574. package/src/resources/extensions/gsd/tests/tool-unavailable-retry.test.ts +33 -0
  575. package/src/resources/extensions/gsd/tests/transport-gate-double-complete.test.ts +139 -0
  576. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +112 -29
  577. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +44 -0
  578. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +8 -0
  579. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
  580. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +2 -0
  581. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
  582. package/src/resources/extensions/gsd/tests/workflow-events.test.ts +19 -0
  583. package/src/resources/extensions/gsd/tests/workflow-mcp-readiness-cache.test.ts +119 -0
  584. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +65 -2
  585. package/src/resources/extensions/gsd/tests/workflow-phase-contract-matrix.test.ts +332 -0
  586. package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +20 -0
  587. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +92 -0
  588. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +273 -38
  589. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +1 -1
  590. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +1 -1
  591. package/src/resources/extensions/gsd/tests/worktree-safety-phase.test.ts +100 -0
  592. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +72 -0
  593. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +22 -0
  594. package/src/resources/extensions/gsd/tests/worktree.test.ts +18 -0
  595. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +358 -0
  596. package/src/resources/extensions/gsd/tests/write-gate.test.ts +67 -1
  597. package/src/resources/extensions/gsd/tool-contract.ts +38 -3
  598. package/src/resources/extensions/gsd/tool-presentation-plan.ts +4 -4
  599. package/src/resources/extensions/gsd/tool-surface-readiness.ts +126 -19
  600. package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
  601. package/src/resources/extensions/gsd/tools/complete-slice.ts +22 -12
  602. package/src/resources/extensions/gsd/tools/complete-task.ts +90 -2
  603. package/src/resources/extensions/gsd/tools/exec-tool.ts +4 -0
  604. package/src/resources/extensions/gsd/tools/plan-slice.ts +2 -2
  605. package/src/resources/extensions/gsd/tools/plan-task.ts +2 -2
  606. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +2 -2
  607. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +2 -2
  608. package/src/resources/extensions/gsd/tools/reopen-slice.ts +2 -2
  609. package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -2
  610. package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -2
  611. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +81 -2
  612. package/src/resources/extensions/gsd/uat-policy.ts +62 -16
  613. package/src/resources/extensions/gsd/unit-context-composer.ts +99 -0
  614. package/src/resources/extensions/gsd/unit-registry.ts +41 -24
  615. package/src/resources/extensions/gsd/verdict-parser.ts +1 -1
  616. package/src/resources/extensions/gsd/verification-verdict.ts +4 -2
  617. package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
  618. package/src/resources/extensions/gsd/workflow-event-ledger.ts +131 -0
  619. package/src/resources/extensions/gsd/workflow-event-vocabulary.ts +59 -0
  620. package/src/resources/extensions/gsd/workflow-events.ts +12 -20
  621. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -0
  622. package/src/resources/extensions/gsd/workflow-mcp-readiness-cache.ts +150 -0
  623. package/src/resources/extensions/gsd/workflow-reconcile.ts +29 -62
  624. package/src/resources/extensions/gsd/worktree-lifecycle.ts +3 -8
  625. package/src/resources/extensions/gsd/worktree-manager.ts +6 -1
  626. package/src/resources/extensions/gsd/worktree-safety.ts +41 -39
  627. package/src/resources/extensions/gsd/worktree.ts +7 -1
  628. package/src/resources/extensions/mcp-client/manager.ts +7 -1
  629. package/src/resources/extensions/search-the-web/native-search.ts +5 -3
  630. package/src/resources/extensions/shared/browser-contract.ts +66 -0
  631. package/src/resources/extensions/shared/gsd-browser-cli.ts +141 -6
  632. package/src/resources/shared/gsd-browser-path-sync.ts +273 -0
  633. package/src/resources/shared/package-manager-detection.ts +1 -1
  634. package/src/resources/shared/package.json +3 -0
  635. package/src/resources/skills/create-skill/SKILL.md +3 -0
  636. package/src/resources/skills/create-skill/references/executable-code.md +1 -1
  637. package/src/resources/skills/create-skill/references/skill-structure.md +1 -0
  638. package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
  639. package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
  640. package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
  641. package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  642. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  643. package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  644. package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
  645. package/dist/resources/extensions/gsd/user-input-boundary.js +0 -218
  646. package/dist/resources/skills/gsd-browser/SKILL.md +0 -41
  647. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +0 -173
  648. package/src/resources/extensions/gsd/user-input-boundary.ts +0 -216
  649. package/src/resources/skills/gsd-browser/SKILL.md +0 -41
  650. /package/dist/web/standalone/.next/static/{2p9Rv9pQflAxCBbGVI2vb → avEtvPrImYTq2gGe-hVNp}/_buildManifest.js +0 -0
  651. /package/dist/web/standalone/.next/static/{2p9Rv9pQflAxCBbGVI2vb → avEtvPrImYTq2gGe-hVNp}/_ssgManifest.js +0 -0
@@ -0,0 +1,303 @@
1
+ /**
2
+ * Tests for the destructive-command confirmation escape hatch.
3
+ *
4
+ * Regression target: the destructive-guard hard block had no confirmation
5
+ * path. Re-issuing a force push after confirming via ask_user_questions hit
6
+ * the identical HARD BLOCK every time — an unwinnable loop. These tests pin
7
+ * the block → confirm → allow-once flow and its safety invariants.
8
+ *
9
+ * Two layers of coverage:
10
+ * 1. Unit — the confirmation-token module in isolation (block/confirm/consume
11
+ * and every safety invariant).
12
+ * 2. Integration — the real registerHooks() bash tool_call guard +
13
+ * ask_user_questions tool_result handler driven end-to-end, proving the
14
+ * loop is escapable through the actual wiring, not just the helper module.
15
+ */
16
+
17
+ import test from "node:test";
18
+ import assert from "node:assert/strict";
19
+
20
+ import { registerHooks } from "../bootstrap/register-hooks.ts";
21
+ import { classifyCommand } from "../safety/destructive-guard.ts";
22
+ import {
23
+ DESTRUCTIVE_CONFIRM_GATE_MARKER,
24
+ confirmDestructiveCommand,
25
+ consumeDestructiveConfirmation,
26
+ isDestructiveConfirmGateId,
27
+ normalizeDestructiveCommand,
28
+ peekPendingDestructiveCommand,
29
+ requestDestructiveConfirmation,
30
+ resetDestructiveConfirmation,
31
+ } from "../safety/destructive-confirmation.ts";
32
+
33
+ const BASE = "/tmp/gsd-destructive-confirm-test";
34
+ const FORCE_PUSH = "git push --force-with-lease origin feature/PO-566-chart-supply-chain";
35
+
36
+ function blocked(command: string, basePath: string): boolean {
37
+ // Mirror the guard's decision: a classified-destructive command is blocked
38
+ // unless a matching confirmation token is consumed in this same check.
39
+ if (!classifyCommand(command).destructive) return false;
40
+ return !consumeDestructiveConfirmation(command, basePath);
41
+ }
42
+
43
+ test("repro: destructive command loops forever without confirmation", () => {
44
+ resetDestructiveConfirmation(BASE);
45
+ // Every attempt blocks — this is the bug the escape hatch fixes.
46
+ assert.equal(blocked(FORCE_PUSH, BASE), true, "first attempt blocks");
47
+ assert.equal(blocked(FORCE_PUSH, BASE), true, "retry still blocks");
48
+ assert.equal(blocked(FORCE_PUSH, BASE), true, "and again — unwinnable loop");
49
+ });
50
+
51
+ test("block then confirm then retry allows the exact command once", () => {
52
+ resetDestructiveConfirmation(BASE);
53
+
54
+ // 1. Guard blocks and records the pending command.
55
+ assert.equal(blocked(FORCE_PUSH, BASE), true, "initial attempt blocks");
56
+ requestDestructiveConfirmation(FORCE_PUSH, BASE);
57
+ assert.equal(peekPendingDestructiveCommand(BASE), normalizeDestructiveCommand(FORCE_PUSH));
58
+
59
+ // 2. User confirms via ask_user_questions affirmative answer.
60
+ const confirmed = confirmDestructiveCommand(BASE);
61
+ assert.equal(confirmed, normalizeDestructiveCommand(FORCE_PUSH));
62
+
63
+ // 3. Retry in the same turn now passes.
64
+ assert.equal(blocked(FORCE_PUSH, BASE), false, "confirmed command passes once");
65
+ });
66
+
67
+ test("confirmation is one-shot — a second destructive command re-blocks", () => {
68
+ resetDestructiveConfirmation(BASE);
69
+
70
+ requestDestructiveConfirmation(FORCE_PUSH, BASE);
71
+ confirmDestructiveCommand(BASE);
72
+ assert.equal(blocked(FORCE_PUSH, BASE), false, "first run consumes the token");
73
+ assert.equal(blocked(FORCE_PUSH, BASE), true, "identical second run re-blocks");
74
+ });
75
+
76
+ test("confirmation is command-bound — a different command is not approved", () => {
77
+ resetDestructiveConfirmation(BASE);
78
+
79
+ requestDestructiveConfirmation(FORCE_PUSH, BASE);
80
+ confirmDestructiveCommand(BASE);
81
+
82
+ // A different destructive command must not ride the force-push confirmation.
83
+ assert.equal(blocked("rm -rf node_modules", BASE), true, "unrelated destructive cmd re-blocks");
84
+ // The original token is still intact for its exact command.
85
+ assert.equal(blocked(FORCE_PUSH, BASE), false, "original confirmed command still passes once");
86
+ });
87
+
88
+ test("cosmetic whitespace reformatting still matches the confirmed token", () => {
89
+ resetDestructiveConfirmation(BASE);
90
+
91
+ requestDestructiveConfirmation("git push --force origin main", BASE);
92
+ confirmDestructiveCommand(BASE);
93
+ assert.equal(blocked("git push --force origin main", BASE), false, "whitespace-normalized match passes");
94
+ });
95
+
96
+ test("requesting a new confirmation invalidates a stale confirmed token", () => {
97
+ resetDestructiveConfirmation(BASE);
98
+
99
+ requestDestructiveConfirmation(FORCE_PUSH, BASE);
100
+ confirmDestructiveCommand(BASE);
101
+ // New block for a different command before the first was consumed.
102
+ requestDestructiveConfirmation("git reset --hard HEAD~3", BASE);
103
+ assert.equal(blocked(FORCE_PUSH, BASE), true, "old confirmation no longer valid after new request");
104
+ });
105
+
106
+ test("confirm with nothing pending returns null and approves nothing", () => {
107
+ resetDestructiveConfirmation(BASE);
108
+ assert.equal(confirmDestructiveCommand(BASE), null, "no pending command -> null");
109
+ assert.equal(blocked(FORCE_PUSH, BASE), true, "no spurious approval");
110
+ });
111
+
112
+ test("tokens are isolated per basePath", () => {
113
+ const a = "/tmp/gsd-confirm-ws-a";
114
+ const b = "/tmp/gsd-confirm-ws-b";
115
+ resetDestructiveConfirmation(a);
116
+ resetDestructiveConfirmation(b);
117
+
118
+ requestDestructiveConfirmation(FORCE_PUSH, a);
119
+ confirmDestructiveCommand(a);
120
+
121
+ assert.equal(blocked(FORCE_PUSH, b), true, "workspace B is unaffected by workspace A's confirmation");
122
+ assert.equal(blocked(FORCE_PUSH, a), false, "workspace A still passes once");
123
+ });
124
+
125
+ test("gate id marker detection", () => {
126
+ assert.equal(isDestructiveConfirmGateId(`${DESTRUCTIVE_CONFIRM_GATE_MARKER}_push`), true);
127
+ assert.equal(isDestructiveConfirmGateId("depth_verification_M001"), false);
128
+ assert.equal(isDestructiveConfirmGateId(undefined), false);
129
+ assert.equal(isDestructiveConfirmGateId(123), false);
130
+ });
131
+
132
+ test("non-destructive commands are never gated regardless of token state", () => {
133
+ resetDestructiveConfirmation(BASE);
134
+ assert.equal(blocked("git status", BASE), false);
135
+ assert.equal(blocked("ls -la", BASE), false);
136
+ });
137
+
138
+ // ─── Integration: real registerHooks() wiring, driven end-to-end ────────────
139
+ // The unit tests above exercise the token module directly. These drive the
140
+ // actual registered bash tool_call guard and ask_user_questions tool_result
141
+ // handler, proving the loop the user hit is escapable through the real hooks —
142
+ // not just the helper. Mirrors the harness in
143
+ // register-hooks-depth-verification.test.ts.
144
+
145
+ type Handler = (event: any, ctx?: any) => Promise<any> | any;
146
+
147
+ function makeHookHarness(): {
148
+ handlers: Map<string, Handler[]>;
149
+ pi: any;
150
+ } {
151
+ const handlers = new Map<string, Handler[]>();
152
+ const pi = {
153
+ on(event: string, handler: Handler) {
154
+ const existing = handlers.get(event) ?? [];
155
+ existing.push(handler);
156
+ handlers.set(event, existing);
157
+ },
158
+ } as any;
159
+ return { handlers, pi };
160
+ }
161
+
162
+ /** Run every bash tool_call guard and return the first block result, if any. */
163
+ async function runBashGuard(
164
+ handlers: Map<string, Handler[]>,
165
+ command: string,
166
+ ctx: any,
167
+ ): Promise<{ block?: boolean; reason?: string } | undefined> {
168
+ let block: { block?: boolean; reason?: string } | undefined;
169
+ for (const handler of handlers.get("tool_call") ?? []) {
170
+ const result = await handler(
171
+ { toolCallId: "bash-1", toolName: "bash", input: { command } },
172
+ ctx,
173
+ );
174
+ if (result?.block) block = result;
175
+ }
176
+ return block;
177
+ }
178
+
179
+ /** Deliver an affirmative ask_user_questions answer for a destructive gate. */
180
+ async function answerConfirmGate(
181
+ handlers: Map<string, Handler[]>,
182
+ questionId: string,
183
+ ctx: any,
184
+ ): Promise<void> {
185
+ const questions = [
186
+ {
187
+ id: questionId,
188
+ question: "Run this destructive command?",
189
+ options: [{ label: "Yes, run it (Recommended)" }, { label: "No, cancel" }],
190
+ },
191
+ ];
192
+ for (const handler of handlers.get("tool_result") ?? []) {
193
+ await handler(
194
+ {
195
+ toolName: "ask_user_questions",
196
+ input: { questions },
197
+ details: {
198
+ response: { answers: { [questionId]: { selected: "Yes, run it (Recommended)" } } },
199
+ },
200
+ },
201
+ ctx,
202
+ );
203
+ }
204
+ }
205
+
206
+ test("integration: real hooks block a force push, then allow it once after confirmation", async (t) => {
207
+ const dir = "/tmp/gsd-destructive-confirm-int-allow";
208
+ const ctx = { cwd: dir, ui: { notify: () => undefined } } as any;
209
+ resetDestructiveConfirmation(dir);
210
+ t.after(() => resetDestructiveConfirmation(dir));
211
+
212
+ const { handlers, pi } = makeHookHarness();
213
+ registerHooks(pi, []);
214
+
215
+ // 1. First attempt is hard-blocked by the real guard, with instructions that
216
+ // name the destructive_confirm gate.
217
+ const firstBlock = await runBashGuard(handlers, FORCE_PUSH, ctx);
218
+ assert.equal(firstBlock?.block, true, "real guard blocks the first attempt");
219
+ assert.match(firstBlock?.reason ?? "", /HARD BLOCK: destructive Bash command/);
220
+ assert.match(firstBlock?.reason ?? "", /force push/);
221
+ assert.match(firstBlock?.reason ?? "", /destructive_confirm/);
222
+
223
+ // 2. User answers an affirmative destructive_confirm gate.
224
+ await answerConfirmGate(handlers, "destructive_confirm_force_push", ctx);
225
+
226
+ // 3. Re-issuing the exact command in the same turn now runs once (no block).
227
+ const secondAttempt = await runBashGuard(handlers, FORCE_PUSH, ctx);
228
+ assert.equal(secondAttempt, undefined, "confirmed command passes the real guard once");
229
+
230
+ // 4. One-shot: an immediate identical third attempt re-blocks.
231
+ const thirdAttempt = await runBashGuard(handlers, FORCE_PUSH, ctx);
232
+ assert.equal(thirdAttempt?.block, true, "second run of the same command re-blocks (one-shot)");
233
+ });
234
+
235
+ test("integration: declining the confirm gate leaves the command blocked", async (t) => {
236
+ const dir = "/tmp/gsd-destructive-confirm-int-decline";
237
+ const ctx = { cwd: dir, ui: { notify: () => undefined } } as any;
238
+ resetDestructiveConfirmation(dir);
239
+ t.after(() => resetDestructiveConfirmation(dir));
240
+
241
+ const { handlers, pi } = makeHookHarness();
242
+ registerHooks(pi, []);
243
+
244
+ assert.equal((await runBashGuard(handlers, FORCE_PUSH, ctx))?.block, true, "first attempt blocks");
245
+
246
+ // Decline: the non-affirmative (non-first) option must NOT promote a token.
247
+ const questions = [
248
+ {
249
+ id: "destructive_confirm_force_push",
250
+ question: "Run this destructive command?",
251
+ options: [{ label: "Yes, run it (Recommended)" }, { label: "No, cancel" }],
252
+ },
253
+ ];
254
+ for (const handler of handlers.get("tool_result") ?? []) {
255
+ await handler(
256
+ {
257
+ toolName: "ask_user_questions",
258
+ input: { questions },
259
+ details: {
260
+ response: { answers: { "destructive_confirm_force_push": { selected: "No, cancel" } } },
261
+ },
262
+ },
263
+ ctx,
264
+ );
265
+ }
266
+
267
+ assert.equal(
268
+ (await runBashGuard(handlers, FORCE_PUSH, ctx))?.block,
269
+ true,
270
+ "declined command stays blocked",
271
+ );
272
+ });
273
+
274
+ test("integration: a confirm token does not leak to a different destructive command", async (t) => {
275
+ const dir = "/tmp/gsd-destructive-confirm-int-bound";
276
+ const ctx = { cwd: dir, ui: { notify: () => undefined } } as any;
277
+ resetDestructiveConfirmation(dir);
278
+ t.after(() => resetDestructiveConfirmation(dir));
279
+
280
+ const { handlers, pi } = makeHookHarness();
281
+ registerHooks(pi, []);
282
+
283
+ await runBashGuard(handlers, FORCE_PUSH, ctx);
284
+ await answerConfirmGate(handlers, "destructive_confirm_force_push", ctx);
285
+
286
+ // A different destructive command must not ride the force-push confirmation.
287
+ // In the real guard, blocking this command also records it as pending, which
288
+ // invalidates the stale force-push token (stale-token safety invariant) — so
289
+ // the original confirmation is consumed/cleared, not left dangling.
290
+ assert.equal(
291
+ (await runBashGuard(handlers, "rm -rf build", ctx))?.block,
292
+ true,
293
+ "unrelated destructive command is still blocked",
294
+ );
295
+ // Because the unrelated block invalidated the stale token, the original
296
+ // force-push now re-blocks too: a confirmation never survives an intervening
297
+ // destructive command. This is stricter (safer) than per-command isolation.
298
+ assert.equal(
299
+ (await runBashGuard(handlers, FORCE_PUSH, ctx))?.block,
300
+ true,
301
+ "force-push token was invalidated by the intervening destructive block",
302
+ );
303
+ });
@@ -39,7 +39,11 @@ function makeDiscussPi() {
39
39
  tmp,
40
40
  pi: {
41
41
  getActiveTools: () => ["gsd_summary_save", "bash"],
42
+ emitAdjustToolSet: async () => undefined,
43
+ emitBeforeModelSelect: async () => undefined,
44
+ setModel: async () => true,
42
45
  setActiveTools: () => {},
46
+ setThinkingLevel: () => {},
43
47
  sendMessage: (message: { content?: unknown }) => {
44
48
  sent.push(message);
45
49
  },
@@ -53,6 +57,7 @@ function makeDiscussPi() {
53
57
  }
54
58
 
55
59
  function makeDiscussCtx(notifications: Array<{ message: string; level?: string }> = []) {
60
+ const model = { provider: "anthropic", id: "claude-sonnet-4-6", api: "anthropic-messages" };
56
61
  return {
57
62
  hasUI: true,
58
63
  sessionManager: {
@@ -65,8 +70,13 @@ function makeDiscussCtx(notifications: Array<{ message: string; level?: string }
65
70
  setStatus: () => {},
66
71
  },
67
72
  waitForIdle: async () => {},
68
- model: undefined,
69
- modelRegistry: { getProviderAuthMode: () => undefined },
73
+ model,
74
+ modelRegistry: {
75
+ getAvailable: () => [model],
76
+ getAll: () => [model],
77
+ getProviderAuthMode: () => "apiKey",
78
+ isProviderRequestReady: () => true,
79
+ },
70
80
  };
71
81
  }
72
82
 
@@ -0,0 +1,328 @@
1
+ // gsd-pi — Dispatch History module tests (#482 / #442 deepening)
2
+ //
3
+ // Covers: canonical key building and legacy-key normalization, window
4
+ // record/evict semantics, ledger error attachment, cross-session rehydration
5
+ // from unit_dispatches (the #482 regression: a fresh history rehydrated from
6
+ // the DB must detect a re-dispatch loop that spans session restarts),
7
+ // retry-budget suppression, and clearOnRecovery.
8
+
9
+ import test from "node:test";
10
+ import assert from "node:assert/strict";
11
+ import { mkdtempSync, mkdirSync, rmSync } from "node:fs";
12
+ import { join } from "node:path";
13
+ import { tmpdir } from "node:os";
14
+
15
+ import {
16
+ openDatabase,
17
+ closeDatabase,
18
+ insertMilestone,
19
+ } from "../gsd-db.ts";
20
+ import { registerAutoWorker } from "../db/auto-workers.ts";
21
+ import { claimMilestoneLease } from "../db/milestone-leases.ts";
22
+ import { recordDispatchClaim, markFailed, markCanceled } from "../db/unit-dispatches.ts";
23
+ import {
24
+ buildDispatchKey,
25
+ createDispatchHistory,
26
+ lookupLatestLedgerError,
27
+ normalizeDispatchKey,
28
+ parseDispatchKey,
29
+ STUCK_WINDOW_SIZE,
30
+ } from "../auto/dispatch-history.ts";
31
+
32
+ function makeBase(): string {
33
+ const base = mkdtempSync(join(tmpdir(), "gsd-dispatch-history-"));
34
+ mkdirSync(join(base, ".gsd"), { recursive: true });
35
+ return base;
36
+ }
37
+
38
+ function cleanup(base: string): void {
39
+ try { closeDatabase(); } catch { /* noop */ }
40
+ try { rmSync(base, { recursive: true, force: true }); } catch { /* noop */ }
41
+ }
42
+
43
+ interface LedgerFixture {
44
+ base: string;
45
+ worker: string;
46
+ token: number;
47
+ claim(unitType: string, unitId: string): number;
48
+ }
49
+
50
+ function makeLedgerFixture(t: { after(fn: () => void): void }): LedgerFixture {
51
+ const base = makeBase();
52
+ t.after(() => cleanup(base));
53
+ openDatabase(join(base, ".gsd", "gsd.db"));
54
+ insertMilestone({ id: "M001", title: "T", status: "active" });
55
+ const worker = registerAutoWorker({ projectRootRealpath: base });
56
+ const lease = claimMilestoneLease(worker, "M001");
57
+ assert.equal(lease.ok, true);
58
+ if (!lease.ok) throw new Error("lease claim failed");
59
+ return {
60
+ base,
61
+ worker,
62
+ token: lease.token,
63
+ claim(unitType: string, unitId: string): number {
64
+ const claim = recordDispatchClaim({
65
+ traceId: `${unitType}-${unitId}-${Math.random()}`,
66
+ workerId: worker,
67
+ milestoneLeaseToken: lease.token,
68
+ milestoneId: "M001",
69
+ unitType,
70
+ unitId,
71
+ });
72
+ assert.equal(claim.ok, true);
73
+ if (!claim.ok) throw new Error("claim failed");
74
+ return claim.dispatchId;
75
+ },
76
+ };
77
+ }
78
+
79
+ function historyFor(scopeId: string | null) {
80
+ return createDispatchHistory({ resolveScopeId: () => scopeId });
81
+ }
82
+
83
+ // ─── Key format ──────────────────────────────────────────────────────────────
84
+
85
+ test("buildDispatchKey produces the canonical unitType:unitId format", () => {
86
+ assert.equal(buildDispatchKey("execute-task", "M001/S01/T01"), "execute-task:M001/S01/T01");
87
+ });
88
+
89
+ test("normalizeDispatchKey converts legacy slash keys and keeps canonical keys", () => {
90
+ assert.equal(normalizeDispatchKey("execute-task/M001/S01/T01"), "execute-task:M001/S01/T01");
91
+ assert.equal(normalizeDispatchKey("execute-task:M001/S01/T01"), "execute-task:M001/S01/T01");
92
+ assert.equal(normalizeDispatchKey("opaque"), "opaque");
93
+ });
94
+
95
+ test("parseDispatchKey splits canonical and legacy keys at the unit type", () => {
96
+ assert.deepEqual(parseDispatchKey("complete-slice:M001/S01"), {
97
+ unitType: "complete-slice",
98
+ unitId: "M001/S01",
99
+ });
100
+ assert.deepEqual(parseDispatchKey("complete-slice/M001/S01"), {
101
+ unitType: "complete-slice",
102
+ unitId: "M001/S01",
103
+ });
104
+ assert.equal(parseDispatchKey("opaque"), null);
105
+ });
106
+
107
+ // ─── Window record/evict ─────────────────────────────────────────────────────
108
+
109
+ test("recordDispatch caps the window at the window size, evicting oldest-first", () => {
110
+ const history = historyFor(null);
111
+ for (let i = 0; i < STUCK_WINDOW_SIZE + 2; i++) {
112
+ history.recordDispatch("execute-task", `M001/S01/T${i}`);
113
+ }
114
+ const window = history.getRecentWindow();
115
+ assert.equal(window.length, STUCK_WINDOW_SIZE);
116
+ assert.equal(window[0].key, "execute-task:M001/S01/T2");
117
+ assert.equal(window[window.length - 1].key, `execute-task:M001/S01/T${STUCK_WINDOW_SIZE + 1}`);
118
+ });
119
+
120
+ test("countMatching counts entries for the canonical key", () => {
121
+ const history = historyFor(null);
122
+ history.recordDispatch("execute-task", "M001/S01/T01");
123
+ history.recordDispatch("complete-slice", "M001/S01");
124
+ history.recordDispatch("execute-task", "M001/S01/T01");
125
+ assert.equal(history.countMatching("execute-task:M001/S01/T01"), 2);
126
+ assert.equal(history.countMatching("complete-slice:M001/S01"), 1);
127
+ });
128
+
129
+ test("clearOnRecovery empties the window", () => {
130
+ const history = historyFor(null);
131
+ history.recordDispatch("execute-task", "M001/S01/T01");
132
+ history.recordDispatch("execute-task", "M001/S01/T01");
133
+ history.clearOnRecovery();
134
+ assert.equal(history.getRecentWindow().length, 0);
135
+ assert.equal(history.detectStuck(), null);
136
+ });
137
+
138
+ // ─── Ledger error attachment + detect-stuck delegation ──────────────────────
139
+
140
+ test("recordDispatch attaches the latest ledger error on repeats so repeat-error detection fires", (t) => {
141
+ const f = makeLedgerFixture(t);
142
+ const dispatchId = f.claim("execute-task", "M001/S01/T01");
143
+ markFailed(dispatchId, { errorSummary: "boom: deterministic failure" });
144
+
145
+ const history = historyFor(f.base);
146
+ history.recordDispatch("execute-task", "M001/S01/T01");
147
+ history.recordDispatch("execute-task", "M001/S01/T01");
148
+ history.recordDispatch("execute-task", "M001/S01/T01");
149
+
150
+ const window = history.getRecentWindow();
151
+ // First dispatch of a unit skips the ledger lookup (zero DB cost on the
152
+ // common path); repeats attach the latest error.
153
+ assert.equal(window[0].error, undefined);
154
+ assert.equal(window[1].error, "boom: deterministic failure");
155
+ assert.equal(window[2].error, "boom: deterministic failure");
156
+ const verdict = history.detectStuck();
157
+ assert.equal(verdict?.stuck, true);
158
+ assert.match(verdict?.reason ?? "", /Same error repeated/);
159
+ });
160
+
161
+ test("lookupLatestLedgerError matches the bare unit id, not the compound key", (t) => {
162
+ const f = makeLedgerFixture(t);
163
+ const dispatchId = f.claim("execute-task", "M001/S01/T01");
164
+ markFailed(dispatchId, { errorSummary: "boom: deterministic failure" });
165
+
166
+ // The ledger keys rows by the bare unit id with the unit type in its own
167
+ // column. The shared lookup (also used by dispatch.ts's runDispatch path)
168
+ // must use the bare id; a compound `unitType/unitId` value misses entirely,
169
+ // which previously silently dropped repeat-error detection on that path.
170
+ assert.equal(
171
+ lookupLatestLedgerError("execute-task", "M001/S01/T01"),
172
+ "boom: deterministic failure",
173
+ );
174
+ assert.equal(
175
+ lookupLatestLedgerError("execute-task", "execute-task/M001/S01/T01"),
176
+ undefined,
177
+ "a compound key must not match the bare-id ledger row",
178
+ );
179
+ assert.equal(
180
+ lookupLatestLedgerError("plan-slice", "M001/S01/T01"),
181
+ undefined,
182
+ "a different unit type on the same id must not be attached",
183
+ );
184
+ });
185
+
186
+ test("recordDispatch never attaches another unit type's ledger error for the same unit id", (t) => {
187
+ const f = makeLedgerFixture(t);
188
+ const dispatchId = f.claim("plan-slice", "M001/S01");
189
+ markFailed(dispatchId, { errorSummary: "boom: plan failure" });
190
+
191
+ const history = historyFor(f.base);
192
+ history.recordDispatch("execute-task", "M001/S01");
193
+ history.recordDispatch("execute-task", "M001/S01");
194
+
195
+ assert.ok(history.getRecentWindow().every((entry) => entry.error === undefined));
196
+ assert.equal(history.detectStuck(), null);
197
+ });
198
+
199
+ test("detectStuck fires on three consecutive same-key dispatches without errors", () => {
200
+ const history = historyFor(null);
201
+ for (let i = 0; i < 3; i++) history.recordDispatch("plan-slice", "M001/S01");
202
+ const verdict = history.detectStuck();
203
+ assert.equal(verdict?.stuck, true);
204
+ assert.match(verdict?.reason ?? "", /plan-slice:M001\/S01 derived 3 consecutive times/);
205
+ });
206
+
207
+ // ─── Retry-budget suppression ────────────────────────────────────────────────
208
+
209
+ test("a bare-id ledger row for a different unit type does not suppress the stuck verdict", (t) => {
210
+ const f = makeLedgerFixture(t);
211
+ // Retry backoff is open for plan-slice:M001/S01 only (bare-id ledger row).
212
+ const dispatchId = f.claim("plan-slice", "M001/S01");
213
+ markFailed(dispatchId, { errorSummary: "", retryAfterMs: 60_000 });
214
+
215
+ const history = historyFor(f.base);
216
+ for (let i = 0; i < 3; i++) history.recordDispatch("execute-task", "M001/S01");
217
+ const verdict = history.detectStuck();
218
+ assert.equal(verdict?.stuck, true, "another unit type's backoff must not suppress this unit");
219
+ });
220
+
221
+ test("consecutive-repeat verdict is suppressed while the retry budget drains", (t) => {
222
+ const f = makeLedgerFixture(t);
223
+ // markCanceled leaves error_summary null so the repeat-error rule (which is
224
+ // never suppressed) cannot fire; the suppression target is rule 2/2b.
225
+ const first = f.claim("plan-slice", "M001/S01");
226
+ markCanceled(first, "retry");
227
+ const second = f.claim("plan-slice", "M001/S01");
228
+ markFailed(second, { errorSummary: "", retryAfterMs: 60_000 });
229
+
230
+ const history = historyFor(f.base);
231
+ for (let i = 0; i < 3; i++) history.recordDispatch("plan-slice", "M001/S01");
232
+ assert.equal(history.detectStuck(), null, "stuck verdict must be suppressed inside the retry backoff window");
233
+ });
234
+
235
+ test("exhausted retry budget does not suppress the stuck verdict", (t) => {
236
+ const f = makeLedgerFixture(t);
237
+ const ids: number[] = [];
238
+ for (let i = 0; i < 3; i++) {
239
+ const id = f.claim("plan-slice", "M001/S01");
240
+ markCanceled(id, "retry");
241
+ ids.push(id);
242
+ }
243
+ const last = f.claim("plan-slice", "M001/S01");
244
+ // attempt_n defaults to 1 here; bump via a fresh claim is unnecessary —
245
+ // exhaust by omitting next_run_at instead (no scheduled retry → no backoff).
246
+ markFailed(last, { errorSummary: "" });
247
+
248
+ const history = historyFor(f.base);
249
+ for (let i = 0; i < 3; i++) history.recordDispatch("plan-slice", "M001/S01");
250
+ const verdict = history.detectStuck();
251
+ assert.equal(verdict?.stuck, true);
252
+ });
253
+
254
+ // ─── Rehydration (#482 regression) ───────────────────────────────────────────
255
+
256
+ test("rehydrate seeds the window from the ledger with normalized canonical keys", (t) => {
257
+ const f = makeLedgerFixture(t);
258
+ for (let i = 0; i < 2; i++) {
259
+ const id = f.claim("execute-task", "M001/S01/T01");
260
+ markFailed(id, { errorSummary: "" });
261
+ }
262
+
263
+ const history = historyFor(f.base);
264
+ const count = history.rehydrate();
265
+ assert.equal(count, 2);
266
+ assert.deepEqual(
267
+ history.getRecentWindow().map((e) => e.key),
268
+ ["execute-task:M001/S01/T01", "execute-task:M001/S01/T01"],
269
+ );
270
+ });
271
+
272
+ test("#482 regression: a re-dispatch loop spanning a session restart is detected as stuck", (t) => {
273
+ const f = makeLedgerFixture(t);
274
+ // Session 1: the same unit was dispatched twice and never made progress.
275
+ for (let i = 0; i < 2; i++) {
276
+ const id = f.claim("execute-task", "M001/S01/T01");
277
+ markFailed(id, { errorSummary: "" });
278
+ }
279
+
280
+ // Session 2: a brand-new history (fresh orchestrator) rehydrates from the
281
+ // ledger; the very next decision for the same unit trips the stuck verdict
282
+ // instead of silently re-dispatching forever.
283
+ const restarted = historyFor(f.base);
284
+ restarted.rehydrate();
285
+ restarted.recordDispatch("execute-task", "M001/S01/T01");
286
+ const verdict = restarted.detectStuck();
287
+ assert.equal(verdict?.stuck, true);
288
+ assert.match(verdict?.reason ?? "", /execute-task:M001\/S01\/T01 derived 3 consecutive times/);
289
+ });
290
+
291
+ test("rehydrate mirrors recordDispatch error attachment so repeat-error detection fires after the next dispatch", (t) => {
292
+ const f = makeLedgerFixture(t);
293
+ // Session 1: two failed dispatches for the same unit, same error summary.
294
+ for (let i = 0; i < 2; i++) {
295
+ const id = f.claim("execute-task", "M001/S01/T01");
296
+ markFailed(id, { errorSummary: "boom: deterministic failure" });
297
+ }
298
+
299
+ // Session 2: fresh history rehydrates from the ledger. Just like the live
300
+ // recordDispatch path, the first occurrence of a unit skips the ledger
301
+ // lookup; only repeats carry the error. So rehydration alone does not trip
302
+ // Rule 1 — keeping the post-restart window no more aggressive than the live
303
+ // one (Rule 1 has no retry-budget suppression).
304
+ const restarted = historyFor(f.base);
305
+ const count = restarted.rehydrate();
306
+ assert.equal(count, 2);
307
+ const window = restarted.getRecentWindow();
308
+ assert.equal(window[0].error, undefined);
309
+ assert.equal(window[1].error, "boom: deterministic failure");
310
+ assert.equal(restarted.detectStuck(), null);
311
+
312
+ // The next dispatch of the same unit attaches the error again, giving two
313
+ // consecutive matching errors → Rule 1 fires, exactly as in the live path.
314
+ restarted.recordDispatch("execute-task", "M001/S01/T01");
315
+ const verdict = restarted.detectStuck();
316
+ assert.equal(verdict?.stuck, true);
317
+ assert.match(verdict?.reason ?? "", /Same error repeated/);
318
+ });
319
+
320
+ test("rehydrate degrades to an empty window without a scope or ledger", () => {
321
+ const noScope = historyFor(null);
322
+ assert.equal(noScope.rehydrate(), 0);
323
+ assert.equal(noScope.getRecentWindow().length, 0);
324
+
325
+ const noDb = historyFor("/nonexistent/scope");
326
+ assert.equal(noDb.rehydrate(), 0);
327
+ assert.equal(noDb.getRecentWindow().length, 0);
328
+ });
@@ -9,6 +9,7 @@ import { join } from "node:path";
9
9
 
10
10
  import { DISPATCH_RULES, type DispatchContext } from "../auto-dispatch.ts";
11
11
  import type { GSDState } from "../types.ts";
12
+ import { BROWSER_AUTOMATION_CONTRACT_TOOLS } from "./browser-automation-contract-fixture.ts";
12
13
 
13
14
  type DispatchRuleEntry = (typeof DISPATCH_RULES)[number];
14
15
 
@@ -80,7 +81,7 @@ test("run-uat browser preflight uses registered tools when the active surface is
80
81
  assert.match(blocked?.action === "stop" ? blocked.reason : "", /run-uat tool surface has none/);
81
82
 
82
83
  const dispatched = await runUatRule().match(makeContext(basePath, {
83
- registeredTools: ["browser_navigate"],
84
+ registeredTools: [...BROWSER_AUTOMATION_CONTRACT_TOOLS.piProvider],
84
85
  }));
85
86
  assert.equal(dispatched?.action, "dispatch");
86
87
  assert.equal(dispatched?.action === "dispatch" ? dispatched.unitType : undefined, "run-uat");