@opengsd/gsd-pi 1.2.0-dev.b1abb545 → 1.2.0-dev.d6c5343c

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 (551) hide show
  1. package/dist/cli-style.d.ts +17 -0
  2. package/dist/cli-style.js +28 -0
  3. package/dist/cli.js +1 -1
  4. package/dist/headless-events.d.ts +4 -2
  5. package/dist/headless-events.js +14 -34
  6. package/dist/models-resolver.d.ts +3 -13
  7. package/dist/models-resolver.js +3 -22
  8. package/dist/resource-loader.js +2 -14
  9. package/dist/resources/.managed-resources-content-hash +1 -1
  10. package/dist/resources/GSD-WORKFLOW.md +5 -4
  11. package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
  12. package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
  13. package/dist/resources/extensions/async-jobs/index.js +65 -0
  14. package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
  15. package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
  16. package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
  17. package/dist/resources/extensions/bg-shell/overlay.js +9 -6
  18. package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
  19. package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
  20. package/dist/resources/extensions/bg-shell/utilities.js +5 -2
  21. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +209 -88
  22. package/dist/resources/extensions/browser-tools/engine/selection.js +73 -5
  23. package/dist/resources/extensions/browser-tools/index.js +69 -12
  24. package/dist/resources/extensions/claude-code-cli/models.js +9 -0
  25. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +38 -6
  26. package/dist/resources/extensions/gsd/auto/custom-verify-retry-store.js +17 -2
  27. package/dist/resources/extensions/gsd/auto/detect-stuck.js +33 -13
  28. package/dist/resources/extensions/gsd/auto/dispatch-history.js +105 -0
  29. package/dist/resources/extensions/gsd/auto/dispatch-key.js +37 -0
  30. package/dist/resources/extensions/gsd/auto/loop.js +4 -1
  31. package/dist/resources/extensions/gsd/auto/orchestrator.js +94 -48
  32. package/dist/resources/extensions/gsd/auto/phases.js +8 -3
  33. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +8 -32
  34. package/dist/resources/extensions/gsd/auto-dispatch.js +40 -57
  35. package/dist/resources/extensions/gsd/auto-model-selection.js +25 -6
  36. package/dist/resources/extensions/gsd/auto-post-unit.js +31 -14
  37. package/dist/resources/extensions/gsd/auto-prompts.js +81 -19
  38. package/dist/resources/extensions/gsd/auto-start.js +24 -26
  39. package/dist/resources/extensions/gsd/auto-tool-tracking.js +18 -0
  40. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +12 -20
  41. package/dist/resources/extensions/gsd/auto-verification.js +9 -28
  42. package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
  43. package/dist/resources/extensions/gsd/auto-worktree.js +35 -352
  44. package/dist/resources/extensions/gsd/auto.js +8 -20
  45. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +3 -2
  46. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +32 -12
  47. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
  48. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +229 -36
  49. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +319 -71
  50. package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
  51. package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
  52. package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
  53. package/dist/resources/extensions/gsd/captures.js +5 -15
  54. package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
  55. package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
  56. package/dist/resources/extensions/gsd/consent-question.js +337 -0
  57. package/dist/resources/extensions/gsd/consent-verdict.js +63 -0
  58. package/dist/resources/extensions/gsd/constants.js +0 -2
  59. package/dist/resources/extensions/gsd/crash-recovery.js +4 -12
  60. package/dist/resources/extensions/gsd/db/engine.js +755 -0
  61. package/dist/resources/extensions/gsd/db/queries.js +398 -0
  62. package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
  63. package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
  64. package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
  65. package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
  66. package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
  67. package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
  68. package/dist/resources/extensions/gsd/dispatch-guard.js +10 -35
  69. package/dist/resources/extensions/gsd/doctor-environment.js +5 -11
  70. package/dist/resources/extensions/gsd/doctor-format.js +9 -6
  71. package/dist/resources/extensions/gsd/doctor-git-checks.js +4 -3
  72. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +21 -16
  73. package/dist/resources/extensions/gsd/engine-hook-contract.js +70 -0
  74. package/dist/resources/extensions/gsd/error-classifier.js +9 -0
  75. package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
  76. package/dist/resources/extensions/gsd/files.js +33 -19
  77. package/dist/resources/extensions/gsd/git-service.js +1 -0
  78. package/dist/resources/extensions/gsd/gitignore.js +3 -0
  79. package/dist/resources/extensions/gsd/gsd-db.js +171 -2048
  80. package/dist/resources/extensions/gsd/guidance.js +158 -0
  81. package/dist/resources/extensions/gsd/guided-flow.js +51 -5
  82. package/dist/resources/extensions/gsd/markdown-renderer.js +10 -0
  83. package/dist/resources/extensions/gsd/mcp-filter.js +2 -19
  84. package/dist/resources/extensions/gsd/mcp-tool-name.js +5 -13
  85. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
  86. package/dist/resources/extensions/gsd/migrate/safety.js +20 -9
  87. package/dist/resources/extensions/gsd/migration-auto-check.js +24 -3
  88. package/dist/resources/extensions/gsd/milestone-closeout.js +13 -23
  89. package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
  90. package/dist/resources/extensions/gsd/model-router.js +3 -0
  91. package/dist/resources/extensions/gsd/notification-store.js +11 -4
  92. package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
  93. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +11 -7
  94. package/dist/resources/extensions/gsd/parsers-legacy.js +16 -4
  95. package/dist/resources/extensions/gsd/paths.js +37 -24
  96. package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
  97. package/dist/resources/extensions/gsd/preferences-models.js +14 -48
  98. package/dist/resources/extensions/gsd/preferences.js +14 -0
  99. package/dist/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  100. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  101. package/dist/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  102. package/dist/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  103. package/dist/resources/extensions/gsd/prompts/run-uat.md +6 -4
  104. package/dist/resources/extensions/gsd/prompts/system.md +5 -2
  105. package/dist/resources/extensions/gsd/provider-error-guidance.js +1 -5
  106. package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
  107. package/dist/resources/extensions/gsd/publication.js +87 -0
  108. package/dist/resources/extensions/gsd/reactive-graph.js +8 -1
  109. package/dist/resources/extensions/gsd/recovery-classification.js +41 -87
  110. package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
  111. package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
  112. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
  113. package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
  114. package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
  115. package/dist/resources/extensions/gsd/state.js +6 -20
  116. package/dist/resources/extensions/gsd/status-guards.js +56 -8
  117. package/dist/resources/extensions/gsd/stop-notice.js +57 -0
  118. package/dist/resources/extensions/gsd/tool-presentation-plan.js +4 -4
  119. package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
  120. package/dist/resources/extensions/gsd/tools/complete-slice.js +44 -53
  121. package/dist/resources/extensions/gsd/tools/exec-tool.js +10 -8
  122. package/dist/resources/extensions/gsd/tools/plan-slice.js +12 -6
  123. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +11 -29
  124. package/dist/resources/extensions/gsd/tools/reopen-slice.js +14 -33
  125. package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
  126. package/dist/resources/extensions/gsd/uat-policy.js +42 -16
  127. package/dist/resources/extensions/gsd/undo.js +8 -7
  128. package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
  129. package/dist/resources/extensions/gsd/unit-context-composer.js +74 -1
  130. package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
  131. package/dist/resources/extensions/gsd/unit-registry.js +337 -0
  132. package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -182
  133. package/dist/resources/extensions/gsd/verdict-parser.js +1 -1
  134. package/dist/resources/extensions/gsd/web-app-uat.js +45 -8
  135. package/dist/resources/extensions/gsd/workflow-tool-surface.js +1 -1
  136. package/dist/resources/extensions/gsd/worktree-git-recovery.js +293 -0
  137. package/dist/resources/extensions/gsd/worktree-lifecycle.js +12 -3
  138. package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
  139. package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
  140. package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
  141. package/dist/resources/extensions/gsd/worktree-root.js +28 -6
  142. package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
  143. package/dist/resources/extensions/gsd/worktree-session-state.js +12 -11
  144. package/dist/resources/extensions/search-the-web/native-search.js +5 -3
  145. package/dist/resources/extensions/shared/browser-contract.js +59 -0
  146. package/dist/resources/extensions/shared/gsd-browser-cli.js +96 -5
  147. package/dist/resources/shared/package.json +3 -0
  148. package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
  149. package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
  150. package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
  151. package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
  152. package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  153. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  154. package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  155. package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
  156. package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
  157. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  158. package/dist/web/standalone/.next/BUILD_ID +1 -1
  159. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  160. package/dist/web/standalone/.next/build-manifest.json +3 -3
  161. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  162. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  163. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  164. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  165. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  166. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  167. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  168. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  169. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  170. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  171. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  172. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  173. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  174. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  175. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  176. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  177. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  178. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  179. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  180. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  181. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  182. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  183. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  184. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  185. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  186. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  187. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  188. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  189. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  190. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  191. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  192. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  193. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  194. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  195. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  196. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  197. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  198. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  199. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  200. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  201. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  202. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  203. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  204. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  205. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  206. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  207. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  208. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  209. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  210. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  211. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  212. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  213. package/dist/web/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  214. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  215. package/dist/web/standalone/.next/server/app/index.html +1 -1
  216. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  217. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  218. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  219. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  220. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  221. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  222. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  223. package/dist/web/standalone/.next/server/chunks/5124.js +1 -1
  224. package/dist/web/standalone/.next/server/chunks/{5047.js → 5942.js} +2 -2
  225. package/dist/web/standalone/.next/server/chunks/8357.js +1 -1
  226. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  227. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  228. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  229. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  230. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  231. package/dist/web/standalone/.next/static/chunks/{796.cf859a427a2cb2ac.js → 796.e0bdc932325d7e03.js} +1 -1
  232. package/dist/web/standalone/.next/static/chunks/{webpack-fbea77b5f9953368.js → webpack-f0285ce91d4ec9ef.js} +1 -1
  233. package/dist/web/standalone/package.json +1 -1
  234. package/dist/worktree-cli.js +3 -6
  235. package/dist/worktree-status-banner.js +7 -11
  236. package/package.json +1 -1
  237. package/packages/cloud-mcp-gateway/package.json +2 -2
  238. package/packages/contracts/dist/rpc.d.ts +1 -0
  239. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  240. package/packages/contracts/dist/rpc.js.map +1 -1
  241. package/packages/contracts/dist/workflow.d.ts +4 -0
  242. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  243. package/packages/contracts/dist/workflow.js.map +1 -1
  244. package/packages/contracts/package.json +1 -1
  245. package/packages/daemon/package.json +4 -4
  246. package/packages/gsd-agent-core/package.json +5 -5
  247. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  248. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  249. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +8 -0
  250. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  251. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  252. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +7 -0
  253. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  254. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  255. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
  256. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  257. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  258. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
  259. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  260. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  261. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
  262. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  263. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  264. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
  265. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  266. package/packages/gsd-agent-modes/package.json +7 -7
  267. package/packages/mcp-server/dist/cli.js +6 -3
  268. package/packages/mcp-server/dist/cli.js.map +1 -1
  269. package/packages/mcp-server/dist/workflow-tools.d.ts +8 -0
  270. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  271. package/packages/mcp-server/dist/workflow-tools.js +46 -21
  272. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  273. package/packages/mcp-server/package.json +3 -3
  274. package/packages/native/package.json +1 -1
  275. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts +1 -0
  276. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
  277. package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
  278. package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
  279. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  280. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  281. package/packages/pi-agent-core/dist/index.js +3 -0
  282. package/packages/pi-agent-core/dist/index.js.map +1 -1
  283. package/packages/pi-agent-core/package.json +1 -1
  284. package/packages/pi-ai/README.md +1 -0
  285. package/packages/pi-ai/dist/models.generated.d.ts +192 -0
  286. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  287. package/packages/pi-ai/dist/models.generated.js +166 -0
  288. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  289. package/packages/pi-ai/package.json +3 -2
  290. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
  291. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  292. package/packages/pi-coding-agent/dist/core/auth-storage.js +19 -13
  293. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  294. package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
  295. package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
  296. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  297. package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
  298. package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
  299. package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
  300. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
  301. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  302. package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
  303. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  304. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  305. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  306. package/packages/pi-coding-agent/dist/index.js +1 -1
  307. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  308. package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
  309. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  310. package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
  311. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  312. package/packages/pi-coding-agent/package.json +7 -7
  313. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  314. package/packages/pi-tui/dist/tui.js +9 -0
  315. package/packages/pi-tui/dist/tui.js.map +1 -1
  316. package/packages/pi-tui/package.json +2 -2
  317. package/packages/rpc-client/package.json +2 -2
  318. package/pkg/package.json +1 -1
  319. package/src/resources/GSD-WORKFLOW.md +5 -4
  320. package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
  321. package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
  322. package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
  323. package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
  324. package/src/resources/extensions/async-jobs/index.ts +79 -0
  325. package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
  326. package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
  327. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
  328. package/src/resources/extensions/bg-shell/overlay.ts +9 -5
  329. package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
  330. package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
  331. package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
  332. package/src/resources/extensions/bg-shell/utilities.ts +5 -2
  333. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
  334. package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
  335. package/src/resources/extensions/browser-tools/index.ts +71 -13
  336. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
  337. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +29 -1
  338. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
  339. package/src/resources/extensions/claude-code-cli/models.ts +9 -0
  340. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +40 -4
  341. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +28 -0
  342. package/src/resources/extensions/gsd/auto/custom-verify-retry-store.ts +21 -3
  343. package/src/resources/extensions/gsd/auto/detect-stuck.ts +32 -9
  344. package/src/resources/extensions/gsd/auto/dispatch-history.ts +152 -0
  345. package/src/resources/extensions/gsd/auto/dispatch-key.ts +39 -0
  346. package/src/resources/extensions/gsd/auto/loop-deps.ts +1 -1
  347. package/src/resources/extensions/gsd/auto/loop.ts +4 -1
  348. package/src/resources/extensions/gsd/auto/orchestrator.ts +109 -51
  349. package/src/resources/extensions/gsd/auto/phases.ts +12 -3
  350. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +8 -32
  351. package/src/resources/extensions/gsd/auto-dispatch.ts +38 -52
  352. package/src/resources/extensions/gsd/auto-model-selection.ts +25 -5
  353. package/src/resources/extensions/gsd/auto-post-unit.ts +37 -13
  354. package/src/resources/extensions/gsd/auto-prompts.ts +118 -35
  355. package/src/resources/extensions/gsd/auto-start.ts +24 -29
  356. package/src/resources/extensions/gsd/auto-tool-tracking.ts +19 -0
  357. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +14 -21
  358. package/src/resources/extensions/gsd/auto-verification.ts +8 -26
  359. package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
  360. package/src/resources/extensions/gsd/auto-worktree.ts +41 -364
  361. package/src/resources/extensions/gsd/auto.ts +20 -24
  362. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +3 -5
  363. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +33 -12
  364. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
  365. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +270 -37
  366. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +368 -78
  367. package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
  368. package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
  369. package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
  370. package/src/resources/extensions/gsd/captures.ts +5 -16
  371. package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
  372. package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
  373. package/src/resources/extensions/gsd/consent-question.ts +416 -0
  374. package/src/resources/extensions/gsd/consent-verdict.ts +86 -0
  375. package/src/resources/extensions/gsd/constants.ts +0 -3
  376. package/src/resources/extensions/gsd/crash-recovery.ts +3 -9
  377. package/src/resources/extensions/gsd/db/engine.ts +809 -0
  378. package/src/resources/extensions/gsd/db/queries.ts +490 -0
  379. package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
  380. package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
  381. package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
  382. package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
  383. package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
  384. package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
  385. package/src/resources/extensions/gsd/dispatch-guard.ts +8 -31
  386. package/src/resources/extensions/gsd/doctor-environment.ts +5 -13
  387. package/src/resources/extensions/gsd/doctor-format.ts +12 -7
  388. package/src/resources/extensions/gsd/doctor-git-checks.ts +3 -3
  389. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +22 -17
  390. package/src/resources/extensions/gsd/engine-hook-contract.ts +79 -0
  391. package/src/resources/extensions/gsd/error-classifier.ts +11 -0
  392. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  393. package/src/resources/extensions/gsd/files.ts +33 -12
  394. package/src/resources/extensions/gsd/git-service.ts +1 -0
  395. package/src/resources/extensions/gsd/gitignore.ts +3 -0
  396. package/src/resources/extensions/gsd/gsd-db.ts +173 -2373
  397. package/src/resources/extensions/gsd/guidance.ts +217 -0
  398. package/src/resources/extensions/gsd/guided-flow.ts +50 -5
  399. package/src/resources/extensions/gsd/markdown-renderer.ts +11 -0
  400. package/src/resources/extensions/gsd/mcp-filter.ts +2 -23
  401. package/src/resources/extensions/gsd/mcp-tool-name.ts +6 -11
  402. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
  403. package/src/resources/extensions/gsd/migrate/safety.ts +18 -7
  404. package/src/resources/extensions/gsd/migration-auto-check.ts +28 -3
  405. package/src/resources/extensions/gsd/milestone-closeout.ts +13 -23
  406. package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
  407. package/src/resources/extensions/gsd/model-router.ts +3 -0
  408. package/src/resources/extensions/gsd/notification-store.ts +26 -3
  409. package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
  410. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -7
  411. package/src/resources/extensions/gsd/parsers-legacy.ts +16 -4
  412. package/src/resources/extensions/gsd/paths.ts +42 -22
  413. package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
  414. package/src/resources/extensions/gsd/preferences-models.ts +12 -47
  415. package/src/resources/extensions/gsd/preferences.ts +18 -0
  416. package/src/resources/extensions/gsd/prompts/complete-slice.md +2 -2
  417. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  418. package/src/resources/extensions/gsd/prompts/refine-slice.md +1 -1
  419. package/src/resources/extensions/gsd/prompts/replan-slice.md +1 -1
  420. package/src/resources/extensions/gsd/prompts/run-uat.md +6 -4
  421. package/src/resources/extensions/gsd/prompts/system.md +5 -2
  422. package/src/resources/extensions/gsd/provider-error-guidance.ts +4 -9
  423. package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
  424. package/src/resources/extensions/gsd/publication.ts +122 -0
  425. package/src/resources/extensions/gsd/reactive-graph.ts +11 -1
  426. package/src/resources/extensions/gsd/recovery-classification.ts +47 -88
  427. package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
  428. package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
  429. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
  430. package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
  431. package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
  432. package/src/resources/extensions/gsd/state.ts +9 -21
  433. package/src/resources/extensions/gsd/status-guards.ts +59 -8
  434. package/src/resources/extensions/gsd/stop-notice.ts +75 -0
  435. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +123 -0
  436. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +22 -0
  437. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +101 -26
  438. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +3 -1
  439. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
  440. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
  441. package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
  442. package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
  443. package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
  444. package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
  445. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +66 -1
  446. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +44 -0
  447. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +8 -7
  448. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  449. package/src/resources/extensions/gsd/tests/consent-question.test.ts +336 -0
  450. package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +67 -0
  451. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +10 -10
  452. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
  453. package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +273 -0
  454. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +2 -1
  455. package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
  456. package/src/resources/extensions/gsd/tests/engine-hook-contract.test.ts +148 -0
  457. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
  458. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
  459. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
  460. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
  461. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
  462. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +27 -0
  463. package/src/resources/extensions/gsd/tests/guidance.test.ts +148 -0
  464. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +58 -15
  465. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +74 -59
  466. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
  467. package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
  468. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +199 -0
  469. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
  470. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +85 -1
  471. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
  472. package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
  473. package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
  474. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +18 -0
  475. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +139 -0
  476. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
  477. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +124 -6
  478. package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
  479. package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
  480. package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
  481. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +248 -1
  482. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +1 -0
  483. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
  484. package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
  485. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +43 -6
  486. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
  487. package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
  488. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
  489. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +76 -0
  490. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +8 -0
  491. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +155 -0
  492. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +112 -29
  493. package/src/resources/extensions/gsd/tests/unit-closeout.test.ts +209 -0
  494. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +67 -2
  495. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
  496. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +44 -1
  497. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +2 -2
  498. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +2 -2
  499. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
  500. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +22 -1
  501. package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
  502. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
  503. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +3 -1
  504. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
  505. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
  506. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +358 -0
  507. package/src/resources/extensions/gsd/tests/write-gate.test.ts +109 -1
  508. package/src/resources/extensions/gsd/tool-presentation-plan.ts +4 -4
  509. package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
  510. package/src/resources/extensions/gsd/tools/complete-slice.ts +43 -68
  511. package/src/resources/extensions/gsd/tools/exec-tool.ts +9 -8
  512. package/src/resources/extensions/gsd/tools/plan-slice.ts +12 -6
  513. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +11 -38
  514. package/src/resources/extensions/gsd/tools/reopen-slice.ts +14 -42
  515. package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
  516. package/src/resources/extensions/gsd/uat-policy.ts +62 -16
  517. package/src/resources/extensions/gsd/undo.ts +9 -8
  518. package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
  519. package/src/resources/extensions/gsd/unit-context-composer.ts +111 -1
  520. package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
  521. package/src/resources/extensions/gsd/unit-registry.ts +412 -0
  522. package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -192
  523. package/src/resources/extensions/gsd/verdict-parser.ts +1 -1
  524. package/src/resources/extensions/gsd/web-app-uat.ts +51 -8
  525. package/src/resources/extensions/gsd/workflow-tool-surface.ts +4 -1
  526. package/src/resources/extensions/gsd/worktree-git-recovery.ts +314 -0
  527. package/src/resources/extensions/gsd/worktree-lifecycle.ts +13 -9
  528. package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
  529. package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
  530. package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
  531. package/src/resources/extensions/gsd/worktree-root.ts +29 -6
  532. package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
  533. package/src/resources/extensions/gsd/worktree-session-state.ts +11 -11
  534. package/src/resources/extensions/search-the-web/native-search.ts +5 -3
  535. package/src/resources/extensions/shared/browser-contract.ts +66 -0
  536. package/src/resources/extensions/shared/gsd-browser-cli.ts +119 -5
  537. package/src/resources/shared/package.json +3 -0
  538. package/src/resources/skills/create-skill/references/executable-code.md +1 -1
  539. package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
  540. package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
  541. package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
  542. package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  543. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  544. package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  545. package/src/resources/skills/gsd-browser/SKILL.md +1 -1
  546. package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
  547. package/dist/resources/extensions/gsd/user-input-boundary.js +0 -218
  548. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +0 -173
  549. package/src/resources/extensions/gsd/user-input-boundary.ts +0 -216
  550. /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → jmTLg6xZmAuq_LIqKOxrH}/_buildManifest.js +0 -0
  551. /package/dist/web/standalone/.next/static/{3PtrU9qGPEXwNLWkIyiqk → jmTLg6xZmAuq_LIqKOxrH}/_ssgManifest.js +0 -0
@@ -131,6 +131,48 @@ export function findTransition(
131
131
  );
132
132
  }
133
133
 
134
+ /**
135
+ * Edge-keyed legality check for the Phase Transition Invariant (ADR-030).
136
+ * `advance()` derives the next Phase and asserts the (from → to) edge here.
137
+ *
138
+ * The matrix is an assertion, not a decision-maker — `deriveState` already
139
+ * chose the Phase. A self-edge is trivially legal (no transition to assert). An
140
+ * edge is legal when some matrix entry permits it, honoring the `*` wildcard
141
+ * rows (e.g. any → blocked via manual-block, any → executing via
142
+ * retryable-failure).
143
+ *
144
+ * Note: the matrix is currently a sparse hardening spec, not a complete
145
+ * legal-edge graph, so `advance()` consumes this in advisory mode (telemetry
146
+ * only). It must be expanded to cover every edge `deriveState` emits before
147
+ * enforcement flips on.
148
+ */
149
+ export function isLegalEdge(from: Phase, to: Phase): boolean {
150
+ if (from === to) return true;
151
+ return STATE_TRANSITION_MATRIX.some(
152
+ (entry) => (entry.from === from || entry.from === "*") && entry.to === to,
153
+ );
154
+ }
155
+
156
+ /**
157
+ * Thrown when an illegal derived Phase edge survives reconciliation. Carries
158
+ * both endpoints so Recovery Classification can report them. Recognized by
159
+ * class in `classifyFailure` and mapped to the `illegal-transition` kind.
160
+ */
161
+ export class IllegalPhaseTransitionError extends Error {
162
+ // Explicit fields, not constructor parameter properties — strip-types
163
+ // consumers (workspace-index subprocess, integration tests) reject the
164
+ // parameter-property syntax with ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX.
165
+ readonly from: Phase;
166
+ readonly to: Phase;
167
+
168
+ constructor(from: Phase, to: Phase) {
169
+ super(`Illegal phase transition ${from} -> ${to} survived reconciliation`);
170
+ this.name = "IllegalPhaseTransitionError";
171
+ this.from = from;
172
+ this.to = to;
173
+ }
174
+ }
175
+
134
176
  export function validateTransitionMatrix(requiredEvents: readonly string[]): MatrixValidationResult {
135
177
  const seen = new Set<string>();
136
178
  const duplicateKeys: string[] = [];
@@ -13,6 +13,11 @@ import type {
13
13
  MilestoneRegistryEntry,
14
14
  } from './types.js';
15
15
 
16
+ // Pre-migration fallback ONLY (ADR-017): deriveState must work on projects
17
+ // whose DB does not exist yet (before md-importer runs), so it parses markdown
18
+ // projections when `isDbAvailable()` is false or the DB has no rows. Once the
19
+ // DB is populated, decision reads go through gsd-db queries — these parsers
20
+ // must never be consulted when DB data is present.
16
21
  import {
17
22
  parseRoadmap,
18
23
  parsePlan,
@@ -71,27 +76,10 @@ import {
71
76
  readinessNeedsDiscussion,
72
77
  } from './milestone-readiness.js';
73
78
 
74
- function formatNeedsAttentionBlocker(milestoneId: string): string {
75
- return [
76
- `Milestone ${milestoneId} is blocked because milestone validation returned needs-attention.`,
77
- `Fix options:`,
78
- `1. Review the validation details: \`/gsd status\``,
79
- `2. If you fixed the missing evidence or issue, re-run milestone validation: \`/gsd validate-milestone\``,
80
- `3. If the finding is acceptable, override it: \`/gsd verdict pass --rationale "why this is okay"\``,
81
- `4. If this should wait, defer it explicitly: \`/gsd park ${milestoneId}\``,
82
- `After validation or override passes, run \`/gsd auto\` to complete and merge the milestone.`,
83
- ].join("\n");
84
- }
85
-
86
- function formatNeedsRemediationBlocker(milestoneId: string): string {
87
- return [
88
- `Milestone ${milestoneId} is blocked because milestone validation returned needs-remediation, but all slices are complete.`,
89
- `Fix options:`,
90
- `1. Run \`/gsd dispatch reassess\` to add remediation slices, then run \`/gsd auto\``,
91
- `2. If the finding is acceptable, override it: \`/gsd verdict pass --rationale "why this is okay"\``,
92
- `3. If this should wait, defer it explicitly: \`/gsd park ${milestoneId}\``,
93
- ].join("\n");
94
- }
79
+ import {
80
+ needsAttentionBlockerGuidance as formatNeedsAttentionBlocker,
81
+ needsRemediationBlockerGuidance as formatNeedsRemediationBlocker,
82
+ } from './guidance.js';
95
83
 
96
84
  /**
97
85
  * A "ghost" milestone directory contains only META.json (and no substantive
@@ -1,17 +1,68 @@
1
1
  /**
2
- * Status predicates for GSD state-machine guards.
2
+ * Status predicates and the canonical status vocabulary for GSD state-machine
3
+ * guards (ADR-030).
3
4
  *
4
- * The DB stores status as free-form strings. Three values indicate
5
- * "closed": "complete" (canonical), "done" (legacy / alias),
6
- * "closed" (legacy/imported), and
7
- * "skipped" (user-directed skip via rethink or backtrack).
8
- * Every inline `status === "complete" || status === "done"` should
9
- * use isClosedStatus() instead.
5
+ * The DB column is free-form `string` so legacy/imported rows still load. Three
6
+ * raw values besides canonical "complete"/"skipped" indicate "closed": "done"
7
+ * (legacy alias), "closed" (legacy/imported), and "skipped" (user-directed skip
8
+ * via rethink or backtrack). `RAW_CLOSED_STATUSES` is the single source for both
9
+ * `isClosedStatus()` and the SQL terminal-status fragment
10
+ * (`db/sql-constants.ts` derives `TERMINAL_STATUS_SQL` from it), replacing the
11
+ * prior independent definitions.
12
+ *
13
+ * `toStatus()` is the single seam where a free-form string becomes the canonical
14
+ * `Status` vocabulary; the Status Transition Core writes canonical, so the store
15
+ * converges over time without a forced migration.
16
+ */
17
+
18
+ /**
19
+ * Canonical, normalized entity-status vocabulary across milestones, slices, and
20
+ * tasks — the single source for both the `Status` type and the runtime
21
+ * membership set. The in-memory domain speaks `Status`; the DB column stays
22
+ * free-form.
23
+ */
24
+ export const CANONICAL_STATUSES = [
25
+ "pending", "queued", "active", "parked", "in_progress", "blocked", "complete", "skipped", "deferred",
26
+ ] as const;
27
+ export type Status = (typeof CANONICAL_STATUSES)[number];
28
+ const CANONICAL_STATUS_SET: ReadonlySet<string> = new Set(CANONICAL_STATUSES);
29
+
30
+ /**
31
+ * Raw status values that mean a unit is closed — the single source of truth.
32
+ * Includes legacy/imported aliases ("done", "closed") alongside canonical
33
+ * "complete"/"skipped" because the DB column is free-form and older rows /
34
+ * imports still carry them. Order matters: `TERMINAL_STATUS_SQL` is derived
35
+ * from this array verbatim.
36
+ */
37
+ export const RAW_CLOSED_STATUSES = ["complete", "done", "skipped", "closed"] as const;
38
+ const RAW_CLOSED_SET: ReadonlySet<string> = new Set(RAW_CLOSED_STATUSES);
39
+
40
+ /** Free-form aliases mapped to their canonical Status on read. */
41
+ const ALIAS_TO_CANONICAL: Readonly<Record<string, Status>> = {
42
+ done: "complete",
43
+ closed: "complete",
44
+ planned: "pending",
45
+ "in-progress": "in_progress",
46
+ };
47
+
48
+ /**
49
+ * Normalize a free-form DB status string into the canonical `Status`
50
+ * vocabulary. Maps known aliases (done/closed → complete, planned → pending,
51
+ * in-progress → in_progress). An unrecognized/legacy value is **quarantined** —
52
+ * preserved verbatim rather than silently remapped to a wrong canonical state —
53
+ * so reads never fail and reconciliation/telemetry can surface it.
10
54
  */
55
+ export function toStatus(raw: string): Status {
56
+ const value = raw.trim();
57
+ if (CANONICAL_STATUS_SET.has(value)) return value as Status;
58
+ const alias = ALIAS_TO_CANONICAL[value];
59
+ if (alias) return alias;
60
+ return value as Status;
61
+ }
11
62
 
12
63
  /** Returns true when a milestone, slice, or task status indicates closure. */
13
64
  export function isClosedStatus(status: string): boolean {
14
- return status === "complete" || status === "done" || status === "skipped" || status === "closed";
65
+ return RAW_CLOSED_SET.has(status);
15
66
  }
16
67
 
17
68
  /** Returns true when a slice status indicates it was deferred by a decision. */
@@ -0,0 +1,75 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Stop Notice module — single owner of the auto/step-mode
3
+ // stop/pause notice vocabulary. Both sides of the wire live here: the
4
+ // formatters that produce the canonical prefixes (used by stopAuto/pauseAuto)
5
+ // and the classifiers that recognize them (used by the headless host to pick
6
+ // exit codes). Wording changes in this file keep emitter and detector in
7
+ // lockstep; round-trip tests enforce it.
8
+
9
+ export type StopNoticeKind = "stopped" | "blocked";
10
+
11
+ /** A reason string of the form "Blocked: …" marks a blocked stop. */
12
+ export function isBlockedStopReason(reason?: string | null): boolean {
13
+ return /^Blocked:\s*/i.test(reason ?? "");
14
+ }
15
+
16
+ /** Strip the "Blocked: " marker for display. */
17
+ export function stopNoticeDisplayReason(reason?: string | null): string {
18
+ return (reason ?? "").replace(/^Blocked:\s*/i, "").trim();
19
+ }
20
+
21
+ export function stopNoticeKind(reason?: string | null): StopNoticeKind {
22
+ return isBlockedStopReason(reason) ? "blocked" : "stopped";
23
+ }
24
+
25
+ /** Canonical stop-notice prefix: "Auto-mode blocked — reason" / "Auto-mode stopped". */
26
+ export function formatStopNoticePrefix(reason?: string | null): string {
27
+ const displayReason = stopNoticeDisplayReason(reason);
28
+ const prefix = stopNoticeKind(reason) === "blocked" ? "Auto-mode blocked" : "Auto-mode stopped";
29
+ return displayReason ? `${prefix} — ${displayReason}` : prefix;
30
+ }
31
+
32
+ // ─── Classification (headless host side) ────────────────────────────────
33
+ // The canonical lowercase prefixes the headless event loop recognizes in
34
+ // notify messages. Emitters above and ad-hoc emitters elsewhere must start
35
+ // their terminal notices with one of these.
36
+
37
+ export const PAUSED_NOTICE_PREFIXES = ["auto-mode paused", "step-mode paused"] as const;
38
+
39
+ export const TERMINAL_NOTICE_PREFIXES = [
40
+ "auto-mode stopped",
41
+ "step-mode stopped",
42
+ "auto-mode complete",
43
+ "no active milestone",
44
+ "auto-mode idle",
45
+ ] as const;
46
+
47
+ /** Manual-resolution notices emitted before auto-mode can formally pause/stop. */
48
+ export function isManualResolutionNotice(message: string): boolean {
49
+ return (
50
+ message.includes("resolve manually and re-run /gsd auto") ||
51
+ message.includes("resolve conflicts manually and run /gsd auto to resume") ||
52
+ message.includes("resolve and run /gsd auto to resume")
53
+ );
54
+ }
55
+
56
+ export function isPauseNotice(message: string): boolean {
57
+ return PAUSED_NOTICE_PREFIXES.some((prefix) => message.startsWith(prefix));
58
+ }
59
+
60
+ export function isTerminalNotice(message: string): boolean {
61
+ return TERMINAL_NOTICE_PREFIXES.some((prefix) => message.startsWith(prefix));
62
+ }
63
+
64
+ /** Pauses that do not require operator intervention in headless mode. */
65
+ export function isNonBlockingPauseNotice(message: string): boolean {
66
+ return message.includes("idempotent advance: unit already active");
67
+ }
68
+
69
+ export function isBlockedNoticeMessage(message: string): boolean {
70
+ return (
71
+ message.includes("blocked:") ||
72
+ (isPauseNotice(message) && !isNonBlockingPauseNotice(message)) ||
73
+ isManualResolutionNotice(message)
74
+ );
75
+ }
@@ -5517,6 +5517,129 @@ test("dispatch Worktree Safety wins before stuck detection for execute-task with
5517
5517
  );
5518
5518
  });
5519
5519
 
5520
+ test("dispatch Worktree Safety honors degraded branch fallback instead of demanding the canonical worktree root", async (t) => {
5521
+ _resetPendingResolve();
5522
+
5523
+ const ctx = makeMockCtx();
5524
+ const pi = makeMockPi();
5525
+ const notifications: string[] = [];
5526
+ ctx.ui.notify = (msg: string) => { notifications.push(msg); };
5527
+
5528
+ // Worktree creation failed and the lifecycle fell back to the milestone
5529
+ // branch in the project root. The safety gate must validate against that
5530
+ // effective branch mode, not the configured worktree mode.
5531
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-wt-safety-degraded-"));
5532
+ t.after(() => rmSync(projectRoot, { recursive: true, force: true }));
5533
+
5534
+ const s = makeLoopSession({
5535
+ basePath: projectRoot,
5536
+ originalBasePath: projectRoot,
5537
+ canonicalProjectRoot: projectRoot,
5538
+ isolationDegraded: true,
5539
+ });
5540
+ const deps = makeMockDeps({
5541
+ getIsolationMode: () => "worktree",
5542
+ });
5543
+ const result = await runDispatch(
5544
+ {
5545
+ ctx,
5546
+ pi,
5547
+ s,
5548
+ deps,
5549
+ prefs: undefined,
5550
+ iteration: 1,
5551
+ flowId: "test-flow",
5552
+ nextSeq: () => 1,
5553
+ },
5554
+ {
5555
+ state: {
5556
+ phase: "executing",
5557
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
5558
+ activeSlice: { id: "S01", title: "Slice 1" },
5559
+ activeTask: { id: "T01" },
5560
+ registry: [{ id: "M001", status: "active" }],
5561
+ blockers: [],
5562
+ } as any,
5563
+ mid: "M001",
5564
+ midTitle: "Test",
5565
+ },
5566
+ {
5567
+ recentUnits: [],
5568
+ stuckRecoveryAttempts: 0,
5569
+ consecutiveFinalizeTimeouts: 0,
5570
+ },
5571
+ );
5572
+
5573
+ assert.equal(result.action, "next", "dispatch must proceed under degraded branch isolation");
5574
+ assert.ok(
5575
+ !notifications.some((n) => n.includes("Worktree Safety failed")),
5576
+ "degraded branch fallback must not trip a false invalid-root",
5577
+ );
5578
+ assert.ok(!deps.callLog.includes("stopAuto"), "auto-mode must not stop on the degraded fallback");
5579
+ });
5580
+
5581
+ test("dispatch Worktree Safety honors stranded branch recovery instead of demanding the canonical worktree root", async (t) => {
5582
+ _resetPendingResolve();
5583
+
5584
+ const ctx = makeMockCtx();
5585
+ const pi = makeMockPi();
5586
+ const notifications: string[] = [];
5587
+ ctx.ui.notify = (msg: string) => { notifications.push(msg); };
5588
+
5589
+ // Bootstrap adopted stranded work by checking out the milestone branch in
5590
+ // the project root (strandedRecoveryIsolationMode = "branch"). Isolation is
5591
+ // NOT degraded — the adoption is intentional. The safety gate must validate
5592
+ // against the effective branch mode, not the configured worktree mode.
5593
+ const projectRoot = mkdtempSync(join(tmpdir(), "gsd-wt-safety-stranded-"));
5594
+ t.after(() => rmSync(projectRoot, { recursive: true, force: true }));
5595
+
5596
+ const s = makeLoopSession({
5597
+ basePath: projectRoot,
5598
+ originalBasePath: projectRoot,
5599
+ canonicalProjectRoot: projectRoot,
5600
+ strandedRecoveryIsolationMode: "branch",
5601
+ });
5602
+ const deps = makeMockDeps({
5603
+ getIsolationMode: () => "worktree",
5604
+ });
5605
+ const result = await runDispatch(
5606
+ {
5607
+ ctx,
5608
+ pi,
5609
+ s,
5610
+ deps,
5611
+ prefs: undefined,
5612
+ iteration: 1,
5613
+ flowId: "test-flow",
5614
+ nextSeq: () => 1,
5615
+ },
5616
+ {
5617
+ state: {
5618
+ phase: "executing",
5619
+ activeMilestone: { id: "M001", title: "Test", status: "active" },
5620
+ activeSlice: { id: "S01", title: "Slice 1" },
5621
+ activeTask: { id: "T01" },
5622
+ registry: [{ id: "M001", status: "active" }],
5623
+ blockers: [],
5624
+ } as any,
5625
+ mid: "M001",
5626
+ midTitle: "Test",
5627
+ },
5628
+ {
5629
+ recentUnits: [],
5630
+ stuckRecoveryAttempts: 0,
5631
+ consecutiveFinalizeTimeouts: 0,
5632
+ },
5633
+ );
5634
+
5635
+ assert.equal(result.action, "next", "dispatch must proceed under stranded branch recovery");
5636
+ assert.ok(
5637
+ !notifications.some((n) => n.includes("Worktree Safety failed")),
5638
+ "stranded branch recovery must not trip a false invalid-root",
5639
+ );
5640
+ assert.ok(!deps.callLog.includes("stopAuto"), "auto-mode must not stop on stranded branch recovery");
5641
+ });
5642
+
5520
5643
  test("runDispatch runs stuck detection while artifact verification retry is pending (#5719)", async (t) => {
5521
5644
  _resetPendingResolve();
5522
5645
 
@@ -857,3 +857,25 @@ test("resolveModelId: claude-code wins when session is claude-code regardless of
857
857
  assert.ok(result, "should resolve a model");
858
858
  assert.equal(result.provider, "claude-code", "claude-code must win when it is the session provider");
859
859
  });
860
+
861
+ test("resolveModelId: openai-codex wins over openai for bare GPT IDs when both are available", () => {
862
+ const availableModels = [
863
+ { id: "gpt-5.5", provider: "openai" },
864
+ { id: "gpt-5.5", provider: "openai-codex" },
865
+ ];
866
+
867
+ const result = resolveModelId("gpt-5.5", availableModels, undefined);
868
+ assert.ok(result, "should resolve a model");
869
+ assert.equal(result.provider, "openai-codex", "ChatGPT OAuth must win over platform API for bare IDs");
870
+ });
871
+
872
+ test("resolveModelId: github-copilot wins over openai when both offer the same GPT model", () => {
873
+ const availableModels = [
874
+ { id: "gpt-5.5", provider: "openai" },
875
+ { id: "gpt-5.5", provider: "github-copilot" },
876
+ ];
877
+
878
+ const result = resolveModelId("gpt-5.5", availableModels, undefined);
879
+ assert.ok(result);
880
+ assert.equal(result.provider, "github-copilot");
881
+ });
@@ -22,8 +22,8 @@ import {
22
22
  createAutoOrchestrator,
23
23
  decideOrchestratorDispatch,
24
24
  resolveLiveOrchestratorBasePath,
25
- STUCK_WINDOW_SIZE,
26
25
  } from "../auto/orchestrator.js";
26
+ import { STUCK_WINDOW_SIZE } from "../auto/dispatch-history.js";
27
27
  import type { OrchestratorContext } from "../auto/orchestrator.js";
28
28
  import type { AutoOrchestrationModule, AutoSessionContext } from "../auto/contracts.js";
29
29
  import type { GSDState } from "../types.js";
@@ -41,6 +41,10 @@ import {
41
41
  openDatabase,
42
42
  } from "../gsd-db.js";
43
43
  import { AutoSession } from "../auto/session.js";
44
+ import { registerAutoWorker } from "../db/auto-workers.js";
45
+ import { claimMilestoneLease } from "../db/milestone-leases.js";
46
+ import { recordDispatchClaim, markFailed } from "../db/unit-dispatches.js";
47
+ import { normalizeRealPath } from "../paths.js";
44
48
  import { acquireSessionLock, releaseSessionLock } from "../session-lock.js";
45
49
  import { queryJournal } from "../journal.js";
46
50
  import { invalidateAllCaches } from "../cache.js";
@@ -518,13 +522,12 @@ test("advance() is idempotent for the same active unit", async (t) => {
518
522
  if (first.kind === "advanced") {
519
523
  assert.deepEqual(first.unit, { unitType: "execute-task", unitId: "M001/S01/T01" });
520
524
  }
521
- assert.equal(second.kind, "blocked");
522
- if (second.kind !== "blocked") return;
525
+ assert.equal(second.kind, "skipped");
526
+ if (second.kind !== "skipped") return;
523
527
  assert.equal(second.reason, "idempotent advance: unit already active");
524
- assert.equal(second.action, "pause");
525
528
  });
526
529
 
527
- test("idempotency block fires with its own reason before saturation", async (t) => {
530
+ test("idempotency skip fires with its own reason before saturation", async (t) => {
528
531
  const f = makeFixture();
529
532
  t.after(() => f.cleanup());
530
533
 
@@ -532,10 +535,9 @@ test("idempotency block fires with its own reason before saturation", async (t)
532
535
  const second = await f.orchestrator.advance();
533
536
 
534
537
  assert.equal(first.kind, "advanced");
535
- assert.equal(second.kind, "blocked");
536
- if (second.kind !== "blocked") return;
538
+ assert.equal(second.kind, "skipped");
539
+ if (second.kind !== "skipped") return;
537
540
  assert.equal(second.reason, "idempotent advance: unit already active");
538
- assert.equal(second.action, "pause");
539
541
  });
540
542
 
541
543
  test("completeActiveUnit clears in-flight idempotency and stops stale same-unit advance", async (t) => {
@@ -671,12 +673,12 @@ test("resume() clears idempotent lock and allows re-advance", async (t) => {
671
673
  t.after(() => f.cleanup());
672
674
 
673
675
  const first = await f.orchestrator.advance();
674
- const blocked = await f.orchestrator.advance();
676
+ const idempotent = await f.orchestrator.advance();
675
677
  const resumed = await f.orchestrator.resume();
676
678
  const next = await f.orchestrator.advance();
677
679
 
678
680
  assert.equal(first.kind, "advanced");
679
- assert.equal(blocked.kind, "blocked");
681
+ assert.equal(idempotent.kind, "skipped");
680
682
  assert.equal(resumed.kind, "resumed");
681
683
  assert.equal(next.kind, "advanced");
682
684
  });
@@ -686,11 +688,11 @@ test("start() clears prior idempotent lock", async (t) => {
686
688
  t.after(() => f.cleanup());
687
689
 
688
690
  await f.orchestrator.advance();
689
- const blocked = await f.orchestrator.advance();
691
+ const idempotent = await f.orchestrator.advance();
690
692
  const restarted = await f.orchestrator.start(SESSION_CONTEXT);
691
693
  const next = await f.orchestrator.advance();
692
694
 
693
- assert.equal(blocked.kind, "blocked");
695
+ assert.equal(idempotent.kind, "skipped");
694
696
  assert.equal(restarted.kind, "started");
695
697
  assert.equal(next.kind, "advanced");
696
698
  });
@@ -700,32 +702,28 @@ test("stop() clears idempotent unit lock so advance can run again", async (t) =>
700
702
  t.after(() => f.cleanup());
701
703
 
702
704
  const first = await f.orchestrator.advance();
703
- const blocked = await f.orchestrator.advance();
705
+ const idempotent = await f.orchestrator.advance();
704
706
  const stopped = await f.orchestrator.stop("reset");
705
707
  const second = await f.orchestrator.advance();
706
708
 
707
709
  assert.equal(first.kind, "advanced");
708
- assert.equal(blocked.kind, "blocked");
710
+ assert.equal(idempotent.kind, "skipped");
709
711
  assert.equal(stopped.kind, "stopped");
710
712
  assert.equal(second.kind, "advanced");
711
713
  });
712
714
 
713
- test("blocked path journals advance-blocked and records a health snapshot", async (t) => {
715
+ test("idempotent path journals advance-skipped and records a health snapshot", async (t) => {
714
716
  const f = makeFixture();
715
717
  t.after(() => f.cleanup());
716
718
 
717
719
  await f.orchestrator.advance();
718
720
  await f.orchestrator.advance();
719
721
 
720
- assert.ok(f.journalNames().includes("advance-blocked"));
722
+ assert.ok(f.journalNames().includes("advance-skipped"));
721
723
  });
722
724
 
723
725
  // ─── Stuck-loop ring buffer (issue #5787) ──────────────────────────────────
724
726
 
725
- test("STUCK_WINDOW_SIZE matches the legacy auto/phases.ts constant", () => {
726
- assert.equal(STUCK_WINDOW_SIZE, 6);
727
- });
728
-
729
727
  test("stuck-loop: empty ring on a freshly constructed orchestrator advances normally", async (t) => {
730
728
  const f = makeFixture();
731
729
  t.after(() => f.cleanup());
@@ -761,21 +759,24 @@ test("stuck-loop: ring saturated with same unit blocks with action 'stop' and st
761
759
  // First call advances.
762
760
  assert.equal(results[0].kind, "advanced");
763
761
 
764
- // Intermediate calls are blocked by idempotency (not stuck-loop yet).
762
+ // Intermediate calls are skipped by idempotency (not stuck-loop yet).
765
763
  for (let i = 1; i < STUCK_WINDOW_SIZE - 1; i++) {
766
764
  const r = results[i];
767
- assert.equal(r.kind, "blocked", `round ${i} should be blocked`);
768
- if (r.kind !== "blocked") return;
765
+ assert.equal(r.kind, "skipped", `round ${i} should be skipped`);
766
+ if (r.kind !== "skipped") return;
769
767
  assert.equal(r.reason, "idempotent advance: unit already active");
770
- assert.equal(r.action, "pause");
771
768
  }
772
769
 
773
- // The final call (ring now holds STUCK_WINDOW_SIZE copies) returns stuck-loop.
770
+ // The final call (ring now holds STUCK_WINDOW_SIZE copies) returns stuck-loop
771
+ // with the detect-stuck rule verdict in the reason.
774
772
  const last = results[STUCK_WINDOW_SIZE - 1];
775
773
  assert.equal(last.kind, "blocked");
776
774
  if (last.kind !== "blocked") return;
777
775
  assert.equal(last.action, "stop");
778
- assert.equal(last.reason, `stuck-loop: execute-task:M001/S01/T01 picked ${STUCK_WINDOW_SIZE} times`);
776
+ assert.ok(
777
+ last.reason.startsWith("stuck-loop: execute-task:M001/S01/T01 derived"),
778
+ `expected detect-stuck verdict reason, got: ${last.reason}`,
779
+ );
779
780
  });
780
781
 
781
782
  test("stuck-loop: start() resets the ring so a fresh saturation cycle is required", async (t) => {
@@ -855,6 +856,80 @@ test("stuck-loop: stop('user-request') resets the ring (hard stop)", async (t) =
855
856
  assert.equal(next.kind, "advanced");
856
857
  });
857
858
 
859
+ test("stuck-loop #482 regression: start() rehydrates the window from the dispatch ledger so cross-session re-dispatch loops are detected", async (t) => {
860
+ const f = makeFixture();
861
+ t.after(() => f.cleanup());
862
+
863
+ // Simulate a PRIOR session: the dispatch ledger recorded the same unit
864
+ // being re-dispatched repeatedly without progress. The orchestrator under test is a
865
+ // fresh instance (as it would be after a session restart) — before the
866
+ // Dispatch History module, start() reset the window to [] and the loop
867
+ // would silently re-dispatch the unit forever (#482: 146 re-dispatches).
868
+ const worker = registerAutoWorker({ projectRootRealpath: normalizeRealPath(f.base) });
869
+ const lease = claimMilestoneLease(worker, "M001");
870
+ assert.equal(lease.ok, true);
871
+ if (!lease.ok) return;
872
+ for (let i = 0; i < STUCK_WINDOW_SIZE - 1; i++) {
873
+ const claim = recordDispatchClaim({
874
+ traceId: `prior-session-${i}`,
875
+ workerId: worker,
876
+ milestoneLeaseToken: lease.token,
877
+ milestoneId: "M001",
878
+ unitType: "execute-task",
879
+ unitId: "M001/S01/T01",
880
+ });
881
+ assert.equal(claim.ok, true);
882
+ if (!claim.ok) return;
883
+ markFailed(claim.dispatchId, { errorSummary: "" });
884
+ }
885
+
886
+ const started = await f.orchestrator.start(SESSION_CONTEXT);
887
+ assert.equal(started.kind, "started");
888
+
889
+ // The very next decision for the same unit must trip the stuck verdict
890
+ // instead of advancing.
891
+ const result = await f.orchestrator.advance();
892
+ assert.equal(result.kind, "blocked");
893
+ if (result.kind !== "blocked") return;
894
+ assert.equal(result.action, "stop");
895
+ assert.ok(result.reason.startsWith("stuck-loop:"), `expected stuck-loop reason, got: ${result.reason}`);
896
+ });
897
+
898
+ test("stuck-loop #482: resume() with an empty window rehydrates from the dispatch ledger", async (t) => {
899
+ const f = makeFixture();
900
+ t.after(() => f.cleanup());
901
+
902
+ const worker = registerAutoWorker({ projectRootRealpath: normalizeRealPath(f.base) });
903
+ const lease = claimMilestoneLease(worker, "M001");
904
+ assert.equal(lease.ok, true);
905
+ if (!lease.ok) return;
906
+ for (let i = 0; i < STUCK_WINDOW_SIZE - 1; i++) {
907
+ const claim = recordDispatchClaim({
908
+ traceId: `prior-session-resume-${i}`,
909
+ workerId: worker,
910
+ milestoneLeaseToken: lease.token,
911
+ milestoneId: "M001",
912
+ unitType: "execute-task",
913
+ unitId: "M001/S01/T01",
914
+ });
915
+ assert.equal(claim.ok, true);
916
+ if (!claim.ok) return;
917
+ markFailed(claim.dispatchId, { errorSummary: "" });
918
+ }
919
+
920
+ // Fresh orchestrator resuming a prior session: window starts empty, so
921
+ // resume() must rehydrate (while in-process resume keeps the live window —
922
+ // see the #572 preservation tests above).
923
+ const resumed = await f.orchestrator.resume();
924
+ assert.equal(resumed.kind, "resumed");
925
+
926
+ const result = await f.orchestrator.advance();
927
+ assert.equal(result.kind, "blocked");
928
+ if (result.kind !== "blocked") return;
929
+ assert.equal(result.action, "stop");
930
+ assert.ok(result.reason.startsWith("stuck-loop:"), `expected stuck-loop reason, got: ${result.reason}`);
931
+ });
932
+
858
933
  test("stuck-loop: journal records the stuck-loop reason on advance-blocked", async (t) => {
859
934
  const f = makeFixture();
860
935
  t.after(() => f.cleanup());
@@ -306,7 +306,9 @@ test("pauseAuto records the expected worktree path when paused from project root
306
306
 
307
307
  const meta = readPausedSessionMetadata(base);
308
308
  assert.ok(meta);
309
- assert.equal(meta.worktreePath, join(base, ".gsd", "worktrees", "M001"));
309
+ // No worktree exists yet, so the recorded path is the canonical
310
+ // .gsd-worktrees/ creation location (worktree-placement seam).
311
+ assert.equal(meta.worktreePath, join(base, ".gsd-worktrees", "M001"));
310
312
  } finally {
311
313
  autoSession.reset();
312
314
  try {