@opengsd/gsd-pi 1.1.1-dev.b2556262 → 1.2.0-dev.0b870afa

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 (934) hide show
  1. package/dist/cli-style.d.ts +17 -0
  2. package/dist/cli-style.js +28 -0
  3. package/dist/cli-web-branch.d.ts +2 -0
  4. package/dist/cli-web-branch.js +9 -2
  5. package/dist/cli.js +1 -1
  6. package/dist/headless-events.d.ts +4 -2
  7. package/dist/headless-events.js +14 -34
  8. package/dist/help-text.js +5 -0
  9. package/dist/mcp-server.js +2 -1
  10. package/dist/models-resolver.d.ts +3 -13
  11. package/dist/models-resolver.js +3 -22
  12. package/dist/project-sessions.js +4 -2
  13. package/dist/resource-loader.js +2 -14
  14. package/dist/resources/.managed-resources-content-hash +1 -1
  15. package/dist/resources/GSD-WORKFLOW.md +5 -4
  16. package/dist/resources/extensions/ask-user-questions.js +78 -23
  17. package/dist/resources/extensions/async-jobs/async-bash-tool.js +30 -64
  18. package/dist/resources/extensions/async-jobs/await-tool.js +80 -12
  19. package/dist/resources/extensions/async-jobs/index.js +65 -0
  20. package/dist/resources/extensions/async-jobs/job-manager.js +12 -1
  21. package/dist/resources/extensions/bg-shell/bg-shell-command.js +6 -6
  22. package/dist/resources/extensions/bg-shell/bg-shell-tool.js +10 -7
  23. package/dist/resources/extensions/bg-shell/overlay.js +9 -6
  24. package/dist/resources/extensions/bg-shell/process-manager.js +54 -25
  25. package/dist/resources/extensions/bg-shell/readiness-detector.js +11 -0
  26. package/dist/resources/extensions/bg-shell/utilities.js +5 -2
  27. package/dist/resources/extensions/browser-tools/engine/managed-gsd-browser.js +209 -88
  28. package/dist/resources/extensions/browser-tools/engine/selection.js +73 -5
  29. package/dist/resources/extensions/browser-tools/index.js +69 -12
  30. package/dist/resources/extensions/claude-code-cli/models.js +9 -0
  31. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +139 -243
  32. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +224 -0
  33. package/dist/resources/extensions/github-sync/templates.js +3 -3
  34. package/dist/resources/extensions/gsd/artifact-projection.js +14 -0
  35. package/dist/resources/extensions/gsd/auto/contracts.js +8 -1
  36. package/dist/resources/extensions/gsd/auto/custom-verify-retry-store.js +17 -2
  37. package/dist/resources/extensions/gsd/auto/detect-stuck.js +33 -13
  38. package/dist/resources/extensions/gsd/auto/dispatch-history.js +105 -0
  39. package/dist/resources/extensions/gsd/auto/dispatch-key.js +37 -0
  40. package/dist/resources/extensions/gsd/auto/loop.js +77 -56
  41. package/dist/resources/extensions/gsd/auto/orchestrator.js +860 -96
  42. package/dist/resources/extensions/gsd/auto/phases.js +81 -8
  43. package/dist/resources/extensions/gsd/auto/run-unit.js +2 -1
  44. package/dist/resources/extensions/gsd/auto/session.js +6 -0
  45. package/dist/resources/extensions/gsd/auto-dashboard.js +16 -4
  46. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -34
  47. package/dist/resources/extensions/gsd/auto-dispatch.js +56 -63
  48. package/dist/resources/extensions/gsd/auto-model-selection.js +44 -13
  49. package/dist/resources/extensions/gsd/auto-post-unit.js +47 -17
  50. package/dist/resources/extensions/gsd/auto-prompts.js +271 -27
  51. package/dist/resources/extensions/gsd/auto-recovery.js +48 -49
  52. package/dist/resources/extensions/gsd/auto-runtime-state.js +17 -0
  53. package/dist/resources/extensions/gsd/auto-start.js +36 -49
  54. package/dist/resources/extensions/gsd/auto-timers.js +16 -2
  55. package/dist/resources/extensions/gsd/auto-tool-tracking.js +55 -0
  56. package/dist/resources/extensions/gsd/auto-unit-closeout.js +45 -21
  57. package/dist/resources/extensions/gsd/auto-unit-tool-scope.js +33 -37
  58. package/dist/resources/extensions/gsd/auto-verification.js +30 -37
  59. package/dist/resources/extensions/gsd/auto-worktree-repair.js +10 -2
  60. package/dist/resources/extensions/gsd/auto-worktree.js +67 -375
  61. package/dist/resources/extensions/gsd/auto.js +112 -486
  62. package/dist/resources/extensions/gsd/blocked-models.js +28 -0
  63. package/dist/resources/extensions/gsd/bootstrap/agent-end-recovery.js +29 -8
  64. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +28 -37
  65. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +43 -49
  66. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +2 -2
  67. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
  68. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +19 -0
  69. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +319 -161
  70. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +365 -58
  71. package/dist/resources/extensions/gsd/branch-patterns.js +2 -0
  72. package/dist/resources/extensions/gsd/browser-daemon-auto-prep.js +83 -0
  73. package/dist/resources/extensions/gsd/browser-evidence.js +8 -2
  74. package/dist/resources/extensions/gsd/captures.js +5 -15
  75. package/dist/resources/extensions/gsd/closeout-consistency-gate.js +21 -4
  76. package/dist/resources/extensions/gsd/closeout-recovery.js +3 -2
  77. package/dist/resources/extensions/gsd/closeout-wizard.js +92 -0
  78. package/dist/resources/extensions/gsd/codebase-generator.js +8 -4
  79. package/dist/resources/extensions/gsd/commands/catalog.js +6 -62
  80. package/dist/resources/extensions/gsd/commands/context.js +16 -2
  81. package/dist/resources/extensions/gsd/commands/handlers/auto.js +3 -0
  82. package/dist/resources/extensions/gsd/commands-handlers.js +66 -3
  83. package/dist/resources/extensions/gsd/commands-inspect.js +4 -8
  84. package/dist/resources/extensions/gsd/commands-maintenance.js +61 -41
  85. package/dist/resources/extensions/gsd/commands-ship.js +2 -2
  86. package/dist/resources/extensions/gsd/commands-verdict.js +12 -2
  87. package/dist/resources/extensions/gsd/consent-question.js +353 -0
  88. package/dist/resources/extensions/gsd/consent-verdict.js +63 -0
  89. package/dist/resources/extensions/gsd/constants.js +0 -2
  90. package/dist/resources/extensions/gsd/crash-recovery.js +12 -15
  91. package/dist/resources/extensions/gsd/db/engine.js +755 -0
  92. package/dist/resources/extensions/gsd/db/queries.js +398 -0
  93. package/dist/resources/extensions/gsd/db/sql-constants.js +11 -0
  94. package/dist/resources/extensions/gsd/db/writers/cascades.js +194 -0
  95. package/dist/resources/extensions/gsd/db/writers/import-restore.js +182 -0
  96. package/dist/resources/extensions/gsd/db/writers/memory.js +149 -0
  97. package/dist/resources/extensions/gsd/db/writers/reconcile.js +458 -0
  98. package/dist/resources/extensions/gsd/db/writers/status.js +70 -0
  99. package/dist/resources/extensions/gsd/db-workspace.js +103 -0
  100. package/dist/resources/extensions/gsd/debug-logger.js +10 -0
  101. package/dist/resources/extensions/gsd/delegation-policy.js +2 -10
  102. package/dist/resources/extensions/gsd/discussion-handoff.js +218 -0
  103. package/dist/resources/extensions/gsd/dispatch-guard.js +10 -35
  104. package/dist/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  105. package/dist/resources/extensions/gsd/doctor-engine-checks.js +5 -5
  106. package/dist/resources/extensions/gsd/doctor-environment.js +5 -11
  107. package/dist/resources/extensions/gsd/doctor-format.js +9 -6
  108. package/dist/resources/extensions/gsd/doctor-git-checks.js +6 -21
  109. package/dist/resources/extensions/gsd/doctor-proactive.js +7 -2
  110. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +21 -16
  111. package/dist/resources/extensions/gsd/doctor.js +16 -9
  112. package/dist/resources/extensions/gsd/engine-hook-contract.js +70 -0
  113. package/dist/resources/extensions/gsd/error-classifier.js +10 -1
  114. package/dist/resources/extensions/gsd/exec-sandbox.js +30 -10
  115. package/dist/resources/extensions/gsd/files.js +33 -19
  116. package/dist/resources/extensions/gsd/git-conflict-state.js +16 -1
  117. package/dist/resources/extensions/gsd/git-service.js +1 -0
  118. package/dist/resources/extensions/gsd/gitignore.js +3 -0
  119. package/dist/resources/extensions/gsd/gsd-command-home.js +22 -12
  120. package/dist/resources/extensions/gsd/gsd-db.js +184 -2048
  121. package/dist/resources/extensions/gsd/guidance.js +158 -0
  122. package/dist/resources/extensions/gsd/guided-flow.js +91 -476
  123. package/dist/resources/extensions/gsd/guided-unit-completion.js +225 -0
  124. package/dist/resources/extensions/gsd/markdown-renderer.js +43 -33
  125. package/dist/resources/extensions/gsd/mcp-filter.js +10 -20
  126. package/dist/resources/extensions/gsd/mcp-tool-name.js +18 -0
  127. package/dist/resources/extensions/gsd/md-importer.js +4 -3
  128. package/dist/resources/extensions/gsd/memory-consolidation-scanner.js +1 -1
  129. package/dist/resources/extensions/gsd/migrate/safety.js +22 -11
  130. package/dist/resources/extensions/gsd/migration-auto-check.js +27 -5
  131. package/dist/resources/extensions/gsd/milestone-closeout-proof.js +72 -0
  132. package/dist/resources/extensions/gsd/milestone-closeout.js +97 -28
  133. package/dist/resources/extensions/gsd/milestone-merge-transaction.js +10 -0
  134. package/dist/resources/extensions/gsd/milestone-planning-persistence.js +156 -0
  135. package/dist/resources/extensions/gsd/milestone-readiness.js +77 -0
  136. package/dist/resources/extensions/gsd/milestone-reopen-events.js +3 -5
  137. package/dist/resources/extensions/gsd/milestone-settlement.js +50 -0
  138. package/dist/resources/extensions/gsd/milestone-validation-evidence.js +73 -0
  139. package/dist/resources/extensions/gsd/milestone-validation-verdict.js +57 -0
  140. package/dist/resources/extensions/gsd/model-cost-table.js +1 -0
  141. package/dist/resources/extensions/gsd/model-router.js +3 -0
  142. package/dist/resources/extensions/gsd/native-git-bridge.js +45 -0
  143. package/dist/resources/extensions/gsd/notification-store.js +11 -4
  144. package/dist/resources/extensions/gsd/parallel-eligibility.js +3 -6
  145. package/dist/resources/extensions/gsd/parallel-merge.js +14 -11
  146. package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +11 -7
  147. package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -2
  148. package/dist/resources/extensions/gsd/parsers-legacy.js +16 -4
  149. package/dist/resources/extensions/gsd/paths.js +37 -24
  150. package/dist/resources/extensions/gsd/pre-execution-checks.js +91 -3
  151. package/dist/resources/extensions/gsd/preferences-diagnostics.js +67 -0
  152. package/dist/resources/extensions/gsd/preferences-models.js +14 -48
  153. package/dist/resources/extensions/gsd/preferences.js +161 -29
  154. package/dist/resources/extensions/gsd/projection-flush.js +7 -0
  155. package/dist/resources/extensions/gsd/prompts/complete-slice.md +4 -3
  156. package/dist/resources/extensions/gsd/prompts/discuss.md +6 -7
  157. package/dist/resources/extensions/gsd/prompts/execute-task.md +3 -1
  158. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
  159. package/dist/resources/extensions/gsd/prompts/guided-discuss-project.md +6 -6
  160. package/dist/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
  161. package/dist/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
  162. package/dist/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  163. package/dist/resources/extensions/gsd/prompts/plan-slice.md +4 -3
  164. package/dist/resources/extensions/gsd/prompts/quick-task.md +1 -1
  165. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  166. package/dist/resources/extensions/gsd/prompts/refine-slice.md +3 -2
  167. package/dist/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  168. package/dist/resources/extensions/gsd/prompts/research-milestone.md +3 -3
  169. package/dist/resources/extensions/gsd/prompts/research-slice.md +1 -1
  170. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  171. package/dist/resources/extensions/gsd/prompts/run-uat.md +7 -5
  172. package/dist/resources/extensions/gsd/prompts/system.md +6 -3
  173. package/dist/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  174. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +6 -4
  175. package/dist/resources/extensions/gsd/provider-error-guidance.js +1 -5
  176. package/dist/resources/extensions/gsd/provider-payload-policy.js +83 -0
  177. package/dist/resources/extensions/gsd/provider-switch-observer.js +1 -1
  178. package/dist/resources/extensions/gsd/publication.js +87 -0
  179. package/dist/resources/extensions/gsd/pull-request-process.js +13 -0
  180. package/dist/resources/extensions/gsd/quality-gate-closure.js +109 -0
  181. package/dist/resources/extensions/gsd/question-transport.js +86 -0
  182. package/dist/resources/extensions/gsd/reactive-graph.js +8 -1
  183. package/dist/resources/extensions/gsd/recovery-classification.js +41 -87
  184. package/dist/resources/extensions/gsd/roadmap-slices.js +33 -5
  185. package/dist/resources/extensions/gsd/safety/destructive-confirmation.js +108 -0
  186. package/dist/resources/extensions/gsd/safety/evidence-collector.js +37 -4
  187. package/dist/resources/extensions/gsd/safety/evidence-cross-ref.js +7 -2
  188. package/dist/resources/extensions/gsd/safety/file-change-validator.js +10 -0
  189. package/dist/resources/extensions/gsd/schemas/parsers.js +6 -1
  190. package/dist/resources/extensions/gsd/session-lock.js +1 -1
  191. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +3 -2
  192. package/dist/resources/extensions/gsd/state-reconciliation/drift/artifact-db.js +21 -1
  193. package/dist/resources/extensions/gsd/state-transition-matrix.js +38 -0
  194. package/dist/resources/extensions/gsd/state.js +19 -25
  195. package/dist/resources/extensions/gsd/status-guards.js +56 -8
  196. package/dist/resources/extensions/gsd/stop-notice.js +57 -0
  197. package/dist/resources/extensions/gsd/templates/plan.md +7 -0
  198. package/dist/resources/extensions/gsd/templates/project.md +1 -0
  199. package/dist/resources/extensions/gsd/templates/roadmap.md +1 -1
  200. package/dist/resources/extensions/gsd/templates/uat.md +5 -1
  201. package/dist/resources/extensions/gsd/tool-contract.js +66 -11
  202. package/dist/resources/extensions/gsd/tool-presentation-plan.js +17 -36
  203. package/dist/resources/extensions/gsd/tool-surface-readiness.js +56 -0
  204. package/dist/resources/extensions/gsd/tool-surface-snapshot.js +17 -0
  205. package/dist/resources/extensions/gsd/tools/complete-milestone.js +3 -2
  206. package/dist/resources/extensions/gsd/tools/complete-slice.js +46 -55
  207. package/dist/resources/extensions/gsd/tools/complete-task.js +3 -2
  208. package/dist/resources/extensions/gsd/tools/exec-tool.js +10 -8
  209. package/dist/resources/extensions/gsd/tools/plan-milestone.js +15 -143
  210. package/dist/resources/extensions/gsd/tools/plan-slice.js +14 -8
  211. package/dist/resources/extensions/gsd/tools/plan-task.js +2 -2
  212. package/dist/resources/extensions/gsd/tools/reassess-roadmap.js +41 -2
  213. package/dist/resources/extensions/gsd/tools/reopen-milestone.js +13 -31
  214. package/dist/resources/extensions/gsd/tools/reopen-slice.js +16 -35
  215. package/dist/resources/extensions/gsd/tools/reopen-task.js +2 -2
  216. package/dist/resources/extensions/gsd/tools/replan-slice.js +2 -2
  217. package/dist/resources/extensions/gsd/tools/skip-slice.js +18 -36
  218. package/dist/resources/extensions/gsd/tools/validate-milestone.js +15 -78
  219. package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +236 -22
  220. package/dist/resources/extensions/gsd/uat-policy.js +57 -25
  221. package/dist/resources/extensions/gsd/uat-run.js +9 -14
  222. package/dist/resources/extensions/gsd/undo.js +8 -7
  223. package/dist/resources/extensions/gsd/unit-closeout.js +138 -0
  224. package/dist/resources/extensions/gsd/unit-context-composer.js +114 -21
  225. package/dist/resources/extensions/gsd/unit-context-manifest.js +4 -27
  226. package/dist/resources/extensions/gsd/unit-registry.js +337 -0
  227. package/dist/resources/extensions/gsd/unit-runtime.js +3 -2
  228. package/dist/resources/extensions/gsd/unit-tool-contracts.js +9 -181
  229. package/dist/resources/extensions/gsd/validation-block-guard.js +2 -0
  230. package/dist/resources/extensions/gsd/verdict-parser.js +1 -1
  231. package/dist/resources/extensions/gsd/verification-verdict.js +2 -1
  232. package/dist/resources/extensions/gsd/web-app-uat.js +117 -0
  233. package/dist/resources/extensions/gsd/workflow-event-ledger.js +91 -0
  234. package/dist/resources/extensions/gsd/workflow-event-vocabulary.js +46 -0
  235. package/dist/resources/extensions/gsd/workflow-events.js +6 -18
  236. package/dist/resources/extensions/gsd/workflow-mcp.js +15 -102
  237. package/dist/resources/extensions/gsd/workflow-reconcile.js +25 -59
  238. package/dist/resources/extensions/gsd/workflow-tool-surface.js +46 -0
  239. package/dist/resources/extensions/gsd/workspace-git-guard.js +2 -0
  240. package/dist/resources/extensions/gsd/worktree-git-recovery.js +293 -0
  241. package/dist/resources/extensions/gsd/worktree-lifecycle.js +12 -3
  242. package/dist/resources/extensions/gsd/worktree-manager.js +45 -28
  243. package/dist/resources/extensions/gsd/worktree-placement.js +59 -0
  244. package/dist/resources/extensions/gsd/worktree-reentry.js +12 -8
  245. package/dist/resources/extensions/gsd/worktree-root.js +28 -6
  246. package/dist/resources/extensions/gsd/worktree-safety.js +8 -5
  247. package/dist/resources/extensions/gsd/worktree-session-state.js +12 -11
  248. package/dist/resources/extensions/gsd/worktree-state-projection.js +33 -4
  249. package/dist/resources/extensions/gsd/worktree-telemetry.js +12 -0
  250. package/dist/resources/extensions/search-the-web/native-search.js +5 -3
  251. package/dist/resources/extensions/shared/browser-contract.js +59 -0
  252. package/dist/resources/extensions/shared/gsd-browser-cli.js +116 -6
  253. package/dist/resources/extensions/shared/interview-ui.js +2 -2
  254. package/dist/resources/shared/claude-runtime-floor.js +182 -0
  255. package/dist/resources/shared/gsd-browser-path-sync.js +214 -0
  256. package/dist/resources/shared/package-manager-detection.js +1 -1
  257. package/dist/resources/shared/package.json +3 -0
  258. package/dist/resources/skills/create-skill/references/executable-code.md +1 -1
  259. package/dist/resources/skills/create-skill/workflows/add-reference.md +8 -3
  260. package/dist/resources/skills/create-skill/workflows/add-script.md +4 -2
  261. package/dist/resources/skills/create-skill/workflows/add-template.md +3 -1
  262. package/dist/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  263. package/dist/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  264. package/dist/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  265. package/dist/resources/skills/gsd-browser/SKILL.md +1 -1
  266. package/dist/resources/skills/spike-wrap-up/SKILL.md +9 -9
  267. package/dist/tsconfig.extensions.tsbuildinfo +1 -0
  268. package/dist/update-check.d.ts +2 -0
  269. package/dist/update-check.js +24 -1
  270. package/dist/update-cmd.js +40 -3
  271. package/dist/web/standalone/.next/BUILD_ID +1 -1
  272. package/dist/web/standalone/.next/app-path-routes-manifest.json +5 -5
  273. package/dist/web/standalone/.next/build-manifest.json +3 -3
  274. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  275. package/dist/web/standalone/.next/react-loadable-manifest.json +8 -8
  276. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  277. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  278. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  279. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  280. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  281. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  282. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  283. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  284. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  285. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  286. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  287. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  288. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  289. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  290. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  291. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  292. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  293. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  294. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  295. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  296. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  297. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  298. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  299. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  300. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  301. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  302. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  303. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  304. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  305. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  306. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  307. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  308. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  309. package/dist/web/standalone/.next/server/app/api/mcp-connections/route.js.nft.json +1 -1
  310. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  311. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  312. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  313. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  314. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  315. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  316. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  317. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  318. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  319. package/dist/web/standalone/.next/server/app/api/shutdown/route.js.nft.json +1 -1
  320. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  321. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  322. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  323. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  324. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  325. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  326. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  327. package/dist/web/standalone/.next/server/app/api/update/route.js.nft.json +1 -1
  328. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  329. package/dist/web/standalone/.next/server/app/index.html +1 -1
  330. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  331. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  332. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  333. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  334. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  335. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  336. package/dist/web/standalone/.next/server/app-paths-manifest.json +5 -5
  337. package/dist/web/standalone/.next/server/chunks/5124.js +1 -0
  338. package/dist/web/standalone/.next/server/chunks/5942.js +2 -0
  339. package/dist/web/standalone/.next/server/chunks/8357.js +3 -3
  340. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  341. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  342. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  343. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  344. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  345. package/dist/web/standalone/.next/static/chunks/2659.b7b129ee6a769448.js +1 -0
  346. package/dist/web/standalone/.next/static/chunks/2772.bfa657f49f955239.js +1 -0
  347. package/dist/web/standalone/.next/static/chunks/{3616.4113d484a994e411.js → 3616.3c60753b8ffcbd2e.js} +1 -1
  348. package/dist/web/standalone/.next/static/chunks/4283.e4873b058df143a1.js +2 -0
  349. package/dist/web/standalone/.next/static/chunks/5826.a46ecdd1cfe8dabc.js +1 -0
  350. package/dist/web/standalone/.next/static/chunks/796.e0bdc932325d7e03.js +10 -0
  351. package/dist/web/standalone/.next/static/chunks/8785.2e5a118797fb2dd2.js +1 -0
  352. package/dist/web/standalone/.next/static/chunks/{webpack-dda80a1ef5587410.js → webpack-f0285ce91d4ec9ef.js} +1 -1
  353. package/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
  354. package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
  355. package/dist/web/standalone/node_modules/postcss/lib/container.js +26 -18
  356. package/dist/web/standalone/node_modules/postcss/lib/css-syntax-error.js +47 -14
  357. package/dist/web/standalone/node_modules/postcss/lib/declaration.js +4 -4
  358. package/dist/web/standalone/node_modules/postcss/lib/fromJSON.js +3 -3
  359. package/dist/web/standalone/node_modules/postcss/lib/input.js +54 -29
  360. package/dist/web/standalone/node_modules/postcss/lib/lazy-result.js +47 -37
  361. package/dist/web/standalone/node_modules/postcss/lib/map-generator.js +26 -9
  362. package/dist/web/standalone/node_modules/postcss/lib/no-work-result.js +57 -55
  363. package/dist/web/standalone/node_modules/postcss/lib/node.js +99 -31
  364. package/dist/web/standalone/node_modules/postcss/lib/parse.js +1 -1
  365. package/dist/web/standalone/node_modules/postcss/lib/parser.js +10 -9
  366. package/dist/web/standalone/node_modules/postcss/lib/postcss.js +12 -12
  367. package/dist/web/standalone/node_modules/postcss/lib/previous-map.js +30 -11
  368. package/dist/web/standalone/node_modules/postcss/lib/processor.js +7 -7
  369. package/dist/web/standalone/node_modules/postcss/lib/result.js +5 -5
  370. package/dist/web/standalone/node_modules/postcss/lib/rule.js +6 -6
  371. package/dist/web/standalone/node_modules/postcss/lib/stringifier.js +69 -28
  372. package/dist/web/standalone/node_modules/postcss/lib/tokenize.js +6 -2
  373. package/dist/web/standalone/node_modules/postcss/package.json +48 -48
  374. package/dist/web/standalone/package.json +1 -1
  375. package/dist/web-mode.d.ts +2 -0
  376. package/dist/web-mode.js +20 -8
  377. package/dist/worktree-cli.js +3 -6
  378. package/dist/worktree-status-banner.js +7 -11
  379. package/package.json +17 -11
  380. package/packages/cloud-mcp-gateway/package.json +2 -2
  381. package/packages/contracts/dist/rpc.d.ts +1 -0
  382. package/packages/contracts/dist/rpc.d.ts.map +1 -1
  383. package/packages/contracts/dist/rpc.js.map +1 -1
  384. package/packages/contracts/dist/workflow.d.ts +4 -0
  385. package/packages/contracts/dist/workflow.d.ts.map +1 -1
  386. package/packages/contracts/dist/workflow.js.map +1 -1
  387. package/packages/contracts/package.json +1 -1
  388. package/packages/daemon/package.json +4 -4
  389. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts +2 -0
  390. package/packages/gsd-agent-core/dist/session/agent-session-extensions.d.ts.map +1 -1
  391. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js +14 -0
  392. package/packages/gsd-agent-core/dist/session/agent-session-extensions.js.map +1 -1
  393. package/packages/gsd-agent-core/package.json +5 -5
  394. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +5 -0
  395. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  396. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +8 -0
  397. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  398. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +1 -1
  399. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  400. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  401. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +113 -40
  402. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  403. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.d.ts.map +1 -1
  404. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js +8 -1
  405. package/packages/gsd-agent-modes/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  406. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.d.ts.map +1 -1
  407. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js +11 -1
  408. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-chat-render.js.map +1 -1
  409. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.d.ts.map +1 -1
  410. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js +6 -0
  411. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-extension-widgets.js.map +1 -1
  412. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
  413. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +4 -4
  414. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
  415. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  416. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js +3 -1
  417. package/packages/gsd-agent-modes/dist/modes/rpc/rpc-mode.js.map +1 -1
  418. package/packages/gsd-agent-modes/package.json +7 -7
  419. package/packages/mcp-server/dist/cli.js +9 -1
  420. package/packages/mcp-server/dist/cli.js.map +1 -1
  421. package/packages/mcp-server/dist/moonshot-tool-schema.d.ts +29 -0
  422. package/packages/mcp-server/dist/moonshot-tool-schema.d.ts.map +1 -0
  423. package/packages/mcp-server/dist/moonshot-tool-schema.js +50 -0
  424. package/packages/mcp-server/dist/moonshot-tool-schema.js.map +1 -0
  425. package/packages/mcp-server/dist/server.d.ts +10 -0
  426. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  427. package/packages/mcp-server/dist/server.js +12 -0
  428. package/packages/mcp-server/dist/server.js.map +1 -1
  429. package/packages/mcp-server/dist/workflow-tools.d.ts +49 -0
  430. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  431. package/packages/mcp-server/dist/workflow-tools.js +147 -60
  432. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  433. package/packages/mcp-server/package.json +5 -4
  434. package/packages/native/package.json +1 -1
  435. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts +1 -0
  436. package/packages/pi-agent-core/dist/harness/env/nodejs.d.ts.map +1 -1
  437. package/packages/pi-agent-core/dist/harness/env/nodejs.js +34 -3
  438. package/packages/pi-agent-core/dist/harness/env/nodejs.js.map +1 -1
  439. package/packages/pi-agent-core/dist/index.d.ts +1 -0
  440. package/packages/pi-agent-core/dist/index.d.ts.map +1 -1
  441. package/packages/pi-agent-core/dist/index.js +3 -0
  442. package/packages/pi-agent-core/dist/index.js.map +1 -1
  443. package/packages/pi-agent-core/package.json +1 -1
  444. package/packages/pi-ai/README.md +1 -0
  445. package/packages/pi-ai/dist/index.d.ts +2 -0
  446. package/packages/pi-ai/dist/index.d.ts.map +1 -1
  447. package/packages/pi-ai/dist/index.js +2 -0
  448. package/packages/pi-ai/dist/index.js.map +1 -1
  449. package/packages/pi-ai/dist/models.generated.d.ts +183 -110
  450. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  451. package/packages/pi-ai/dist/models.generated.js +205 -158
  452. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  453. package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
  454. package/packages/pi-ai/dist/providers/anthropic.js +12 -7
  455. package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
  456. package/packages/pi-ai/dist/providers/google-shared.d.ts +5 -0
  457. package/packages/pi-ai/dist/providers/google-shared.d.ts.map +1 -1
  458. package/packages/pi-ai/dist/providers/google-shared.js +12 -3
  459. package/packages/pi-ai/dist/providers/google-shared.js.map +1 -1
  460. package/packages/pi-ai/dist/providers/openai-completions.d.ts.map +1 -1
  461. package/packages/pi-ai/dist/providers/openai-completions.js +7 -3
  462. package/packages/pi-ai/dist/providers/openai-completions.js.map +1 -1
  463. package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts +9 -0
  464. package/packages/pi-ai/dist/utils/moonshot-tool-schema.d.ts.map +1 -0
  465. package/packages/pi-ai/dist/utils/moonshot-tool-schema.js +34 -0
  466. package/packages/pi-ai/dist/utils/moonshot-tool-schema.js.map +1 -0
  467. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  468. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +6 -2
  469. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  470. package/packages/pi-ai/package.json +3 -2
  471. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +2 -2
  472. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  473. package/packages/pi-coding-agent/dist/core/auth-storage.js +29 -15
  474. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  475. package/packages/pi-coding-agent/dist/core/capability-patches.d.ts.map +1 -1
  476. package/packages/pi-coding-agent/dist/core/capability-patches.js +3 -1
  477. package/packages/pi-coding-agent/dist/core/capability-patches.js.map +1 -1
  478. package/packages/pi-coding-agent/dist/core/provider-readiness.d.ts.map +1 -1
  479. package/packages/pi-coding-agent/dist/core/provider-readiness.js +13 -6
  480. package/packages/pi-coding-agent/dist/core/provider-readiness.js.map +1 -1
  481. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts +11 -0
  482. package/packages/pi-coding-agent/dist/core/tools/bash.d.ts.map +1 -1
  483. package/packages/pi-coding-agent/dist/core/tools/bash.js +53 -11
  484. package/packages/pi-coding-agent/dist/core/tools/bash.js.map +1 -1
  485. package/packages/pi-coding-agent/dist/index.d.ts +1 -1
  486. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  487. package/packages/pi-coding-agent/dist/index.js +1 -1
  488. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  489. package/packages/pi-coding-agent/dist/utils/shell.d.ts +28 -2
  490. package/packages/pi-coding-agent/dist/utils/shell.d.ts.map +1 -1
  491. package/packages/pi-coding-agent/dist/utils/shell.js +56 -10
  492. package/packages/pi-coding-agent/dist/utils/shell.js.map +1 -1
  493. package/packages/pi-coding-agent/package.json +7 -7
  494. package/packages/pi-tui/dist/components/input.js +1 -1
  495. package/packages/pi-tui/dist/components/input.js.map +1 -1
  496. package/packages/pi-tui/dist/keys.d.ts.map +1 -1
  497. package/packages/pi-tui/dist/keys.js +39 -30
  498. package/packages/pi-tui/dist/keys.js.map +1 -1
  499. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  500. package/packages/pi-tui/dist/stdin-buffer.js +22 -0
  501. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  502. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  503. package/packages/pi-tui/dist/tui.js +9 -0
  504. package/packages/pi-tui/dist/tui.js.map +1 -1
  505. package/packages/pi-tui/package.json +2 -2
  506. package/packages/rpc-client/package.json +2 -2
  507. package/pkg/package.json +1 -1
  508. package/scripts/install/deps.js +10 -0
  509. package/scripts/link-workspace-packages.cjs +7 -40
  510. package/src/resources/GSD-WORKFLOW.md +5 -4
  511. package/src/resources/extensions/ask-user-questions.ts +87 -24
  512. package/src/resources/extensions/async-jobs/async-bash-cancel.test.ts +360 -0
  513. package/src/resources/extensions/async-jobs/async-bash-tool.ts +33 -56
  514. package/src/resources/extensions/async-jobs/await-tool.test.ts +139 -0
  515. package/src/resources/extensions/async-jobs/await-tool.ts +82 -12
  516. package/src/resources/extensions/async-jobs/index.ts +79 -0
  517. package/src/resources/extensions/async-jobs/job-manager.ts +21 -1
  518. package/src/resources/extensions/bg-shell/bg-shell-command.ts +6 -6
  519. package/src/resources/extensions/bg-shell/bg-shell-tool.ts +10 -6
  520. package/src/resources/extensions/bg-shell/overlay.ts +9 -5
  521. package/src/resources/extensions/bg-shell/process-manager.ts +50 -25
  522. package/src/resources/extensions/bg-shell/readiness-detector.ts +12 -0
  523. package/src/resources/extensions/bg-shell/tests/lifecycle-and-utilities.test.ts +48 -1
  524. package/src/resources/extensions/bg-shell/utilities.ts +5 -2
  525. package/src/resources/extensions/browser-tools/engine/managed-gsd-browser.ts +265 -98
  526. package/src/resources/extensions/browser-tools/engine/selection.ts +90 -4
  527. package/src/resources/extensions/browser-tools/index.ts +71 -13
  528. package/src/resources/extensions/browser-tools/tests/browser-engine-selection.test.mjs +83 -13
  529. package/src/resources/extensions/browser-tools/tests/gsd-browser-launch-config.test.mjs +40 -1
  530. package/src/resources/extensions/browser-tools/tests/managed-gsd-browser-tools.test.mjs +136 -0
  531. package/src/resources/extensions/claude-code-cli/models.ts +9 -0
  532. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +166 -293
  533. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +270 -2
  534. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +287 -0
  535. package/src/resources/extensions/github-sync/templates.ts +3 -3
  536. package/src/resources/extensions/github-sync/tests/templates.test.ts +2 -2
  537. package/src/resources/extensions/gsd/artifact-projection.ts +31 -0
  538. package/src/resources/extensions/gsd/auto/contracts.ts +40 -121
  539. package/src/resources/extensions/gsd/auto/custom-verify-retry-store.ts +21 -3
  540. package/src/resources/extensions/gsd/auto/detect-stuck.ts +32 -9
  541. package/src/resources/extensions/gsd/auto/dispatch-history.ts +152 -0
  542. package/src/resources/extensions/gsd/auto/dispatch-key.ts +39 -0
  543. package/src/resources/extensions/gsd/auto/loop-deps.ts +3 -1
  544. package/src/resources/extensions/gsd/auto/loop.ts +86 -61
  545. package/src/resources/extensions/gsd/auto/orchestrator.ts +1023 -98
  546. package/src/resources/extensions/gsd/auto/phases.ts +108 -28
  547. package/src/resources/extensions/gsd/auto/run-unit.ts +2 -1
  548. package/src/resources/extensions/gsd/auto/session.ts +7 -0
  549. package/src/resources/extensions/gsd/auto-dashboard.ts +18 -4
  550. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +18 -48
  551. package/src/resources/extensions/gsd/auto-dispatch.ts +68 -68
  552. package/src/resources/extensions/gsd/auto-model-selection.ts +49 -12
  553. package/src/resources/extensions/gsd/auto-post-unit.ts +56 -16
  554. package/src/resources/extensions/gsd/auto-prompts.ts +338 -44
  555. package/src/resources/extensions/gsd/auto-recovery.ts +50 -50
  556. package/src/resources/extensions/gsd/auto-runtime-state.ts +30 -0
  557. package/src/resources/extensions/gsd/auto-start.ts +41 -49
  558. package/src/resources/extensions/gsd/auto-timers.ts +16 -2
  559. package/src/resources/extensions/gsd/auto-tool-tracking.ts +59 -0
  560. package/src/resources/extensions/gsd/auto-unit-closeout.ts +83 -28
  561. package/src/resources/extensions/gsd/auto-unit-tool-scope.ts +43 -38
  562. package/src/resources/extensions/gsd/auto-verification.ts +33 -36
  563. package/src/resources/extensions/gsd/auto-worktree-repair.ts +13 -2
  564. package/src/resources/extensions/gsd/auto-worktree.ts +83 -391
  565. package/src/resources/extensions/gsd/auto.ts +151 -524
  566. package/src/resources/extensions/gsd/blocked-models.ts +49 -0
  567. package/src/resources/extensions/gsd/bootstrap/agent-end-recovery.ts +37 -10
  568. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +29 -37
  569. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +43 -49
  570. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +2 -2
  571. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
  572. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +24 -0
  573. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +379 -177
  574. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +452 -58
  575. package/src/resources/extensions/gsd/branch-patterns.ts +3 -0
  576. package/src/resources/extensions/gsd/browser-daemon-auto-prep.ts +108 -0
  577. package/src/resources/extensions/gsd/browser-evidence.ts +18 -2
  578. package/src/resources/extensions/gsd/captures.ts +5 -16
  579. package/src/resources/extensions/gsd/closeout-consistency-gate.ts +27 -5
  580. package/src/resources/extensions/gsd/closeout-recovery.ts +2 -1
  581. package/src/resources/extensions/gsd/closeout-wizard.ts +102 -0
  582. package/src/resources/extensions/gsd/codebase-generator.ts +9 -5
  583. package/src/resources/extensions/gsd/commands/catalog.ts +6 -68
  584. package/src/resources/extensions/gsd/commands/context.ts +16 -2
  585. package/src/resources/extensions/gsd/commands/handlers/auto.ts +3 -0
  586. package/src/resources/extensions/gsd/commands-handlers.ts +64 -3
  587. package/src/resources/extensions/gsd/commands-inspect.ts +7 -8
  588. package/src/resources/extensions/gsd/commands-maintenance.ts +74 -40
  589. package/src/resources/extensions/gsd/commands-ship.ts +2 -2
  590. package/src/resources/extensions/gsd/commands-verdict.ts +19 -2
  591. package/src/resources/extensions/gsd/consent-question.ts +431 -0
  592. package/src/resources/extensions/gsd/consent-verdict.ts +86 -0
  593. package/src/resources/extensions/gsd/constants.ts +0 -3
  594. package/src/resources/extensions/gsd/crash-recovery.ts +13 -11
  595. package/src/resources/extensions/gsd/db/engine.ts +809 -0
  596. package/src/resources/extensions/gsd/db/queries.ts +490 -0
  597. package/src/resources/extensions/gsd/db/sql-constants.ts +12 -0
  598. package/src/resources/extensions/gsd/db/writers/cascades.ts +237 -0
  599. package/src/resources/extensions/gsd/db/writers/import-restore.ts +310 -0
  600. package/src/resources/extensions/gsd/db/writers/memory.ts +220 -0
  601. package/src/resources/extensions/gsd/db/writers/reconcile.ts +500 -0
  602. package/src/resources/extensions/gsd/db/writers/status.ts +88 -0
  603. package/src/resources/extensions/gsd/db-workspace.ts +170 -0
  604. package/src/resources/extensions/gsd/debug-logger.ts +11 -0
  605. package/src/resources/extensions/gsd/delegation-policy.ts +3 -11
  606. package/src/resources/extensions/gsd/discussion-handoff.ts +276 -0
  607. package/src/resources/extensions/gsd/dispatch-guard.ts +8 -31
  608. package/src/resources/extensions/gsd/docs/preferences-reference.md +9 -0
  609. package/src/resources/extensions/gsd/doctor-engine-checks.ts +5 -4
  610. package/src/resources/extensions/gsd/doctor-environment.ts +5 -13
  611. package/src/resources/extensions/gsd/doctor-format.ts +12 -7
  612. package/src/resources/extensions/gsd/doctor-git-checks.ts +5 -22
  613. package/src/resources/extensions/gsd/doctor-proactive.ts +8 -2
  614. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +22 -17
  615. package/src/resources/extensions/gsd/doctor.ts +15 -5
  616. package/src/resources/extensions/gsd/engine-hook-contract.ts +79 -0
  617. package/src/resources/extensions/gsd/error-classifier.ts +12 -1
  618. package/src/resources/extensions/gsd/exec-sandbox.ts +49 -9
  619. package/src/resources/extensions/gsd/files.ts +33 -12
  620. package/src/resources/extensions/gsd/git-conflict-state.ts +17 -1
  621. package/src/resources/extensions/gsd/git-service.ts +1 -0
  622. package/src/resources/extensions/gsd/gitignore.ts +3 -0
  623. package/src/resources/extensions/gsd/gsd-command-home.ts +13 -3
  624. package/src/resources/extensions/gsd/gsd-db.ts +188 -2375
  625. package/src/resources/extensions/gsd/guidance.ts +217 -0
  626. package/src/resources/extensions/gsd/guided-flow.ts +118 -589
  627. package/src/resources/extensions/gsd/guided-unit-completion.ts +275 -0
  628. package/src/resources/extensions/gsd/markdown-renderer.ts +51 -20
  629. package/src/resources/extensions/gsd/mcp-filter.ts +11 -24
  630. package/src/resources/extensions/gsd/mcp-tool-name.ts +30 -0
  631. package/src/resources/extensions/gsd/md-importer.ts +3 -3
  632. package/src/resources/extensions/gsd/memory-consolidation-scanner.ts +1 -1
  633. package/src/resources/extensions/gsd/migrate/safety.ts +20 -9
  634. package/src/resources/extensions/gsd/migration-auto-check.ts +30 -5
  635. package/src/resources/extensions/gsd/milestone-closeout-proof.ts +131 -0
  636. package/src/resources/extensions/gsd/milestone-closeout.ts +121 -28
  637. package/src/resources/extensions/gsd/milestone-merge-transaction.ts +47 -0
  638. package/src/resources/extensions/gsd/milestone-planning-persistence.ts +224 -0
  639. package/src/resources/extensions/gsd/milestone-readiness.ts +125 -0
  640. package/src/resources/extensions/gsd/milestone-reopen-events.ts +3 -6
  641. package/src/resources/extensions/gsd/milestone-settlement.ts +81 -0
  642. package/src/resources/extensions/gsd/milestone-validation-evidence.ts +95 -0
  643. package/src/resources/extensions/gsd/milestone-validation-verdict.ts +80 -0
  644. package/src/resources/extensions/gsd/model-cost-table.ts +1 -0
  645. package/src/resources/extensions/gsd/model-router.ts +3 -0
  646. package/src/resources/extensions/gsd/native-git-bridge.ts +48 -0
  647. package/src/resources/extensions/gsd/notification-store.ts +26 -3
  648. package/src/resources/extensions/gsd/parallel-eligibility.ts +4 -5
  649. package/src/resources/extensions/gsd/parallel-merge.ts +12 -9
  650. package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +10 -7
  651. package/src/resources/extensions/gsd/parallel-orchestrator.ts +6 -2
  652. package/src/resources/extensions/gsd/parsers-legacy.ts +16 -4
  653. package/src/resources/extensions/gsd/paths.ts +42 -22
  654. package/src/resources/extensions/gsd/pre-execution-checks.ts +109 -3
  655. package/src/resources/extensions/gsd/preferences-diagnostics.ts +98 -0
  656. package/src/resources/extensions/gsd/preferences-models.ts +12 -47
  657. package/src/resources/extensions/gsd/preferences-types.ts +16 -0
  658. package/src/resources/extensions/gsd/preferences.ts +191 -28
  659. package/src/resources/extensions/gsd/projection-flush.ts +20 -0
  660. package/src/resources/extensions/gsd/prompts/complete-slice.md +4 -3
  661. package/src/resources/extensions/gsd/prompts/discuss.md +6 -7
  662. package/src/resources/extensions/gsd/prompts/execute-task.md +3 -1
  663. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +5 -7
  664. package/src/resources/extensions/gsd/prompts/guided-discuss-project.md +6 -6
  665. package/src/resources/extensions/gsd/prompts/guided-discuss-requirements.md +1 -2
  666. package/src/resources/extensions/gsd/prompts/guided-discuss-slice.md +5 -6
  667. package/src/resources/extensions/gsd/prompts/plan-milestone.md +3 -1
  668. package/src/resources/extensions/gsd/prompts/plan-slice.md +4 -3
  669. package/src/resources/extensions/gsd/prompts/quick-task.md +1 -1
  670. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +1 -1
  671. package/src/resources/extensions/gsd/prompts/refine-slice.md +3 -2
  672. package/src/resources/extensions/gsd/prompts/replan-slice.md +2 -2
  673. package/src/resources/extensions/gsd/prompts/research-milestone.md +3 -3
  674. package/src/resources/extensions/gsd/prompts/research-slice.md +1 -1
  675. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +1 -1
  676. package/src/resources/extensions/gsd/prompts/run-uat.md +7 -5
  677. package/src/resources/extensions/gsd/prompts/system.md +6 -3
  678. package/src/resources/extensions/gsd/prompts/triage-captures.md +1 -1
  679. package/src/resources/extensions/gsd/prompts/validate-milestone.md +6 -4
  680. package/src/resources/extensions/gsd/provider-error-guidance.ts +4 -9
  681. package/src/resources/extensions/gsd/provider-payload-policy.ts +140 -0
  682. package/src/resources/extensions/gsd/provider-switch-observer.ts +1 -1
  683. package/src/resources/extensions/gsd/publication.ts +122 -0
  684. package/src/resources/extensions/gsd/pull-request-process.ts +41 -0
  685. package/src/resources/extensions/gsd/quality-gate-closure.ts +140 -0
  686. package/src/resources/extensions/gsd/question-transport.ts +138 -0
  687. package/src/resources/extensions/gsd/reactive-graph.ts +11 -1
  688. package/src/resources/extensions/gsd/recovery-classification.ts +47 -88
  689. package/src/resources/extensions/gsd/roadmap-slices.ts +36 -5
  690. package/src/resources/extensions/gsd/safety/destructive-confirmation.ts +134 -0
  691. package/src/resources/extensions/gsd/safety/evidence-collector.ts +36 -4
  692. package/src/resources/extensions/gsd/safety/evidence-cross-ref.ts +7 -2
  693. package/src/resources/extensions/gsd/safety/file-change-validator.ts +14 -0
  694. package/src/resources/extensions/gsd/schemas/parsers.ts +6 -1
  695. package/src/resources/extensions/gsd/session-lock.ts +1 -1
  696. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +6 -2
  697. package/src/resources/extensions/gsd/state-reconciliation/drift/artifact-db.ts +31 -10
  698. package/src/resources/extensions/gsd/state-transition-matrix.ts +42 -0
  699. package/src/resources/extensions/gsd/state.ts +24 -26
  700. package/src/resources/extensions/gsd/status-guards.ts +59 -8
  701. package/src/resources/extensions/gsd/stop-notice.ts +75 -0
  702. package/src/resources/extensions/gsd/templates/plan.md +7 -0
  703. package/src/resources/extensions/gsd/templates/project.md +1 -0
  704. package/src/resources/extensions/gsd/templates/roadmap.md +1 -1
  705. package/src/resources/extensions/gsd/templates/uat.md +5 -1
  706. package/src/resources/extensions/gsd/tests/artifact-db-drift-memo.test.ts +66 -0
  707. package/src/resources/extensions/gsd/tests/ask-user-questions-render.test.ts +92 -0
  708. package/src/resources/extensions/gsd/tests/auto-dashboard.test.ts +29 -1
  709. package/src/resources/extensions/gsd/tests/auto-dispatch-baseline-harness.test.ts +53 -0
  710. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +444 -5
  711. package/src/resources/extensions/gsd/tests/auto-milestone-target.test.ts +23 -0
  712. package/src/resources/extensions/gsd/tests/auto-model-selection-tool-poisoning.test.ts +18 -0
  713. package/src/resources/extensions/gsd/tests/auto-model-selection.test.ts +91 -0
  714. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +894 -858
  715. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +41 -11
  716. package/src/resources/extensions/gsd/tests/auto-post-unit-evidence-crossref-4909.test.ts +46 -0
  717. package/src/resources/extensions/gsd/tests/auto-remote-session-lock-cleanup.test.ts +65 -3
  718. package/src/resources/extensions/gsd/tests/auto-runtime-state.test.ts +34 -0
  719. package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +2 -2
  720. package/src/resources/extensions/gsd/tests/auto-worktree-repair.test.ts +4 -2
  721. package/src/resources/extensions/gsd/tests/blocked-models.test.ts +19 -0
  722. package/src/resources/extensions/gsd/tests/browser-automation-contract-fixture.ts +39 -0
  723. package/src/resources/extensions/gsd/tests/browser-contract.test.ts +44 -0
  724. package/src/resources/extensions/gsd/tests/browser-daemon-auto-prep.test.ts +144 -0
  725. package/src/resources/extensions/gsd/tests/canonical-milestone-root.test.ts +20 -0
  726. package/src/resources/extensions/gsd/tests/checkout-branch-stash-guard.test.ts +66 -1
  727. package/src/resources/extensions/gsd/tests/clear-stale-autostart.test.ts +44 -0
  728. package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
  729. package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +11 -0
  730. package/src/resources/extensions/gsd/tests/commands-verdict.test.ts +46 -8
  731. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +42 -0
  732. package/src/resources/extensions/gsd/tests/consent-question.test.ts +351 -0
  733. package/src/resources/extensions/gsd/tests/custom-verify-retry-store.test.ts +67 -0
  734. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +15 -0
  735. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +10 -10
  736. package/src/resources/extensions/gsd/tests/destructive-confirmation.test.ts +303 -0
  737. package/src/resources/extensions/gsd/tests/dispatch-complete-milestone-guard.test.ts +34 -3
  738. package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +273 -0
  739. package/src/resources/extensions/gsd/tests/dispatch-run-uat-browser-tools.test.ts +89 -0
  740. package/src/resources/extensions/gsd/tests/doctor-git-checks-terminal.test.ts +73 -0
  741. package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +18 -0
  742. package/src/resources/extensions/gsd/tests/dynamic-bash-no-cap.test.ts +132 -0
  743. package/src/resources/extensions/gsd/tests/engine-hook-contract.test.ts +148 -0
  744. package/src/resources/extensions/gsd/tests/evidence-xref-gsd-exec.test.ts +157 -0
  745. package/src/resources/extensions/gsd/tests/exec-graceful-kill.test.ts +193 -0
  746. package/src/resources/extensions/gsd/tests/exec-tool.test.ts +29 -1
  747. package/src/resources/extensions/gsd/tests/execute-summary-save-empty-project.test.ts +64 -1
  748. package/src/resources/extensions/gsd/tests/execute-task-rendering.test.ts +1 -0
  749. package/src/resources/extensions/gsd/tests/extension-bootstrap-isolation.test.ts +35 -1
  750. package/src/resources/extensions/gsd/tests/file-change-validator.test.ts +33 -1
  751. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-no-blockers.md +1 -5
  752. package/src/resources/extensions/gsd/tests/fixtures/pr-body/swarm-lane-with-blockers.md +1 -5
  753. package/src/resources/extensions/gsd/tests/gate-state-canonicalization.test.ts +48 -1
  754. package/src/resources/extensions/gsd/tests/gsd-command-home.test.ts +120 -0
  755. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +27 -0
  756. package/src/resources/extensions/gsd/tests/guidance.test.ts +148 -0
  757. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +2 -6
  758. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +58 -15
  759. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +74 -59
  760. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
  761. package/src/resources/extensions/gsd/tests/integration/gsd-integration-fixture.ts +80 -0
  762. package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +157 -0
  763. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +199 -0
  764. package/src/resources/extensions/gsd/tests/markdown-renderer-parse-cache.test.ts +75 -0
  765. package/src/resources/extensions/gsd/tests/mcp-project-config.test.ts +3 -1
  766. package/src/resources/extensions/gsd/tests/mcp-tool-name.test.ts +34 -0
  767. package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +143 -1
  768. package/src/resources/extensions/gsd/tests/milestone-closeout-proof.test.ts +99 -0
  769. package/src/resources/extensions/gsd/tests/milestone-closeout.test.ts +120 -4
  770. package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +46 -0
  771. package/src/resources/extensions/gsd/tests/milestone-readiness.test.ts +65 -0
  772. package/src/resources/extensions/gsd/tests/milestone-validation-evidence.test.ts +41 -0
  773. package/src/resources/extensions/gsd/tests/milestone-validation-verdict.test.ts +55 -0
  774. package/src/resources/extensions/gsd/tests/model-unittype-mapping.test.ts +32 -1
  775. package/src/resources/extensions/gsd/tests/native-merge-regular.test.ts +139 -0
  776. package/src/resources/extensions/gsd/tests/notification-store.test.ts +32 -0
  777. package/src/resources/extensions/gsd/tests/oauth-api-model-routing.test.ts +167 -0
  778. package/src/resources/extensions/gsd/tests/orchestrator-legacy-parity.test.ts +127 -0
  779. package/src/resources/extensions/gsd/tests/parallel-research-dispatch.test.ts +18 -0
  780. package/src/resources/extensions/gsd/tests/parse-project-milestone-bridge.test.ts +77 -0
  781. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +138 -0
  782. package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +242 -0
  783. package/src/resources/extensions/gsd/tests/plan-milestone.test.ts +45 -0
  784. package/src/resources/extensions/gsd/tests/plan-slice-prompt.test.ts +6 -2
  785. package/src/resources/extensions/gsd/tests/planning-crossval.test.ts +45 -0
  786. package/src/resources/extensions/gsd/tests/post-exec-retry-bypass.test.ts +63 -2
  787. package/src/resources/extensions/gsd/tests/pre-execution-checks.test.ts +193 -1
  788. package/src/resources/extensions/gsd/tests/preferences-diagnostics.test.ts +67 -0
  789. package/src/resources/extensions/gsd/tests/preferences.test.ts +183 -0
  790. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +75 -2
  791. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +124 -6
  792. package/src/resources/extensions/gsd/tests/provider-error-guidance.test.ts +3 -3
  793. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +9 -0
  794. package/src/resources/extensions/gsd/tests/provider-payload-policy.test.ts +165 -0
  795. package/src/resources/extensions/gsd/tests/publication.test.ts +120 -0
  796. package/src/resources/extensions/gsd/tests/pull-request-process.test.ts +47 -0
  797. package/src/resources/extensions/gsd/tests/recovery-classification-illegal-transition.test.ts +30 -0
  798. package/src/resources/extensions/gsd/tests/register-hooks-depth-verification.test.ts +342 -1
  799. package/src/resources/extensions/gsd/tests/research-milestone-composer.test.ts +65 -0
  800. package/src/resources/extensions/gsd/tests/roadmap-parse-regression.test.ts +40 -0
  801. package/src/resources/extensions/gsd/tests/roadmap-slices.test.ts +68 -0
  802. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +44 -1
  803. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +38 -0
  804. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +80 -0
  805. package/src/resources/extensions/gsd/tests/session-switch-clears-pending-autostart.test.ts +108 -0
  806. package/src/resources/extensions/gsd/tests/single-writer-invariant.test.ts +144 -7
  807. package/src/resources/extensions/gsd/tests/stale-queued-milestone.test.ts +27 -0
  808. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +21 -6
  809. package/src/resources/extensions/gsd/tests/state-transition-matrix.test.ts +36 -0
  810. package/src/resources/extensions/gsd/tests/status-guards.test.ts +38 -0
  811. package/src/resources/extensions/gsd/tests/stop-notice.test.ts +70 -0
  812. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +114 -0
  813. package/src/resources/extensions/gsd/tests/tool-availability-audit.test.ts +35 -0
  814. package/src/resources/extensions/gsd/tests/tool-invocation-error-loop-break.test.ts +8 -0
  815. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +35 -42
  816. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +155 -0
  817. package/src/resources/extensions/gsd/tests/tool-unavailable-retry.test.ts +33 -0
  818. package/src/resources/extensions/gsd/tests/transport-gate-double-complete.test.ts +139 -0
  819. package/src/resources/extensions/gsd/tests/uat-policy.test.ts +112 -6
  820. package/src/resources/extensions/gsd/tests/unit-closeout.test.ts +209 -0
  821. package/src/resources/extensions/gsd/tests/unit-context-composer.test.ts +114 -2
  822. package/src/resources/extensions/gsd/tests/unit-registry.test.ts +163 -0
  823. package/src/resources/extensions/gsd/tests/uok-audit-unified.test.ts +8 -0
  824. package/src/resources/extensions/gsd/tests/validate-milestone-stuck-guard.test.ts +39 -0
  825. package/src/resources/extensions/gsd/tests/verification-verdict.test.ts +2 -0
  826. package/src/resources/extensions/gsd/tests/web-app-uat.test.ts +193 -0
  827. package/src/resources/extensions/gsd/tests/workflow-events.test.ts +19 -0
  828. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +128 -11
  829. package/src/resources/extensions/gsd/tests/workflow-reconcile.test.ts +20 -0
  830. package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +275 -40
  831. package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +15 -0
  832. package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +41 -4
  833. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +43 -1
  834. package/src/resources/extensions/gsd/tests/worktree-placement.test.ts +113 -0
  835. package/src/resources/extensions/gsd/tests/worktree-projection-writers.test.ts +1 -1
  836. package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +1 -1
  837. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +27 -1
  838. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +12 -6
  839. package/src/resources/extensions/gsd/tests/worktree-teardown-safety.test.ts +2 -2
  840. package/src/resources/extensions/gsd/tests/worktree-telemetry.test.ts +22 -0
  841. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +15 -3
  842. package/src/resources/extensions/gsd/tests/write-gate-seam.test.ts +358 -0
  843. package/src/resources/extensions/gsd/tests/write-gate.test.ts +188 -1
  844. package/src/resources/extensions/gsd/tool-contract.ts +124 -11
  845. package/src/resources/extensions/gsd/tool-presentation-plan.ts +18 -35
  846. package/src/resources/extensions/gsd/tool-surface-readiness.ts +76 -0
  847. package/src/resources/extensions/gsd/tool-surface-snapshot.ts +47 -0
  848. package/src/resources/extensions/gsd/tools/complete-milestone.ts +3 -2
  849. package/src/resources/extensions/gsd/tools/complete-slice.ts +45 -70
  850. package/src/resources/extensions/gsd/tools/complete-task.ts +3 -2
  851. package/src/resources/extensions/gsd/tools/exec-tool.ts +9 -8
  852. package/src/resources/extensions/gsd/tools/plan-milestone.ts +19 -160
  853. package/src/resources/extensions/gsd/tools/plan-slice.ts +14 -8
  854. package/src/resources/extensions/gsd/tools/plan-task.ts +2 -2
  855. package/src/resources/extensions/gsd/tools/reassess-roadmap.ts +45 -2
  856. package/src/resources/extensions/gsd/tools/reopen-milestone.ts +13 -40
  857. package/src/resources/extensions/gsd/tools/reopen-slice.ts +16 -44
  858. package/src/resources/extensions/gsd/tools/reopen-task.ts +2 -2
  859. package/src/resources/extensions/gsd/tools/replan-slice.ts +2 -2
  860. package/src/resources/extensions/gsd/tools/skip-slice.ts +18 -44
  861. package/src/resources/extensions/gsd/tools/validate-milestone.ts +25 -84
  862. package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +264 -23
  863. package/src/resources/extensions/gsd/uat-policy.ts +80 -25
  864. package/src/resources/extensions/gsd/uat-run.ts +10 -14
  865. package/src/resources/extensions/gsd/undo.ts +9 -8
  866. package/src/resources/extensions/gsd/unit-closeout.ts +201 -0
  867. package/src/resources/extensions/gsd/unit-context-composer.ts +196 -21
  868. package/src/resources/extensions/gsd/unit-context-manifest.ts +4 -28
  869. package/src/resources/extensions/gsd/unit-registry.ts +412 -0
  870. package/src/resources/extensions/gsd/unit-runtime.ts +3 -2
  871. package/src/resources/extensions/gsd/unit-tool-contracts.ts +27 -191
  872. package/src/resources/extensions/gsd/validation-block-guard.ts +2 -0
  873. package/src/resources/extensions/gsd/verdict-parser.ts +1 -1
  874. package/src/resources/extensions/gsd/verification-verdict.ts +4 -2
  875. package/src/resources/extensions/gsd/web-app-uat.ts +144 -0
  876. package/src/resources/extensions/gsd/workflow-event-ledger.ts +131 -0
  877. package/src/resources/extensions/gsd/workflow-event-vocabulary.ts +59 -0
  878. package/src/resources/extensions/gsd/workflow-events.ts +12 -20
  879. package/src/resources/extensions/gsd/workflow-mcp.ts +22 -110
  880. package/src/resources/extensions/gsd/workflow-reconcile.ts +32 -65
  881. package/src/resources/extensions/gsd/workflow-tool-surface.ts +76 -0
  882. package/src/resources/extensions/gsd/workspace-git-guard.ts +1 -0
  883. package/src/resources/extensions/gsd/worktree-git-recovery.ts +314 -0
  884. package/src/resources/extensions/gsd/worktree-lifecycle.ts +20 -25
  885. package/src/resources/extensions/gsd/worktree-manager.ts +47 -28
  886. package/src/resources/extensions/gsd/worktree-placement.ts +63 -0
  887. package/src/resources/extensions/gsd/worktree-reentry.ts +10 -7
  888. package/src/resources/extensions/gsd/worktree-root.ts +29 -6
  889. package/src/resources/extensions/gsd/worktree-safety.ts +8 -5
  890. package/src/resources/extensions/gsd/worktree-session-state.ts +11 -11
  891. package/src/resources/extensions/gsd/worktree-state-projection.ts +55 -7
  892. package/src/resources/extensions/gsd/worktree-telemetry.ts +16 -0
  893. package/src/resources/extensions/search-the-web/native-search.ts +5 -3
  894. package/src/resources/extensions/shared/browser-contract.ts +66 -0
  895. package/src/resources/extensions/shared/gsd-browser-cli.ts +141 -6
  896. package/src/resources/extensions/shared/interview-ui.ts +15 -2
  897. package/src/resources/shared/claude-runtime-floor.ts +248 -0
  898. package/src/resources/shared/gsd-browser-path-sync.ts +273 -0
  899. package/src/resources/shared/package-manager-detection.ts +1 -1
  900. package/src/resources/shared/package.json +3 -0
  901. package/src/resources/skills/create-skill/references/executable-code.md +1 -1
  902. package/src/resources/skills/create-skill/workflows/add-reference.md +8 -3
  903. package/src/resources/skills/create-skill/workflows/add-script.md +4 -2
  904. package/src/resources/skills/create-skill/workflows/add-template.md +3 -1
  905. package/src/resources/skills/create-skill/workflows/add-workflow.md +8 -3
  906. package/src/resources/skills/create-skill/workflows/upgrade-to-router.md +10 -5
  907. package/src/resources/skills/create-skill/workflows/verify-skill.md +9 -4
  908. package/src/resources/skills/gsd-browser/SKILL.md +1 -1
  909. package/src/resources/skills/spike-wrap-up/SKILL.md +9 -9
  910. package/dist/resources/extensions/gsd/user-input-boundary.js +0 -157
  911. package/dist/web/standalone/.next/server/chunks/678.js +0 -2
  912. package/dist/web/standalone/.next/static/chunks/2659.feb6499ca863ebfc.js +0 -1
  913. package/dist/web/standalone/.next/static/chunks/2772.151789db0edea835.js +0 -1
  914. package/dist/web/standalone/.next/static/chunks/4283.10a065467b5340d8.js +0 -2
  915. package/dist/web/standalone/.next/static/chunks/5826.960dc4634cc9b0d3.js +0 -1
  916. package/dist/web/standalone/.next/static/chunks/796.46f811c0fac23aab.js +0 -10
  917. package/dist/web/standalone/.next/static/chunks/8785.d32f7a61f55c1600.js +0 -1
  918. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts +0 -21
  919. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.d.ts.map +0 -1
  920. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js +0 -213
  921. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/gsd-widget-prototype.js.map +0 -1
  922. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts +0 -28
  923. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.d.ts.map +0 -1
  924. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js +0 -249
  925. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-density-prototype.js.map +0 -1
  926. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts +0 -19
  927. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.d.ts.map +0 -1
  928. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js +0 -797
  929. package/packages/gsd-agent-modes/dist/modes/interactive/components/__prototype__/transcript-design-prototype.js.map +0 -1
  930. package/scripts/ensure-workspace-builds.cjs +0 -129
  931. package/src/resources/extensions/gsd/tests/user-input-boundary.test.ts +0 -26
  932. package/src/resources/extensions/gsd/user-input-boundary.ts +0 -166
  933. /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → T-LTxEw5wir5Lm5T3qEVd}/_buildManifest.js +0 -0
  934. /package/dist/web/standalone/.next/static/{tJOKQbQRO-9MiFDO8DIDS → T-LTxEw5wir5Lm5T3qEVd}/_ssgManifest.js +0 -0
@@ -1,28 +1,334 @@
1
1
  // Project/App: gsd-pi
2
2
  // File Purpose: Auto Orchestration module implementation and ADR-015 invariant pipeline owner.
3
+ //
4
+ // Phase 2 of #442 collapsed the nine single-implementation adapter seams
5
+ // (DispatchAdapter, RecoveryAdapter, StateReconciliationAdapter,
6
+ // ToolContractAdapter, WorktreeAdapter, HealthAdapter, UokGateAdapter,
7
+ // RuntimePersistenceAdapter, NotificationAdapter) into this class. The
8
+ // orchestrator now constructs from the concrete extension context and calls
9
+ // the real collaborators (state-reconciliation, doctor-proactive,
10
+ // auto-dispatch, recovery-classification, tool-contract, worktree-safety,
11
+ // uok/gate-runner, journal, session-lock, ctx.ui.notify) directly.
3
12
 
4
- import type { AutoAdvanceResult, AutoOrchestrationModule, AutoOrchestratorDeps, AutoSessionContext, AutoStatus } from "./contracts.js";
5
- import type { GSDState } from "../types.js";
13
+ import type { ExtensionAPI, ExtensionContext } from "@gsd/pi-coding-agent";
14
+
15
+ import type { AutoAdvanceResult, AutoOrchestrationModule, AutoSessionContext, AutoStatus, AutoTerminalOutcome } from "./contracts.js";
16
+ import type { AutoSession, PendingOrchestrationDispatch } from "./session.js";
17
+ import type { GSDState, Phase } from "../types.js";
18
+ import type { MinimalModelRegistry } from "../context-budget.js";
19
+
20
+ type BlockedAdvanceResult = Extract<AutoAdvanceResult, { kind: "blocked" }>;
21
+
22
+ import { debugCount, debugLog, debugTime } from "../debug-logger.js";
23
+ import { reconcileBeforeDispatch } from "../state-reconciliation.js";
24
+ import { isLegalEdge, IllegalPhaseTransitionError } from "../state-transition-matrix.js";
25
+ import { hasPendingDeepStage, resolveDispatch } from "../auto-dispatch.js";
26
+ import { classifyFailure } from "../recovery-classification.js";
27
+ import { verifyExpectedArtifact, refreshRecoveryDbForArtifact } from "../auto-recovery.js";
28
+ import { invalidateAllCaches } from "../cache.js";
29
+ import { compileUnitToolContract } from "../tool-contract.js";
30
+ import { createWorktreeSafetyModule } from "../worktree-safety.js";
31
+ import { repairAutoWorktreeSafetyFailure } from "../auto-worktree-repair.js";
32
+ import { resolveManifest } from "../unit-context-manifest.js";
33
+ import {
34
+ preDispatchHealthGate,
35
+ recordHealthSnapshot,
36
+ } from "../doctor-proactive.js";
37
+ import { checkResourcesStale, autoWorktreeBranch, mergeMilestoneToMain } from "../auto-worktree.js";
38
+ import { getSessionLockStatus } from "../session-lock.js";
39
+ import { resolveUokFlags } from "../uok/flags.js";
40
+ import { emitJournalEvent as _emitJournalEvent } from "../journal.js";
41
+ import { loadEffectiveGSDPreferences, getIsolationMode, resolveEffectiveUnitIsolationMode } from "../preferences.js";
42
+ import {
43
+ detectWorktreeName,
44
+ getMainBranch,
45
+ resolveProjectRoot,
46
+ resolveWorktreeProjectRoot,
47
+ } from "../worktree.js";
48
+ import { getPriorSliceCompletionBlocker } from "../dispatch-guard.js";
49
+ import { GitServiceImpl } from "../git-service.js";
50
+ import { WorktreeStateProjection } from "../worktree-state-projection.js";
51
+ import { WorktreeLifecycle } from "../worktree-lifecycle.js";
52
+ import { createMilestoneMergeTransaction } from "../milestone-merge-transaction.js";
53
+ import { createWorkspace, scopeMilestone } from "../workspace.js";
54
+ import { supportsStructuredQuestions } from "../workflow-mcp.js";
55
+ import { getRegisteredToolSnapshot, getToolBaselineSnapshot } from "../auto-model-selection.js";
56
+ import { deriveState } from "../state.js";
57
+ import { parseUnitId } from "../unit-id.js";
58
+ import { isClosedStatus } from "../status-guards.js";
59
+ import {
60
+ isDbAvailable,
61
+ getSlice,
62
+ getTask,
63
+ } from "../gsd-db.js";
64
+ import { refreshWorkflowDatabaseFromDisk } from "../db-workspace.js";
65
+ import { getErrorMessage } from "../error-utils.js";
66
+ import { logWarning } from "../workflow-logger.js";
67
+ import { normalizeRealPath } from "../paths.js";
68
+ import {
69
+ buildDispatchKey,
70
+ createDispatchHistory,
71
+ STUCK_WINDOW_SIZE,
72
+ type DispatchHistory,
73
+ } from "./dispatch-history.js";
74
+ import { existsSync, readFileSync } from "node:fs";
75
+ import { join } from "node:path";
76
+ import { evaluateAllCompleteSettlement } from "../milestone-settlement.js";
6
77
 
7
78
  function now(): number {
8
79
  return Date.now();
9
80
  }
10
81
 
82
+ function noRemainingUnitsOutcome(stateSnapshot: GSDState): AutoTerminalOutcome {
83
+ if (stateSnapshot.phase === "complete") {
84
+ return {
85
+ code: "all-complete",
86
+ displayReason: "All milestones complete",
87
+ allMilestonesComplete: true,
88
+ };
89
+ }
90
+ return {
91
+ code: "no-remaining-units",
92
+ displayReason: "No remaining units",
93
+ allMilestonesComplete: false,
94
+ };
95
+ }
96
+
11
97
  /**
12
- * Size of the dispatch-decision ring buffer used by the Auto Orchestration
13
- * module's stuck-loop detector. When the same `${unitType}:${unitId}` key
14
- * fills the window, advance() blocks with `action: "stop"`.
98
+ * Concrete construction context for the Auto Orchestrator.
15
99
  *
16
- * Mirrors the legacy `STUCK_WINDOW_SIZE` in auto/phases.ts so behaviour is
17
- * preserved across the eventual cutover (issue #5791).
100
+ * Phase 2 of #442 replaced the nine adapter interfaces with this bundle of the
101
+ * real values the wiring factory used to close over: the extension context and
102
+ * API, the dispatch/runtime base paths, and the shared {@link AutoSession}
103
+ * singleton.
18
104
  */
19
- export const STUCK_WINDOW_SIZE = 6;
105
+ export interface OrchestratorContext {
106
+ ctx: ExtensionContext;
107
+ pi: ExtensionAPI;
108
+ dispatchBasePath: string;
109
+ runtimeBasePath: string;
110
+ session: AutoSession;
111
+ }
20
112
 
21
- function noRemainingUnitsReason(stateSnapshot: GSDState): string {
22
- if (stateSnapshot.phase === "complete") {
23
- return "all milestones complete";
113
+ /** Result type of a single dispatch decision. */
114
+ export type DispatchDecision =
115
+ | { kind: "blocked"; reason: string; action: "pause" | "stop" }
116
+ | { kind: "skipped"; reason: string }
117
+ | { unitType: string; unitId: string; reason: string; preconditions: string[] }
118
+ | null;
119
+
120
+ /** Inputs to a dispatch decision. Caller-supplied fields override ctx-derived ones. */
121
+ export interface DispatchDecisionInput {
122
+ stateSnapshot: GSDState;
123
+ /** Optional live session context, forwarded to dispatch rules that need session-derived state. */
124
+ session?: AutoSession;
125
+ /** Mirrors `DispatchContext.structuredQuestionsAvailable` — "true"/"false" string per the dispatch contract. */
126
+ structuredQuestionsAvailable?: "true" | "false";
127
+ /** Session model context window in tokens, forwarded to the budget engine. */
128
+ sessionContextWindow?: number;
129
+ /** Session model provider, used for provider-specific effective context windows. */
130
+ sessionProvider?: string;
131
+ /** Model registry for executor-model lookups inside the budget engine. */
132
+ modelRegistry?: MinimalModelRegistry;
133
+ }
134
+
135
+ function getAlreadyClosedDispatchReason(unitType: string, unitId: string): string | null {
136
+ if (!isDbAvailable()) return null;
137
+ refreshWorkflowDatabaseFromDisk();
138
+ const { milestone, slice, task } = parseUnitId(unitId);
139
+ if (unitType === "execute-task" && milestone && slice && task) {
140
+ const row = getTask(milestone, slice, task);
141
+ return row && isClosedStatus(row.status)
142
+ ? `execute-task ${unitId} is already ${row.status}`
143
+ : null;
144
+ }
145
+ if (unitType === "complete-slice" && milestone && slice) {
146
+ const row = getSlice(milestone, slice);
147
+ return row && isClosedStatus(row.status)
148
+ ? `complete-slice ${unitId} is already ${row.status}`
149
+ : null;
150
+ }
151
+ return null;
152
+ }
153
+
154
+ function shouldAdoptActiveMilestone(
155
+ state: GSDState,
156
+ activeSession: AutoSession | undefined,
157
+ activeDispatchBasePath: string,
158
+ ): boolean {
159
+ const activeMilestoneId = state.activeMilestone?.id;
160
+ const currentMilestoneId = activeSession?.currentMilestoneId;
161
+ if (!activeSession || !activeMilestoneId || !currentMilestoneId || activeMilestoneId === currentMilestoneId) {
162
+ return false;
163
+ }
164
+
165
+ const scopedWorktreeMilestone =
166
+ (activeSession.basePath ? detectWorktreeName(activeSession.basePath) : null) ??
167
+ detectWorktreeName(activeDispatchBasePath);
168
+ if (scopedWorktreeMilestone && scopedWorktreeMilestone !== activeMilestoneId) {
169
+ return false;
170
+ }
171
+
172
+ const currentMilestone = state.registry.find((milestone) => milestone.id === currentMilestoneId);
173
+ return !!currentMilestone && isClosedStatus(currentMilestone.status);
174
+ }
175
+
176
+ /**
177
+ * Pure dispatch-decision function — formerly `createWiredDispatchAdapter`'s
178
+ * `decideNextUnit`. Folded out of the closure so the orchestrator can call it
179
+ * directly and tests can drive the exact dispatch decision logic against real
180
+ * fixtures without re-introducing an adapter seam.
181
+ *
182
+ * Derives session-derived dispatch inputs the same way phases.ts:runDispatch
183
+ * does (#5789): prefers caller-supplied values when present so test harnesses
184
+ * and alternative wirings can inject deterministic snapshots; otherwise pulls
185
+ * from the captured pi/ctx references.
186
+ */
187
+ export async function decideOrchestratorDispatch(
188
+ ctx: ExtensionContext,
189
+ pi: ExtensionAPI,
190
+ dispatchBasePath: string,
191
+ session: AutoSession | undefined,
192
+ input: DispatchDecisionInput,
193
+ ): Promise<DispatchDecision> {
194
+ const state = input.stateSnapshot;
195
+ const active = state.activeMilestone;
196
+ const activeSession = input.session ?? session;
197
+ const activeDispatchBasePath = activeSession?.basePath || dispatchBasePath;
198
+ const prefs = loadEffectiveGSDPreferences(activeDispatchBasePath)?.preferences;
199
+ if (!active) {
200
+ if (state.phase !== "pre-planning") return null;
201
+ if (!hasPendingDeepStage(prefs, activeDispatchBasePath)) {
202
+ return {
203
+ kind: "blocked",
204
+ reason: state.nextAction || "No active milestone. Run /gsd unpark <id> or create a new milestone.",
205
+ action: "stop",
206
+ };
207
+ }
208
+ }
209
+
210
+ if (active && activeSession && shouldAdoptActiveMilestone(state, activeSession, activeDispatchBasePath)) {
211
+ activeSession.currentMilestoneId = active.id;
212
+ }
213
+ const dispatchMid = active?.id ?? activeSession?.currentMilestoneId ?? "";
214
+ const dispatchMidTitle = active?.title ?? "";
215
+
216
+ // Derive session-derived dispatch inputs the same way phases.ts:runDispatch does
217
+ // (#5789). Prefer caller-supplied values when present so test harnesses and
218
+ // alternative wirings can inject deterministic snapshots; otherwise pull from
219
+ // the captured pi/ctx references.
220
+ const sessionProvider = input.sessionProvider ?? ctx.model?.provider;
221
+ const sessionContextWindow = input.sessionContextWindow ?? ctx.model?.contextWindow;
222
+ const modelRegistry = input.modelRegistry ?? (ctx.modelRegistry as MinimalModelRegistry | undefined);
223
+ const authMode =
224
+ sessionProvider && typeof ctx.modelRegistry?.getProviderAuthMode === "function"
225
+ ? ctx.modelRegistry.getProviderAuthMode(sessionProvider)
226
+ : undefined;
227
+ // Use baseline snapshot — same reason as phases.ts:runDispatch: the live
228
+ // active set may be narrowed by the prior unit before selectAndApplyModel
229
+ // restores it, causing false transport-preflight failures (#477 follow-up).
230
+ const activeTools = getToolBaselineSnapshot(pi);
231
+ const registeredTools = getRegisteredToolSnapshot(pi);
232
+ // Mirrors runDispatch: deep-planning keeps approval gates in plain chat
233
+ // because structured questions can be cancelled outside the chat turn on
234
+ // some transports.
235
+ const structuredQuestionsAvailable =
236
+ input.structuredQuestionsAvailable ??
237
+ (prefs?.planning_depth === "deep"
238
+ ? "false"
239
+ : supportsStructuredQuestions(activeTools, {
240
+ authMode,
241
+ baseUrl: ctx.model?.baseUrl,
242
+ })
243
+ ? "true"
244
+ : "false");
245
+
246
+ // Only replay a milestone-scoped verification retry when a milestone is
247
+ // active. Pre-PR (#712 fix), `!active` returned null before reaching this
248
+ // block, so the retry was preserved for a future tick. The new
249
+ // pre-planning + deep-pending fall-through must keep that contract:
250
+ // otherwise a stale execute-task / complete-slice / complete-milestone
251
+ // retry whose target milestone has since been parked would preempt
252
+ // project-level deep rules like `discuss-project`.
253
+ const pendingRetry = session?.pendingVerificationRetryDispatch;
254
+ if (session && pendingRetry && active) {
255
+ session.pendingVerificationRetryDispatch = null;
256
+ const alreadyClosedReason = getAlreadyClosedDispatchReason(
257
+ pendingRetry.unitType,
258
+ pendingRetry.unitId,
259
+ );
260
+ if (alreadyClosedReason) {
261
+ session.pendingOrchestrationDispatch = null;
262
+ session.pendingVerificationRetry = null;
263
+ return { kind: "skipped", reason: alreadyClosedReason };
264
+ }
265
+ session.pendingOrchestrationDispatch = pendingRetry;
266
+ return {
267
+ unitType: pendingRetry.unitType,
268
+ unitId: pendingRetry.unitId,
269
+ reason: "verification-retry",
270
+ preconditions: [],
271
+ };
272
+ }
273
+
274
+ const action = await resolveDispatch({
275
+ basePath: activeDispatchBasePath,
276
+ mid: dispatchMid,
277
+ midTitle: dispatchMidTitle,
278
+ state,
279
+ prefs,
280
+ session: activeSession,
281
+ structuredQuestionsAvailable,
282
+ sessionContextWindow,
283
+ sessionProvider,
284
+ modelRegistry,
285
+ activeTools,
286
+ registeredTools,
287
+ sessionAuthMode: authMode,
288
+ sessionBaseUrl: ctx.model?.baseUrl,
289
+ });
290
+
291
+ if (action.action === "stop") {
292
+ if (session) session.pendingOrchestrationDispatch = null;
293
+ return {
294
+ kind: "blocked",
295
+ reason: action.reason,
296
+ action: action.level === "warning" ? "pause" : "stop",
297
+ };
24
298
  }
25
- return "no remaining units";
299
+ if (action.action !== "dispatch") {
300
+ if (session) session.pendingOrchestrationDispatch = null;
301
+ return {
302
+ kind: "skipped",
303
+ reason: action.matchedRule ?? "dispatch-skip",
304
+ };
305
+ }
306
+ const alreadyClosedReason = getAlreadyClosedDispatchReason(action.unitType, action.unitId);
307
+ if (alreadyClosedReason) {
308
+ if (session) {
309
+ session.pendingOrchestrationDispatch = null;
310
+ session.pendingVerificationRetry = null;
311
+ }
312
+ return { kind: "skipped", reason: alreadyClosedReason };
313
+ }
314
+ if (session) {
315
+ const pending: PendingOrchestrationDispatch = {
316
+ unitType: action.unitType,
317
+ unitId: action.unitId,
318
+ prompt: action.prompt,
319
+ pauseAfterUatDispatch: action.pauseAfterDispatch ?? false,
320
+ state,
321
+ mid: dispatchMid,
322
+ midTitle: dispatchMidTitle,
323
+ };
324
+ session.pendingOrchestrationDispatch = pending;
325
+ }
326
+ return {
327
+ unitType: action.unitType,
328
+ unitId: action.unitId,
329
+ reason: action.matchedRule ?? "dispatch",
330
+ preconditions: [],
331
+ };
26
332
  }
27
333
 
28
334
  export class AutoOrchestrator implements AutoOrchestrationModule {
@@ -30,33 +336,529 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
30
336
  phase: "idle",
31
337
  transitionCount: 0,
32
338
  };
33
- private readonly deps: AutoOrchestratorDeps;
339
+ private readonly ctx: ExtensionContext;
340
+ private readonly pi: ExtensionAPI;
341
+ private readonly dispatchBasePath: string;
342
+ private readonly runtimeBasePath: string;
343
+ private readonly s: AutoSession;
344
+ private readonly flowId: string;
345
+ private seq = 0;
34
346
  private lastAdvanceKey: string | null = null;
35
347
  private lastFinalizedUnitKey: string | null = null;
36
- private dispatchKeyWindow: string[] = [];
348
+ // Dispatch History module (#482): the dispatch-decision window with
349
+ // cross-session DB rehydration and full detect-stuck rules.
350
+ private readonly dispatchHistory: DispatchHistory;
351
+ // ADR-030 Phase Transition Invariant: the prior advance's reconciled Phase,
352
+ // the "from" endpoint of the edge check. In-memory; reset on start/resume/stop
353
+ // so the first advance of a session has no edge to assert.
354
+ private lastDerivedPhase: Phase | null = null;
355
+ // #442: the unit key we last attempted graduated stuck-recovery for. Bounds
356
+ // recovery to one attempt per stuck episode per run (reset on start/resume/
357
+ // stop), mirroring the legacy Level-1-then-Level-2 escalation in phases.ts.
358
+ private lastStuckRecoveryKey: string | null = null;
37
359
 
38
- public constructor(deps: AutoOrchestratorDeps) {
39
- this.deps = deps;
360
+ public constructor(context: OrchestratorContext) {
361
+ this.ctx = context.ctx;
362
+ this.pi = context.pi;
363
+ this.dispatchBasePath = context.dispatchBasePath;
364
+ this.runtimeBasePath = context.runtimeBasePath;
365
+ this.s = context.session;
366
+ this.flowId = `auto-orchestrator-${Date.now()}`;
367
+ this.dispatchHistory = createDispatchHistory({
368
+ windowSize: STUCK_WINDOW_SIZE,
369
+ // Same stable scope the auto-loop uses for stuck-state persistence so
370
+ // rehydration reads the rows the dispatch ledger wrote for this project.
371
+ resolveScopeId: () =>
372
+ normalizeRealPath(
373
+ this.s.scope?.workspace.projectRoot ??
374
+ (this.s.originalBasePath || this.s.basePath || this.runtimeBasePath),
375
+ ) || null,
376
+ });
377
+ }
378
+
379
+ // ── Live base-path resolution (was the wiring factory's getLiveDispatchBasePath) ──
380
+
381
+ private getLiveDispatchBasePath(): string {
382
+ return resolveLiveOrchestratorBasePath({
383
+ capturedBasePath: this.dispatchBasePath,
384
+ runtimeBasePath: this.runtimeBasePath,
385
+ sessionBasePath: this.s.basePath,
386
+ originalBasePath: this.s.originalBasePath,
387
+ });
388
+ }
389
+
390
+ // ── RuntimePersistenceAdapter (folded) ───────────────────────────────────
391
+
392
+ private ensureLockOwnership(): void {
393
+ const status = getSessionLockStatus(this.runtimeBasePath);
394
+ if (!status.valid || status.failureReason === "pid-mismatch") {
395
+ throw new Error("session lock held by another process");
396
+ }
397
+ }
398
+
399
+ /**
400
+ * Map an orchestrator lifecycle event name to its journal eventType and emit
401
+ * it. The name→eventType ternary is preserved byte-for-byte from the legacy
402
+ * wired RuntimePersistenceAdapter.journalTransition.
403
+ */
404
+ private journalTransition(event: {
405
+ name: string;
406
+ reason?: string;
407
+ unitType?: string;
408
+ unitId?: string;
409
+ }): void {
410
+ const eventType = event.name === "start"
411
+ ? "orchestrator-iteration-start"
412
+ : event.name === "resume"
413
+ ? "orchestrator-iteration-start"
414
+ : event.name === "advance"
415
+ ? "orchestrator-dispatch-match"
416
+ : event.name === "advance-blocked"
417
+ ? "orchestrator-guard-block"
418
+ : event.name === "advance-stopped"
419
+ ? "orchestrator-dispatch-stop"
420
+ : event.name === "advance-error"
421
+ ? "orchestrator-iteration-end"
422
+ : event.name === "advance-paused" || event.name === "advance-retry"
423
+ ? "orchestrator-guard-block"
424
+ : event.name === "stop"
425
+ ? "orchestrator-terminal"
426
+ : "orchestrator-iteration-end";
427
+
428
+ _emitJournalEvent(this.runtimeBasePath, {
429
+ ts: new Date().toISOString(),
430
+ flowId: this.flowId,
431
+ seq: ++this.seq,
432
+ eventType,
433
+ data: {
434
+ source: "auto-orchestrator",
435
+ name: event.name,
436
+ reason: event.reason,
437
+ unitType: event.unitType,
438
+ unitId: event.unitId,
439
+ },
440
+ });
441
+ }
442
+
443
+ // ── NotificationAdapter (folded) ─────────────────────────────────────────
444
+
445
+ private notifyLifecycle(event: { name: string; detail?: string }): void {
446
+ if (event.name === "error") {
447
+ this.ctx.ui.notify(event.detail ?? "auto orchestration error", "error");
448
+ }
449
+ }
450
+
451
+ // ── HealthAdapter (folded) ───────────────────────────────────────────────
452
+
453
+ private checkResourcesStale(): string | null {
454
+ return checkResourcesStale(this.s.resourceVersionOnStart);
455
+ }
456
+
457
+ private async preAdvanceGate(): Promise<
458
+ | { kind: "pass"; fixesApplied?: readonly string[] }
459
+ | { kind: "fail"; reason: string; action?: "pause" | "stop" }
460
+ | { kind: "threw"; error: unknown }
461
+ > {
462
+ try {
463
+ const gate = await preDispatchHealthGate(this.getLiveDispatchBasePath());
464
+ if (gate.proceed) {
465
+ return {
466
+ kind: "pass",
467
+ fixesApplied: gate.fixesApplied,
468
+ };
469
+ }
470
+ return {
471
+ kind: "fail",
472
+ reason: gate.reason ?? "Pre-dispatch health check failed — run /gsd doctor for details.",
473
+ action: gate.severity ?? "pause",
474
+ };
475
+ } catch (error) {
476
+ return { kind: "threw", error };
477
+ }
478
+ }
479
+
480
+ private postAdvanceRecord(result: AutoAdvanceResult): void {
481
+ if (result.kind === "error") {
482
+ recordHealthSnapshot(1, 0, 0, [{
483
+ code: "orchestration-error",
484
+ message: result.reason ?? "orchestration error",
485
+ severity: "error",
486
+ unitId: "orchestration",
487
+ }], [], "orchestration");
488
+ } else if (result.kind === "blocked") {
489
+ recordHealthSnapshot(0, 1, 0, [{
490
+ code: "orchestration-blocked",
491
+ message: result.reason ?? "orchestration blocked",
492
+ severity: "warning",
493
+ unitId: "orchestration",
494
+ }], [], "orchestration");
495
+ }
496
+ }
497
+
498
+ // ── UokGateAdapter (folded) ──────────────────────────────────────────────
499
+
500
+ private async emitUokGate(input: {
501
+ gateId: string;
502
+ gateType: "policy" | "execution";
503
+ outcome: "pass" | "fail" | "manual-attention";
504
+ failureClass: "none" | "policy" | "manual-attention";
505
+ rationale: string;
506
+ findings?: string;
507
+ milestoneId?: string;
508
+ }): Promise<void> {
509
+ const activeBasePath = this.getLiveDispatchBasePath();
510
+ const prefs = loadEffectiveGSDPreferences(activeBasePath)?.preferences;
511
+ const uokFlags = resolveUokFlags(prefs);
512
+ if (!uokFlags.gates) return;
513
+ const milestoneId = input.milestoneId ?? this.s.currentMilestoneId ?? undefined;
514
+ try {
515
+ const { UokGateRunner } = await import("../uok/gate-runner.js");
516
+ const runner = new UokGateRunner();
517
+ runner.register({
518
+ id: input.gateId,
519
+ type: input.gateType,
520
+ execute: async () => ({
521
+ outcome: input.outcome,
522
+ failureClass: input.failureClass,
523
+ rationale: input.rationale,
524
+ findings: input.findings ?? "",
525
+ }),
526
+ });
527
+ await runner.run(input.gateId, {
528
+ basePath: activeBasePath,
529
+ traceId: `pre-dispatch:${this.flowId}`,
530
+ turnId: `orch-${this.seq}`,
531
+ milestoneId,
532
+ unitType: "pre-dispatch",
533
+ unitId: `orch-${this.seq}`,
534
+ });
535
+ } catch (err) {
536
+ logWarning("engine", `uok gate emit failed: ${getErrorMessage(err)}`, {
537
+ file: "orchestrator.ts",
538
+ gateId: input.gateId,
539
+ gateType: input.gateType,
540
+ ...(milestoneId ? { milestoneId } : {}),
541
+ });
542
+ }
543
+ }
544
+
545
+ // ── StateReconciliationAdapter (folded) ──────────────────────────────────
546
+
547
+ private async reconcileBeforeDispatch(): Promise<
548
+ { ok: true; reason: string; stateSnapshot?: GSDState }
549
+ | { ok: false; reason: string; stateSnapshot?: GSDState }
550
+ > {
551
+ const activeBasePath = this.getLiveDispatchBasePath();
552
+ const result = await reconcileBeforeDispatch(activeBasePath);
553
+ // Failure-path summaries written by gsd_summary_save create
554
+ // artifact-db-status-divergence blockers for tasks that are still
555
+ // pending (gsd_task_complete never ran). These tasks can still be
556
+ // dispatched and the drift self-heals once they complete successfully.
557
+ const hardBlockers = result.blockers.filter(
558
+ (b) =>
559
+ !b.includes("has SUMMARY artifact while DB status is") &&
560
+ !b.includes("has SUMMARY on disk while DB status is") &&
561
+ !b.includes("has task SUMMARY artifacts but no DB tasks"),
562
+ );
563
+ if (hardBlockers.length > 0) {
564
+ return {
565
+ ok: false,
566
+ reason: hardBlockers[0],
567
+ stateSnapshot: result.stateSnapshot,
568
+ };
569
+ }
570
+ const repairedKinds = result.repaired.map((d) => d.kind);
571
+ return {
572
+ ok: true,
573
+ reason:
574
+ repairedKinds.length > 0
575
+ ? `repaired: ${repairedKinds.join(", ")}`
576
+ : "clean",
577
+ stateSnapshot: result.stateSnapshot,
578
+ };
579
+ }
580
+
581
+ // ── DispatchAdapter (folded) ─────────────────────────────────────────────
582
+
583
+ private decideNextUnit(input: DispatchDecisionInput): Promise<DispatchDecision> {
584
+ return decideOrchestratorDispatch(this.ctx, this.pi, this.dispatchBasePath, this.s, input);
585
+ }
586
+
587
+ private evaluateNoRemainingUnitsSettlement(stateSnapshot: GSDState): BlockedAdvanceResult | null {
588
+ const settlement = evaluateAllCompleteSettlement({
589
+ milestoneId: this.s.currentMilestoneId ?? stateSnapshot.activeMilestone?.id,
590
+ statePhase: stateSnapshot.phase,
591
+ basePath: this.s.basePath || this.getLiveDispatchBasePath(),
592
+ originalBasePath: this.s.originalBasePath || this.runtimeBasePath,
593
+ milestoneMerged: this.s.milestoneMergedInPhases,
594
+ });
595
+ this.s.milestoneSettlement = settlement;
596
+ if (settlement.ok) return null;
597
+ return {
598
+ kind: "blocked",
599
+ reason: settlement.message,
600
+ action: settlement.action,
601
+ stateSnapshot,
602
+ terminalOutcome: {
603
+ code: "settlement-blocked",
604
+ displayReason: settlement.message,
605
+ nextAction: settlement.nextAction,
606
+ milestoneId: settlement.milestoneId,
607
+ allMilestonesComplete: false,
608
+ },
609
+ };
610
+ }
611
+
612
+ private clearPendingDispatch(): void {
613
+ this.s.pendingOrchestrationDispatch = null;
614
+ }
615
+
616
+ private findPriorSliceCompletionBlocker(unitType: string, unitId: string): string | null {
617
+ const guardBasePath = resolveWorktreeProjectRoot(
618
+ this.getLiveDispatchBasePath(),
619
+ this.s.originalBasePath,
620
+ );
621
+ let mainBranch = "main";
622
+ try {
623
+ mainBranch = getMainBranch(guardBasePath);
624
+ } catch (err) {
625
+ // Preserve legacy dispatch behavior: fall back to main when branch
626
+ // discovery fails, then let the guard make the progression decision.
627
+ logWarning(
628
+ "engine",
629
+ `branch discovery failed, falling back to main: ${getErrorMessage(err)}`,
630
+ { file: "orchestrator.ts" },
631
+ );
632
+ }
633
+ return getPriorSliceCompletionBlocker(guardBasePath, mainBranch, unitType, unitId);
634
+ }
635
+
636
+ // ── ToolContractAdapter (folded) ─────────────────────────────────────────
637
+
638
+ private compileUnitToolContract(unitType: string): { ok: true; reason: string } | { ok: false; reason: string } {
639
+ const result = compileUnitToolContract(unitType);
640
+ if (!result.ok) return { ok: false, reason: result.detail };
641
+ return { ok: true, reason: result.contract.validationRules.join(", ") };
642
+ }
643
+
644
+ // ── WorktreeAdapter (folded) ─────────────────────────────────────────────
645
+
646
+ private getEffectiveUnitIsolationMode(basePath: string): ReturnType<typeof getIsolationMode> {
647
+ return resolveEffectiveUnitIsolationMode(
648
+ getIsolationMode(basePath),
649
+ this.s.isolationDegraded,
650
+ this.s.strandedRecoveryIsolationMode,
651
+ );
652
+ }
653
+
654
+ private buildLifecycle(): WorktreeLifecycle {
655
+ return new WorktreeLifecycle(this.s, {
656
+ gitServiceFactory: (basePath: string) => {
657
+ const gitConfig = loadEffectiveGSDPreferences()?.preferences?.git ?? {};
658
+ return new GitServiceImpl(basePath, gitConfig);
659
+ },
660
+ worktreeProjection: new WorktreeStateProjection(),
661
+ mergeMilestoneToMain: createMilestoneMergeTransaction(mergeMilestoneToMain),
662
+ });
663
+ }
664
+
665
+ private rebuildScope(rawPath: string, milestoneId: string | null): void {
666
+ if (!milestoneId) {
667
+ this.s.scope = null;
668
+ return;
669
+ }
670
+ try {
671
+ const workspace = createWorkspace(rawPath);
672
+ this.s.scope = scopeMilestone(workspace, milestoneId);
673
+ } catch {
674
+ // Non-fatal — scope is additive. Existing readers still use basePath.
675
+ this.s.scope = null;
676
+ }
677
+ }
678
+
679
+ private async prepareWorktreeForUnit(
680
+ unitType: string,
681
+ unitId: string,
682
+ ): Promise<{ ok: true; reason: string } | { ok: false; reason: string }> {
683
+ const isolationMode = this.getEffectiveUnitIsolationMode(this.runtimeBasePath);
684
+ const manifest = resolveManifest(unitType);
685
+ if (!manifest) {
686
+ return {
687
+ ok: false,
688
+ reason: `No Unit manifest is registered for ${unitType}`,
689
+ };
690
+ }
691
+ if (isolationMode !== "worktree") {
692
+ return { ok: true, reason: "not-required" };
693
+ }
694
+ const writeScope =
695
+ manifest.tools.mode === "all" || manifest.tools.mode === "docs"
696
+ ? "source-writing"
697
+ : "planning-only";
698
+ const safety = createWorktreeSafetyModule();
699
+ const activeBasePath = this.getLiveDispatchBasePath();
700
+ const snapshot = await deriveState(activeBasePath);
701
+ const milestoneId = snapshot.activeMilestone?.id ?? null;
702
+ const expectedBranch = milestoneId ? autoWorktreeBranch(milestoneId) : null;
703
+ let result = safety.validateUnitRoot({
704
+ unitType,
705
+ unitId,
706
+ writeScope,
707
+ projectRoot: this.runtimeBasePath,
708
+ unitRoot: activeBasePath,
709
+ milestoneId,
710
+ isolationMode,
711
+ expectedBranch,
712
+ });
713
+ if (!result.ok) {
714
+ const repaired = await repairAutoWorktreeSafetyFailure({
715
+ safetyResult: result,
716
+ projectRoot: this.runtimeBasePath,
717
+ activeRoot: activeBasePath,
718
+ milestoneId,
719
+ enterMilestone: async (id) => {
720
+ this.buildLifecycle().adoptSessionRoot(this.runtimeBasePath, this.s.originalBasePath || this.runtimeBasePath);
721
+ const enterResult = this.buildLifecycle().enterMilestone(id, {
722
+ notify: this.ctx.ui.notify.bind(this.ctx.ui),
723
+ });
724
+ if (!enterResult.ok) return { ok: false, reason: enterResult.reason };
725
+ this.rebuildScope(this.s.basePath, this.s.currentMilestoneId);
726
+ return { ok: true };
727
+ },
728
+ revalidate: () => safety.validateUnitRoot({
729
+ unitType,
730
+ unitId,
731
+ writeScope,
732
+ projectRoot: this.runtimeBasePath,
733
+ unitRoot: this.getLiveDispatchBasePath(),
734
+ milestoneId,
735
+ isolationMode: this.getEffectiveUnitIsolationMode(this.runtimeBasePath),
736
+ expectedBranch,
737
+ }),
738
+ });
739
+ result = repaired.result;
740
+ if (result.ok) {
741
+ return { ok: true, reason: repaired.repaired ? `repaired-${result.kind}` : result.kind };
742
+ }
743
+ const repairDetail = repaired.repairReason
744
+ ? ` (repair skipped: ${repaired.repairReason})`
745
+ : "";
746
+ return { ok: false, reason: `${result.kind}: ${result.reason}${repairDetail}` };
747
+ }
748
+ return { ok: true, reason: result.kind };
749
+ }
750
+
751
+ // ── RecoveryAdapter (folded) ─────────────────────────────────────────────
752
+
753
+ private classifyAndRecover(input: {
754
+ error: unknown;
755
+ unitType?: string;
756
+ unitId?: string;
757
+ }): { action: "retry" | "escalate" | "stop"; reason: string } {
758
+ const recovery = classifyFailure(input);
759
+ return { action: recovery.action, reason: recovery.reason };
760
+ }
761
+
762
+ /**
763
+ * ADR-030 Phase Transition Invariant (advisory mode). The matrix is an
764
+ * assertion, not a decision-maker — deriveState already chose the phase; we
765
+ * only observe illegal *derived* edges that survived reconciliation. The
766
+ * matrix is still a sparse hardening spec, so this is telemetry-only (no
767
+ * block) until it is expanded into a validated legal-edge graph. To enforce:
768
+ * `throw violation;` instead of logging — recovery-classification maps
769
+ * IllegalPhaseTransitionError to kind "illegal-transition" (escalate).
770
+ */
771
+ private observePhaseTransition(from: Phase, to: Phase): void {
772
+ if (isLegalEdge(from, to)) return;
773
+ const violation = new IllegalPhaseTransitionError(from, to);
774
+ debugLog("phase-transition-advisory", { from, to, message: violation.message });
775
+ }
776
+
777
+ // ── Lifecycle verbs ──────────────────────────────────────────────────────
778
+
779
+ /**
780
+ * #442: graduated stuck recovery, ported from the legacy
781
+ * auto/phases.ts:runDispatch path that Phase 3 retires. The ring-buffer
782
+ * hard-stops (stuck-loop saturation and finalized-repeat) would otherwise
783
+ * KILL a unit that actually completed on disk but whose DB row is still
784
+ * stale. Before hard-stopping, verify the expected artifact exists; if so,
785
+ * refresh the DB from it, invalidate caches and reset the dispatch ring so
786
+ * the next advance picks the correct next unit. Bounded to one attempt per
787
+ * stuck key per episode (reset on lifecycle + genuine finalize) to avoid an
788
+ * unbounded recover→re-saturate→recover loop — mirrors the legacy
789
+ * Level-1-recover-then-Level-2-hard-stop escalation.
790
+ *
791
+ * Returns true when recovery succeeded; the caller should re-loop (return a
792
+ * skipped result) instead of stopping.
793
+ */
794
+ private tryStuckArtifactRecovery(unitType: string, unitId: string): boolean {
795
+ const key = buildDispatchKey(unitType, unitId);
796
+ if (this.lastStuckRecoveryKey === key) return false; // already tried this episode
797
+ const basePath = this.getLiveDispatchBasePath();
798
+ if (!verifyExpectedArtifact(unitType, unitId, basePath)) return false;
799
+ const refreshed = refreshRecoveryDbForArtifact(unitType, unitId, basePath);
800
+ // Fatal failures cannot be recovered — hard-stop. Non-fatal (e.g. plan-slice
801
+ // DB refresh hiccup) still fall through: invalidating caches and resetting
802
+ // the ring gives the next advance a clean slate to pick up the correct state,
803
+ // mirroring the legacy Level-1 "continue" escalation path.
804
+ if (!refreshed.ok && refreshed.fatal) return false;
805
+ this.lastStuckRecoveryKey = key;
806
+ invalidateAllCaches();
807
+ this.dispatchHistory.clearOnRecovery();
808
+ this.lastAdvanceKey = null;
809
+ this.lastFinalizedUnitKey = null;
810
+ return true;
811
+ }
812
+
813
+ private stuckRecovered(
814
+ decision: { unitType: string; unitId: string },
815
+ stateSnapshot: GSDState,
816
+ ): AutoAdvanceResult {
817
+ const recovered: AutoAdvanceResult = {
818
+ kind: "skipped",
819
+ reason: `stuck-recovery: ${decision.unitType} ${decision.unitId} artifact found on disk; DB refreshed`,
820
+ stateSnapshot,
821
+ };
822
+ this.status.phase = "running";
823
+ this.status.activeUnit = undefined;
824
+ this.bumpTransition();
825
+ this.journalTransition({
826
+ name: "advance-skipped",
827
+ reason: recovered.reason,
828
+ unitType: decision.unitType,
829
+ unitId: decision.unitId,
830
+ });
831
+ this.postAdvanceRecord(recovered);
832
+ return recovered;
40
833
  }
41
834
 
42
835
  public async start(_sessionContext: AutoSessionContext): Promise<AutoAdvanceResult> {
43
836
  this.lastAdvanceKey = null;
44
837
  this.lastFinalizedUnitKey = null;
45
- this.dispatchKeyWindow = [];
838
+ // #482: the DB dispatch ledger is the source of truth across sessions.
839
+ // Discard any in-memory window and rebuild it from the ledger so a unit
840
+ // that was re-dispatched in previous sessions is detected as stuck here
841
+ // instead of silently re-dispatching forever.
842
+ this.dispatchHistory.clearOnRecovery();
843
+ this.dispatchHistory.rehydrate();
844
+ this.lastStuckRecoveryKey = null;
845
+ this.lastDerivedPhase = null;
46
846
  this.status.phase = "running";
47
847
  this.bumpTransition();
48
- await this.deps.runtime.journalTransition({ name: "start" });
49
- await this.deps.notifications.notifyLifecycle({ name: "start" });
848
+ this.journalTransition({ name: "start" });
849
+ this.notifyLifecycle({ name: "start" });
50
850
  return { kind: "started" };
51
851
  }
52
852
 
53
853
  public async advance(): Promise<AutoAdvanceResult> {
854
+ debugCount("dispatches");
855
+ const stopAdvanceTimer = debugTime("orchestrator-advance");
54
856
  try {
55
- await this.deps.runtime.ensureLockOwnership();
857
+ this.ensureLockOwnership();
56
858
 
57
- const staleMsg = this.deps.health.checkResourcesStale();
859
+ const staleMsg = this.checkResourcesStale();
58
860
  if (staleMsg) {
59
- await this.deps.uokGate.emit({
861
+ await this.emitUokGate({
60
862
  gateId: "resource-version-guard",
61
863
  gateType: "policy",
62
864
  outcome: "fail",
@@ -65,11 +867,11 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
65
867
  findings: staleMsg,
66
868
  });
67
869
  const blocked: AutoAdvanceResult = { kind: "blocked", reason: staleMsg, action: "pause" };
68
- await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
69
- await this.deps.health.postAdvanceRecord(blocked);
870
+ this.journalTransition({ name: "advance-blocked", reason: blocked.reason });
871
+ this.postAdvanceRecord(blocked);
70
872
  return blocked;
71
873
  }
72
- await this.deps.uokGate.emit({
874
+ await this.emitUokGate({
73
875
  gateId: "resource-version-guard",
74
876
  gateType: "policy",
75
877
  outcome: "pass",
@@ -77,9 +879,9 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
77
879
  rationale: "resource version guard passed",
78
880
  });
79
881
 
80
- const gate = await this.deps.health.preAdvanceGate();
882
+ const gate = await this.preAdvanceGate();
81
883
  if (gate.kind === "fail") {
82
- await this.deps.uokGate.emit({
884
+ await this.emitUokGate({
83
885
  gateId: "pre-dispatch-health-gate",
84
886
  gateType: "execution",
85
887
  outcome: "manual-attention",
@@ -92,12 +894,12 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
92
894
  reason: gate.reason,
93
895
  action: gate.action ?? "pause",
94
896
  };
95
- await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
96
- await this.deps.health.postAdvanceRecord(blocked);
897
+ this.journalTransition({ name: "advance-blocked", reason: blocked.reason });
898
+ this.postAdvanceRecord(blocked);
97
899
  return blocked;
98
900
  }
99
901
  if (gate.kind === "threw") {
100
- await this.deps.uokGate.emit({
902
+ await this.emitUokGate({
101
903
  gateId: "pre-dispatch-health-gate",
102
904
  gateType: "execution",
103
905
  outcome: "manual-attention",
@@ -107,7 +909,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
107
909
  });
108
910
  // intentional fall-through: matches runPreDispatch behaviour
109
911
  } else {
110
- await this.deps.uokGate.emit({
912
+ await this.emitUokGate({
111
913
  gateId: "pre-dispatch-health-gate",
112
914
  gateType: "execution",
113
915
  outcome: "pass",
@@ -117,7 +919,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
117
919
  });
118
920
  }
119
921
 
120
- const reconciliation = await this.deps.stateReconciliation.reconcileBeforeDispatch();
922
+ const reconciliation = await this.reconcileBeforeDispatch();
121
923
  if (!reconciliation.ok || !reconciliation.stateSnapshot) {
122
924
  const blocked: AutoAdvanceResult = {
123
925
  kind: "blocked",
@@ -125,25 +927,44 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
125
927
  action: "pause",
126
928
  stateSnapshot: reconciliation.stateSnapshot,
127
929
  };
128
- await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
129
- await this.deps.health.postAdvanceRecord(blocked);
930
+ this.journalTransition({ name: "advance-blocked", reason: blocked.reason });
931
+ this.postAdvanceRecord(blocked);
130
932
  return blocked;
131
933
  }
132
934
 
133
- const decision = await this.deps.dispatch.decideNextUnit({ stateSnapshot: reconciliation.stateSnapshot });
935
+ const reconciledPhase = reconciliation.stateSnapshot.phase;
936
+ if (this.lastDerivedPhase !== null) {
937
+ this.observePhaseTransition(this.lastDerivedPhase, reconciledPhase);
938
+ }
939
+ this.lastDerivedPhase = reconciledPhase;
940
+
941
+ const decision = await this.decideNextUnit({ stateSnapshot: reconciliation.stateSnapshot });
134
942
  if (!decision) {
943
+ const settlementBlock = this.evaluateNoRemainingUnitsSettlement(reconciliation.stateSnapshot);
944
+ if (settlementBlock) {
945
+ this.status.phase = "paused";
946
+ this.status.activeUnit = undefined;
947
+ this.lastAdvanceKey = null;
948
+ this.dispatchHistory.clearOnRecovery();
949
+ this.bumpTransition();
950
+ this.journalTransition({ name: "advance-blocked", reason: settlementBlock.reason });
951
+ this.postAdvanceRecord(settlementBlock);
952
+ return settlementBlock;
953
+ }
954
+ const terminalOutcome = noRemainingUnitsOutcome(reconciliation.stateSnapshot);
135
955
  const stopped: AutoAdvanceResult = {
136
956
  kind: "stopped",
137
- reason: noRemainingUnitsReason(reconciliation.stateSnapshot),
957
+ reason: terminalOutcome.displayReason,
138
958
  stateSnapshot: reconciliation.stateSnapshot,
959
+ terminalOutcome,
139
960
  };
140
961
  this.status.phase = "stopped";
141
962
  this.status.activeUnit = undefined;
142
963
  this.lastAdvanceKey = null;
143
- this.dispatchKeyWindow = [];
964
+ this.dispatchHistory.clearOnRecovery();
144
965
  this.bumpTransition();
145
- await this.deps.runtime.journalTransition({ name: "advance-stopped", reason: stopped.reason });
146
- await this.deps.health.postAdvanceRecord(stopped);
966
+ this.journalTransition({ name: "advance-stopped", reason: stopped.reason });
967
+ this.postAdvanceRecord(stopped);
147
968
  return stopped;
148
969
  }
149
970
  if ("kind" in decision && decision.kind === "skipped") {
@@ -155,8 +976,8 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
155
976
  this.status.phase = "running";
156
977
  this.status.activeUnit = undefined;
157
978
  this.bumpTransition();
158
- await this.deps.runtime.journalTransition({ name: "advance-skipped", reason: skipped.reason });
159
- await this.deps.health.postAdvanceRecord(skipped);
979
+ this.journalTransition({ name: "advance-skipped", reason: skipped.reason });
980
+ this.postAdvanceRecord(skipped);
160
981
  return skipped;
161
982
  }
162
983
  if (!("unitType" in decision)) {
@@ -166,37 +987,59 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
166
987
  action: decision.action,
167
988
  stateSnapshot: reconciliation.stateSnapshot,
168
989
  };
169
- await this.deps.runtime.journalTransition({ name: "advance-blocked", reason: blocked.reason });
170
- await this.deps.health.postAdvanceRecord(blocked);
990
+ this.journalTransition({ name: "advance-blocked", reason: blocked.reason });
991
+ this.postAdvanceRecord(blocked);
171
992
  return blocked;
172
993
  }
173
994
 
174
- const nextKey = `${decision.unitType}:${decision.unitId}`;
995
+ const priorSliceBlocker = this.findPriorSliceCompletionBlocker(decision.unitType, decision.unitId);
996
+ if (priorSliceBlocker) {
997
+ this.clearPendingDispatch();
998
+ const blocked: AutoAdvanceResult = {
999
+ kind: "blocked",
1000
+ reason: priorSliceBlocker,
1001
+ action: "stop",
1002
+ stateSnapshot: reconciliation.stateSnapshot,
1003
+ };
1004
+ this.journalTransition({
1005
+ name: "advance-blocked",
1006
+ reason: blocked.reason,
1007
+ unitType: decision.unitType,
1008
+ unitId: decision.unitId,
1009
+ });
1010
+ this.postAdvanceRecord(blocked);
1011
+ return blocked;
1012
+ }
175
1013
 
176
- // Record every dispatch decision in the ring buffer before pre-flight
1014
+ // Record every dispatch decision in the history window before pre-flight
177
1015
  // checks so the stuck-loop detector observes the full decision history
178
1016
  // (including decisions that idempotency would otherwise short-circuit).
179
- // The ring is capped at STUCK_WINDOW_SIZE and evicts oldest-first.
180
- this.dispatchKeyWindow.push(nextKey);
181
- if (this.dispatchKeyWindow.length > STUCK_WINDOW_SIZE) {
182
- this.dispatchKeyWindow.shift();
183
- }
1017
+ // The window is capped at STUCK_WINDOW_SIZE and evicts oldest-first.
1018
+ const nextKey = this.dispatchHistory.recordDispatch(decision.unitType, decision.unitId);
184
1019
 
185
- const matchingCount = this.dispatchKeyWindow.filter((k) => k === nextKey).length;
1020
+ const matchingCount = this.dispatchHistory.countMatching(nextKey);
186
1021
  if (this.lastFinalizedUnitKey === nextKey) {
1022
+ // #442: the unit re-dispatched immediately after finalizing may have
1023
+ // actually completed on disk with a stale DB. Verify + recover before
1024
+ // hard-stopping (legacy graduated stuck-recovery parity).
1025
+ if (this.tryStuckArtifactRecovery(decision.unitType, decision.unitId)) {
1026
+ this.clearPendingDispatch();
1027
+ return this.stuckRecovered(decision, reconciliation.stateSnapshot);
1028
+ }
1029
+ this.clearPendingDispatch();
187
1030
  const blocked: AutoAdvanceResult = {
188
1031
  kind: "blocked",
189
1032
  reason: `state did not advance after finalized ${decision.unitType} ${decision.unitId}`,
190
1033
  action: "stop",
191
1034
  stateSnapshot: reconciliation.stateSnapshot,
192
1035
  };
193
- await this.deps.runtime.journalTransition({
1036
+ this.journalTransition({
194
1037
  name: "advance-blocked",
195
1038
  reason: blocked.reason,
196
1039
  unitType: decision.unitType,
197
1040
  unitId: decision.unitId,
198
1041
  });
199
- await this.deps.health.postAdvanceRecord(blocked);
1042
+ this.postAdvanceRecord(blocked);
200
1043
  return blocked;
201
1044
  }
202
1045
 
@@ -207,70 +1050,90 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
207
1050
  // checks coexist: idempotency for the common immediate-repeat case,
208
1051
  // stuck-loop for the saturated-window case.
209
1052
  if (this.lastAdvanceKey === nextKey && matchingCount < STUCK_WINDOW_SIZE) {
210
- const blocked: AutoAdvanceResult = { kind: "blocked", reason: "idempotent advance: unit already active", action: "pause" };
211
- await this.deps.runtime.journalTransition({
212
- name: "advance-blocked",
213
- reason: blocked.reason,
1053
+ // Unit already active benign no-op. Return skipped so the loop re-polls
1054
+ // without cancelling the in-flight unit (blocked+pause would force-cancel it).
1055
+ this.clearPendingDispatch();
1056
+ const skipped: AutoAdvanceResult = { kind: "skipped", reason: "idempotent advance: unit already active" };
1057
+ this.journalTransition({
1058
+ name: "advance-skipped",
1059
+ reason: skipped.reason,
214
1060
  unitType: decision.unitType,
215
1061
  unitId: decision.unitId,
216
1062
  });
217
- await this.deps.health.postAdvanceRecord(blocked);
218
- return blocked;
1063
+ this.postAdvanceRecord(skipped);
1064
+ return skipped;
219
1065
  }
220
1066
 
221
- // Stuck-loop detection: when the ring is saturated with copies of
222
- // `nextKey` (count >= STUCK_WINDOW_SIZE), the orchestrator has been
223
- // picking the same unit across the whole window and must hard-stop with
224
- // a diagnosable reason.
225
- if (matchingCount >= STUCK_WINDOW_SIZE) {
1067
+ // Stuck-loop detection: when the window is saturated with copies of
1068
+ // `nextKey` (count >= STUCK_WINDOW_SIZE), consult the Dispatch History
1069
+ // module's full detect-stuck rule set for the verdict instead of the old
1070
+ // bare saturation count. This keeps the saturation threshold (the window
1071
+ // deliberately records benign idempotent repeats, so earlier-firing
1072
+ // rules would false-positive on pause/resume re-advances) while gaining
1073
+ // retry-budget suppression and diagnosable rule reasons. A saturated
1074
+ // window with no verdict means the dispatch ledger says we are inside
1075
+ // the unit's retry-backoff budget — let the retry proceed.
1076
+ const stuckVerdict =
1077
+ matchingCount >= STUCK_WINDOW_SIZE ? this.dispatchHistory.detectStuck() : null;
1078
+ if (stuckVerdict) {
1079
+ // #442: before declaring a stuck loop, verify the unit didn't actually
1080
+ // complete on disk (stale DB) and recover if so — legacy graduated
1081
+ // stuck-recovery parity. Otherwise hard-stop with a diagnosable reason.
1082
+ if (this.tryStuckArtifactRecovery(decision.unitType, decision.unitId)) {
1083
+ this.clearPendingDispatch();
1084
+ return this.stuckRecovered(decision, reconciliation.stateSnapshot);
1085
+ }
1086
+ this.clearPendingDispatch();
226
1087
  const blocked: AutoAdvanceResult = {
227
1088
  kind: "blocked",
228
- reason: `stuck-loop: ${nextKey} picked ${matchingCount} times`,
1089
+ reason: `stuck-loop: ${stuckVerdict.reason}`,
229
1090
  action: "stop",
230
1091
  };
231
- await this.deps.runtime.journalTransition({
1092
+ this.journalTransition({
232
1093
  name: "advance-blocked",
233
1094
  reason: blocked.reason,
234
1095
  unitType: decision.unitType,
235
1096
  unitId: decision.unitId,
236
1097
  });
237
- await this.deps.health.postAdvanceRecord(blocked);
1098
+ this.postAdvanceRecord(blocked);
238
1099
  return blocked;
239
1100
  }
240
1101
 
241
- const contract = await this.deps.toolContract.compileUnitToolContract(decision.unitType, decision.unitId);
1102
+ const contract = this.compileUnitToolContract(decision.unitType);
242
1103
  if (!contract.ok) {
1104
+ this.clearPendingDispatch();
243
1105
  const blocked: AutoAdvanceResult = {
244
1106
  kind: "blocked",
245
1107
  reason: contract.reason,
246
1108
  action: "pause",
247
1109
  stateSnapshot: reconciliation.stateSnapshot,
248
1110
  };
249
- await this.deps.runtime.journalTransition({
1111
+ this.journalTransition({
250
1112
  name: "advance-blocked",
251
1113
  reason: blocked.reason,
252
1114
  unitType: decision.unitType,
253
1115
  unitId: decision.unitId,
254
1116
  });
255
- await this.deps.health.postAdvanceRecord(blocked);
1117
+ this.postAdvanceRecord(blocked);
256
1118
  return blocked;
257
1119
  }
258
1120
 
259
- const worktree = await this.deps.worktree.prepareForUnit(decision.unitType, decision.unitId);
1121
+ const worktree = await this.prepareWorktreeForUnit(decision.unitType, decision.unitId);
260
1122
  if (!worktree.ok) {
1123
+ this.clearPendingDispatch();
261
1124
  const blocked: AutoAdvanceResult = {
262
1125
  kind: "blocked",
263
1126
  reason: worktree.reason,
264
1127
  action: "pause",
265
1128
  stateSnapshot: reconciliation.stateSnapshot,
266
1129
  };
267
- await this.deps.runtime.journalTransition({
1130
+ this.journalTransition({
268
1131
  name: "advance-blocked",
269
1132
  reason: blocked.reason,
270
1133
  unitType: decision.unitType,
271
1134
  unitId: decision.unitId,
272
1135
  });
273
- await this.deps.health.postAdvanceRecord(blocked);
1136
+ this.postAdvanceRecord(blocked);
274
1137
  return blocked;
275
1138
  }
276
1139
 
@@ -279,23 +1142,23 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
279
1142
  this.lastAdvanceKey = nextKey;
280
1143
  this.bumpTransition();
281
1144
 
282
- await this.deps.runtime.journalTransition({
1145
+ this.journalTransition({
283
1146
  name: "advance",
284
1147
  reason: decision.reason,
285
1148
  unitType: decision.unitType,
286
1149
  unitId: decision.unitId,
287
1150
  });
288
- await this.deps.worktree.syncAfterUnit(decision.unitType, decision.unitId);
1151
+ // syncAfterUnit was a no-op in the wired WorktreeAdapter.
289
1152
 
290
1153
  const advanced: AutoAdvanceResult = {
291
1154
  kind: "advanced",
292
1155
  unit: { unitType: decision.unitType, unitId: decision.unitId },
293
1156
  stateSnapshot: reconciliation.stateSnapshot,
294
1157
  };
295
- await this.deps.health.postAdvanceRecord(advanced);
1158
+ this.postAdvanceRecord(advanced);
296
1159
  return advanced;
297
1160
  } catch (error) {
298
- const recovery = await this.deps.recovery.classifyAndRecover({
1161
+ const recovery = this.classifyAndRecover({
299
1162
  error,
300
1163
  unitType: this.status.activeUnit?.unitType,
301
1164
  unitId: this.status.activeUnit?.unitId,
@@ -317,7 +1180,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
317
1180
  if (result.kind === "stopped") {
318
1181
  this.lastAdvanceKey = null;
319
1182
  this.lastFinalizedUnitKey = null;
320
- this.dispatchKeyWindow = [];
1183
+ this.dispatchHistory.clearOnRecovery();
321
1184
  this.status.activeUnit = undefined;
322
1185
  }
323
1186
  this.bumpTransition();
@@ -327,28 +1190,41 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
327
1190
  : result.kind === "stopped"
328
1191
  ? "advance-stopped"
329
1192
  : "advance-error";
330
- await this.deps.runtime.journalTransition({ name: journalName, reason: recovery.reason });
1193
+ this.journalTransition({ name: journalName, reason: recovery.reason });
331
1194
 
332
1195
  if (result.kind === "paused") {
333
- await this.deps.notifications.notifyLifecycle({ name: "pause", detail: recovery.reason });
1196
+ this.notifyLifecycle({ name: "pause", detail: recovery.reason });
334
1197
  } else if (result.kind === "stopped") {
335
- await this.deps.notifications.notifyLifecycle({ name: "stopped", detail: recovery.reason });
1198
+ this.notifyLifecycle({ name: "stopped", detail: recovery.reason });
336
1199
  } else if (result.kind === "error") {
337
- await this.deps.notifications.notifyLifecycle({ name: "error", detail: recovery.reason });
1200
+ this.notifyLifecycle({ name: "error", detail: recovery.reason });
338
1201
  }
339
- await this.deps.health.postAdvanceRecord(result);
1202
+ this.postAdvanceRecord(result);
340
1203
  return result;
1204
+ } finally {
1205
+ stopAdvanceTimer();
341
1206
  }
342
1207
  }
343
1208
 
344
1209
  public async resume(): Promise<AutoAdvanceResult> {
345
1210
  this.lastAdvanceKey = null;
346
1211
  this.lastFinalizedUnitKey = null;
347
- this.dispatchKeyWindow = [];
1212
+ // Preserve the dispatch-history window across an in-process resume so
1213
+ // stuck-loop detection accumulates across pause/resume cycles rather than
1214
+ // resetting each time (#572 regression). When the window is empty (fresh
1215
+ // orchestrator resuming a prior session), rehydrate it from the DB
1216
+ // dispatch ledger so cross-session re-dispatch loops are detected (#482).
1217
+ if (this.dispatchHistory.getRecentWindow().length === 0) {
1218
+ this.dispatchHistory.rehydrate();
1219
+ }
1220
+ this.lastStuckRecoveryKey = null;
1221
+ // ADR-030: drop the prior "from" — the first advance after resume has no
1222
+ // edge to assert (avoids a false illegal-edge across the pause boundary).
1223
+ this.lastDerivedPhase = null;
348
1224
  this.status.phase = "running";
349
1225
  this.bumpTransition();
350
- await this.deps.runtime.journalTransition({ name: "resume" });
351
- await this.deps.notifications.notifyLifecycle({ name: "resume" });
1226
+ this.journalTransition({ name: "resume" });
1227
+ this.notifyLifecycle({ name: "resume" });
352
1228
  return { kind: "resumed" };
353
1229
  }
354
1230
 
@@ -356,15 +1232,21 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
356
1232
  if (this.status.phase === "stopped") {
357
1233
  return { kind: "stopped", reason };
358
1234
  }
359
- await this.deps.worktree.cleanupOnStop(reason);
1235
+ // cleanupOnStop was a no-op in the wired WorktreeAdapter.
360
1236
  this.status.phase = "stopped";
361
1237
  this.status.activeUnit = undefined;
362
1238
  this.lastAdvanceKey = null;
363
1239
  this.lastFinalizedUnitKey = null;
364
- this.dispatchKeyWindow = [];
1240
+ this.lastDerivedPhase = null;
1241
+ // Preserve the dispatch-history window on pause so stuck-loop detection
1242
+ // accumulates across pause/resume cycles. Only clear on a hard stop.
1243
+ if (reason !== "pause") {
1244
+ this.dispatchHistory.clearOnRecovery();
1245
+ }
1246
+ this.lastStuckRecoveryKey = null;
365
1247
  this.bumpTransition();
366
- await this.deps.runtime.journalTransition({ name: "stop", reason });
367
- await this.deps.notifications.notifyLifecycle({ name: "stop", detail: reason });
1248
+ this.journalTransition({ name: "stop", reason });
1249
+ this.notifyLifecycle({ name: "stop", detail: reason });
368
1250
  return { kind: "stopped", reason };
369
1251
  }
370
1252
 
@@ -373,17 +1255,19 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
373
1255
  }
374
1256
 
375
1257
  public async completeActiveUnit(unit: { unitType: string; unitId: string }): Promise<void> {
376
- const unitKey = `${unit.unitType}:${unit.unitId}`;
1258
+ const unitKey = buildDispatchKey(unit.unitType, unit.unitId);
377
1259
  const activeUnitKey = this.status.activeUnit
378
- ? `${this.status.activeUnit.unitType}:${this.status.activeUnit.unitId}`
1260
+ ? buildDispatchKey(this.status.activeUnit.unitType, this.status.activeUnit.unitId)
379
1261
  : null;
380
1262
  if (activeUnitKey !== unitKey) return;
381
1263
 
382
1264
  this.status.activeUnit = undefined;
383
1265
  this.lastAdvanceKey = null;
384
1266
  this.lastFinalizedUnitKey = unitKey;
1267
+ // Genuine progress — re-enable graduated stuck recovery for future episodes.
1268
+ this.lastStuckRecoveryKey = null;
385
1269
  this.bumpTransition();
386
- await this.deps.runtime.journalTransition({
1270
+ this.journalTransition({
387
1271
  name: "unit-finalized",
388
1272
  unitType: unit.unitType,
389
1273
  unitId: unit.unitId,
@@ -391,9 +1275,9 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
391
1275
  }
392
1276
 
393
1277
  public async retryActiveUnit(unit: { unitType: string; unitId: string }): Promise<void> {
394
- const unitKey = `${unit.unitType}:${unit.unitId}`;
1278
+ const unitKey = buildDispatchKey(unit.unitType, unit.unitId);
395
1279
  const activeUnitKey = this.status.activeUnit
396
- ? `${this.status.activeUnit.unitType}:${this.status.activeUnit.unitId}`
1280
+ ? buildDispatchKey(this.status.activeUnit.unitType, this.status.activeUnit.unitId)
397
1281
  : null;
398
1282
  if (activeUnitKey !== unitKey && this.lastFinalizedUnitKey !== unitKey) return;
399
1283
 
@@ -403,7 +1287,7 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
403
1287
  this.lastAdvanceKey = null;
404
1288
  this.lastFinalizedUnitKey = null;
405
1289
  this.bumpTransition();
406
- await this.deps.runtime.journalTransition({
1290
+ this.journalTransition({
407
1291
  name: "unit-retry",
408
1292
  reason: "finalize-retry",
409
1293
  unitType: unit.unitType,
@@ -417,6 +1301,47 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
417
1301
  }
418
1302
  }
419
1303
 
420
- export function createAutoOrchestrator(deps: AutoOrchestratorDeps): AutoOrchestrationModule {
421
- return new AutoOrchestrator(deps);
1304
+ function isUsableLiveOrchestratorBasePath(basePath: string): boolean {
1305
+ if (!basePath || !existsSync(basePath)) return false;
1306
+ if (!detectWorktreeName(basePath)) return true;
1307
+
1308
+ try {
1309
+ return readFileSync(join(basePath, ".git"), "utf8").trim().startsWith("gitdir: ");
1310
+ } catch {
1311
+ return false;
1312
+ }
1313
+ }
1314
+
1315
+ /**
1316
+ * Resolve the base path the live orchestrator should dispatch from, falling
1317
+ * back to the project root when the captured worktree path has been removed
1318
+ * (e.g. after milestone-merge cleanup). Exported for the closeout-regression
1319
+ * tests and reused by the orchestrator's getLiveDispatchBasePath.
1320
+ */
1321
+ export function resolveLiveOrchestratorBasePath(input: {
1322
+ capturedBasePath: string;
1323
+ runtimeBasePath: string;
1324
+ sessionBasePath?: string | null;
1325
+ originalBasePath?: string | null;
1326
+ }): string {
1327
+ const primary = input.sessionBasePath || input.capturedBasePath;
1328
+ if (isUsableLiveOrchestratorBasePath(primary)) return primary;
1329
+
1330
+ const fallbacks = [
1331
+ input.originalBasePath,
1332
+ input.runtimeBasePath,
1333
+ resolveProjectRoot(input.capturedBasePath),
1334
+ ];
1335
+
1336
+ for (const candidate of fallbacks) {
1337
+ if (candidate && isUsableLiveOrchestratorBasePath(candidate)) {
1338
+ return candidate;
1339
+ }
1340
+ }
1341
+
1342
+ return input.runtimeBasePath || input.capturedBasePath;
1343
+ }
1344
+
1345
+ export function createAutoOrchestrator(context: OrchestratorContext): AutoOrchestrationModule {
1346
+ return new AutoOrchestrator(context);
422
1347
  }