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

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 (264) hide show
  1. package/dist/cli-model-override.d.ts +15 -0
  2. package/dist/cli-model-override.js +21 -0
  3. package/dist/cli.js +1 -18
  4. package/dist/loader.js +6 -4
  5. package/dist/register-agent-bundles.d.ts +11 -2
  6. package/dist/register-agent-bundles.js +18 -4
  7. package/dist/resources/.managed-resources-content-hash +1 -1
  8. package/dist/resources/extensions/ask-user-questions.js +3 -2
  9. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +447 -215
  10. package/dist/resources/extensions/claude-code-cli/turn-assembler.js +33 -1
  11. package/dist/resources/extensions/gsd/auto/closeout.js +215 -0
  12. package/dist/resources/extensions/gsd/auto/dispatch-history.js +21 -6
  13. package/dist/resources/extensions/gsd/auto/dispatch.js +365 -0
  14. package/dist/resources/extensions/gsd/auto/finalize.js +347 -0
  15. package/dist/resources/extensions/gsd/auto/loop.js +4 -1
  16. package/dist/resources/extensions/gsd/auto/milestone-lease-reclaim.js +56 -0
  17. package/dist/resources/extensions/gsd/auto/orchestrator.js +85 -15
  18. package/dist/resources/extensions/gsd/auto/phase-helpers.js +146 -0
  19. package/dist/resources/extensions/gsd/auto/phases.js +17 -2372
  20. package/dist/resources/extensions/gsd/auto/pre-dispatch.js +534 -0
  21. package/dist/resources/extensions/gsd/auto/unit-phase.js +694 -0
  22. package/dist/resources/extensions/gsd/auto/workflow-unit-dispatch.js +1 -1
  23. package/dist/resources/extensions/gsd/auto/worktree-safety-phase.js +125 -0
  24. package/dist/resources/extensions/gsd/auto-worktree.js +1 -1
  25. package/dist/resources/extensions/gsd/auto.js +15 -1
  26. package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +37 -7
  27. package/dist/resources/extensions/gsd/commands-mcp-status.js +2 -2
  28. package/dist/resources/extensions/gsd/commands-workflow-templates.js +9 -2
  29. package/dist/resources/extensions/gsd/db/queries.js +30 -0
  30. package/dist/resources/extensions/gsd/doctor-environment.js +256 -125
  31. package/dist/resources/extensions/gsd/guided-flow.js +88 -2
  32. package/dist/resources/extensions/gsd/health-widget.js +87 -28
  33. package/dist/resources/extensions/gsd/mcp-bridge.js +10 -0
  34. package/dist/resources/extensions/gsd/milestone-settlement.js +2 -2
  35. package/dist/resources/extensions/gsd/notifications.js +12 -7
  36. package/dist/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  37. package/dist/resources/extensions/gsd/prompts/execute-task.md +2 -1
  38. package/dist/resources/extensions/gsd/prompts/run-uat.md +2 -0
  39. package/dist/resources/extensions/gsd/prompts/workflow-start.md +2 -1
  40. package/dist/resources/extensions/gsd/skill-activation.js +3 -6
  41. package/dist/resources/extensions/gsd/state.js +6 -2
  42. package/dist/resources/extensions/gsd/tool-surface-readiness.js +83 -31
  43. package/dist/resources/extensions/gsd/tools/complete-task.js +62 -0
  44. package/dist/resources/extensions/gsd/unit-context-composer.js +1 -1
  45. package/dist/resources/extensions/gsd/unit-registry.js +34 -4
  46. package/dist/resources/extensions/gsd/workflow-mcp-auto-prep.js +2 -0
  47. package/dist/resources/extensions/gsd/workflow-mcp-readiness-cache.js +105 -0
  48. package/dist/resources/extensions/gsd/worktree-safety.js +28 -26
  49. package/dist/resources/extensions/mcp-client/manager.js +6 -1
  50. package/dist/runtime-checks.d.ts +10 -0
  51. package/dist/runtime-checks.js +27 -0
  52. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  53. package/dist/web/standalone/.next/BUILD_ID +1 -1
  54. package/dist/web/standalone/.next/app-path-routes-manifest.json +8 -8
  55. package/dist/web/standalone/.next/build-manifest.json +2 -2
  56. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  57. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  58. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  61. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  62. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  63. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  64. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  65. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  66. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  67. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  68. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  69. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  70. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  71. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  72. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  73. package/dist/web/standalone/.next/server/app/index.html +1 -1
  74. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  75. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  76. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  77. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  78. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  79. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  80. package/dist/web/standalone/.next/server/app-paths-manifest.json +8 -8
  81. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  82. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  83. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  84. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  85. package/package.json +2 -2
  86. package/packages/cloud-mcp-gateway/package.json +2 -2
  87. package/packages/contracts/package.json +1 -1
  88. package/packages/daemon/package.json +4 -4
  89. package/packages/gsd-agent-core/dist/sdk.d.ts.map +1 -1
  90. package/packages/gsd-agent-core/dist/sdk.js +6 -4
  91. package/packages/gsd-agent-core/dist/sdk.js.map +1 -1
  92. package/packages/gsd-agent-core/package.json +5 -5
  93. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts +2 -0
  94. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  95. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js +10 -0
  96. package/packages/gsd-agent-modes/dist/modes/interactive/components/settings-selector.js.map +1 -1
  97. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts +8 -0
  98. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  99. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js +50 -6
  100. package/packages/gsd-agent-modes/dist/modes/interactive/components/tool-execution.js.map +1 -1
  101. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts +2 -0
  102. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
  103. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +34 -5
  104. package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
  105. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts +1 -0
  106. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  107. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js +12 -0
  108. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-mode.js.map +1 -1
  109. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.d.ts.map +1 -1
  110. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js +4 -0
  111. package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-settings.js.map +1 -1
  112. package/packages/gsd-agent-modes/package.json +7 -7
  113. package/packages/mcp-server/README.md +12 -3
  114. package/packages/mcp-server/dist/cli-runner.d.ts +40 -0
  115. package/packages/mcp-server/dist/cli-runner.d.ts.map +1 -0
  116. package/packages/mcp-server/dist/cli-runner.js +137 -0
  117. package/packages/mcp-server/dist/cli-runner.js.map +1 -0
  118. package/packages/mcp-server/dist/cli.js +2 -58
  119. package/packages/mcp-server/dist/cli.js.map +1 -1
  120. package/packages/mcp-server/dist/pid-registry.d.ts +46 -0
  121. package/packages/mcp-server/dist/pid-registry.d.ts.map +1 -0
  122. package/packages/mcp-server/dist/pid-registry.js +452 -0
  123. package/packages/mcp-server/dist/pid-registry.js.map +1 -0
  124. package/packages/mcp-server/dist/probe-mode.d.ts +4 -0
  125. package/packages/mcp-server/dist/probe-mode.d.ts.map +1 -0
  126. package/packages/mcp-server/dist/probe-mode.js +10 -0
  127. package/packages/mcp-server/dist/probe-mode.js.map +1 -0
  128. package/packages/mcp-server/dist/stdio-watchdog.d.ts +8 -0
  129. package/packages/mcp-server/dist/stdio-watchdog.d.ts.map +1 -0
  130. package/packages/mcp-server/dist/stdio-watchdog.js +40 -0
  131. package/packages/mcp-server/dist/stdio-watchdog.js.map +1 -0
  132. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  133. package/packages/mcp-server/dist/workflow-tools.js +62 -43
  134. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  135. package/packages/mcp-server/package.json +5 -5
  136. package/packages/native/package.json +1 -1
  137. package/packages/pi-agent-core/dist/agent-loop.js +43 -2
  138. package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
  139. package/packages/pi-agent-core/package.json +1 -1
  140. package/packages/pi-ai/package.json +1 -1
  141. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +3 -0
  142. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  143. package/packages/pi-coding-agent/dist/core/settings-manager.js +11 -0
  144. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  145. package/packages/pi-coding-agent/dist/theme/theme.d.ts.map +1 -1
  146. package/packages/pi-coding-agent/dist/theme/theme.js +45 -17
  147. package/packages/pi-coding-agent/dist/theme/theme.js.map +1 -1
  148. package/packages/pi-coding-agent/package.json +7 -7
  149. package/packages/pi-tui/dist/index.d.ts +1 -1
  150. package/packages/pi-tui/dist/index.d.ts.map +1 -1
  151. package/packages/pi-tui/dist/index.js +1 -1
  152. package/packages/pi-tui/dist/index.js.map +1 -1
  153. package/packages/pi-tui/dist/terminal-image.d.ts +33 -0
  154. package/packages/pi-tui/dist/terminal-image.d.ts.map +1 -1
  155. package/packages/pi-tui/dist/terminal-image.js +54 -2
  156. package/packages/pi-tui/dist/terminal-image.js.map +1 -1
  157. package/packages/pi-tui/dist/tui.d.ts +8 -0
  158. package/packages/pi-tui/dist/tui.d.ts.map +1 -1
  159. package/packages/pi-tui/dist/tui.js +63 -18
  160. package/packages/pi-tui/dist/tui.js.map +1 -1
  161. package/packages/pi-tui/dist/utils.d.ts.map +1 -1
  162. package/packages/pi-tui/dist/utils.js +110 -36
  163. package/packages/pi-tui/dist/utils.js.map +1 -1
  164. package/packages/pi-tui/package.json +2 -2
  165. package/packages/rpc-client/package.json +2 -2
  166. package/pkg/dist/theme/theme.d.ts.map +1 -1
  167. package/pkg/dist/theme/theme.js +45 -17
  168. package/pkg/dist/theme/theme.js.map +1 -1
  169. package/pkg/package.json +1 -1
  170. package/src/resources/extensions/ask-user-questions.ts +7 -2
  171. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +531 -226
  172. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +672 -7
  173. package/src/resources/extensions/claude-code-cli/turn-assembler.ts +38 -1
  174. package/src/resources/extensions/gsd/auto/closeout.ts +309 -0
  175. package/src/resources/extensions/gsd/auto/dispatch-history.ts +22 -6
  176. package/src/resources/extensions/gsd/auto/dispatch.ts +449 -0
  177. package/src/resources/extensions/gsd/auto/finalize.ts +445 -0
  178. package/src/resources/extensions/gsd/auto/loop.ts +4 -1
  179. package/src/resources/extensions/gsd/auto/milestone-lease-reclaim.ts +74 -0
  180. package/src/resources/extensions/gsd/auto/orchestrator.ts +95 -15
  181. package/src/resources/extensions/gsd/auto/phase-helpers.ts +199 -0
  182. package/src/resources/extensions/gsd/auto/phases.ts +58 -3061
  183. package/src/resources/extensions/gsd/auto/pre-dispatch.ts +704 -0
  184. package/src/resources/extensions/gsd/auto/unit-phase.ts +910 -0
  185. package/src/resources/extensions/gsd/auto/workflow-unit-dispatch.ts +1 -1
  186. package/src/resources/extensions/gsd/auto/worktree-safety-phase.ts +149 -0
  187. package/src/resources/extensions/gsd/auto-worktree.ts +1 -1
  188. package/src/resources/extensions/gsd/auto.ts +20 -1
  189. package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +56 -6
  190. package/src/resources/extensions/gsd/commands-mcp-status.ts +2 -2
  191. package/src/resources/extensions/gsd/commands-workflow-templates.ts +11 -4
  192. package/src/resources/extensions/gsd/db/queries.ts +29 -0
  193. package/src/resources/extensions/gsd/doctor-environment.ts +267 -142
  194. package/src/resources/extensions/gsd/guided-flow.ts +128 -2
  195. package/src/resources/extensions/gsd/health-widget.ts +91 -27
  196. package/src/resources/extensions/gsd/mcp-bridge.ts +39 -0
  197. package/src/resources/extensions/gsd/milestone-settlement.ts +2 -2
  198. package/src/resources/extensions/gsd/notifications.ts +13 -6
  199. package/src/resources/extensions/gsd/prompts/complete-slice.md +1 -1
  200. package/src/resources/extensions/gsd/prompts/execute-task.md +2 -1
  201. package/src/resources/extensions/gsd/prompts/run-uat.md +2 -0
  202. package/src/resources/extensions/gsd/prompts/workflow-start.md +2 -1
  203. package/src/resources/extensions/gsd/skill-activation.ts +3 -6
  204. package/src/resources/extensions/gsd/state.ts +7 -1
  205. package/src/resources/extensions/gsd/tests/auto-abort-pause-regression.test.ts +1 -1
  206. package/src/resources/extensions/gsd/tests/auto-blocked-remediation-message.test.ts +1 -1
  207. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +206 -22
  208. package/src/resources/extensions/gsd/tests/auto-orchestrator.test.ts +76 -12
  209. package/src/resources/extensions/gsd/tests/auto-pause-double-entry-guard.test.ts +1 -1
  210. package/src/resources/extensions/gsd/tests/auto-paused-ui-cleanup.test.ts +77 -1
  211. package/src/resources/extensions/gsd/tests/auto-phases-lifecycle.test.ts +2 -1
  212. package/src/resources/extensions/gsd/tests/auto-unit-closeout.test.ts +169 -1
  213. package/src/resources/extensions/gsd/tests/complete-task.test.ts +141 -5
  214. package/src/resources/extensions/gsd/tests/deep-project-auto-loop.test.ts +2 -1
  215. package/src/resources/extensions/gsd/tests/derive-state-helpers.test.ts +36 -0
  216. package/src/resources/extensions/gsd/tests/dispatch-history.test.ts +55 -0
  217. package/src/resources/extensions/gsd/tests/dist-redirect.mjs +8 -0
  218. package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +117 -91
  219. package/src/resources/extensions/gsd/tests/ensure-db-open.test.ts +113 -0
  220. package/src/resources/extensions/gsd/tests/guided-dispatch-root.test.ts +16 -0
  221. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +15 -0
  222. package/src/resources/extensions/gsd/tests/integration/doctor-environment-async.test.ts +104 -0
  223. package/src/resources/extensions/gsd/tests/integration/run-uat.test.ts +18 -0
  224. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +47 -16
  225. package/src/resources/extensions/gsd/tests/mcp-readiness-preflight.test.ts +205 -0
  226. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +6 -5
  227. package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +1 -1
  228. package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +1 -1
  229. package/src/resources/extensions/gsd/tests/milestone-settlement.test.ts +92 -0
  230. package/src/resources/extensions/gsd/tests/milestone-transition-state-rebuild.test.ts +1 -1
  231. package/src/resources/extensions/gsd/tests/notifications.test.ts +64 -9
  232. package/src/resources/extensions/gsd/tests/parallel-skill-prompt-integration.test.ts +2 -2
  233. package/src/resources/extensions/gsd/tests/parsers-legacy-importers.test.ts +5 -0
  234. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +1 -1
  235. package/src/resources/extensions/gsd/tests/phases-terminal-complete-idempotent.test.ts +1 -1
  236. package/src/resources/extensions/gsd/tests/plan-gate-failed-doctor-heal-hint.test.ts +3 -3
  237. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +10 -2
  238. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +2 -4
  239. package/src/resources/extensions/gsd/tests/remote-notification-from-desktop.test.ts +31 -81
  240. package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +7 -1
  241. package/src/resources/extensions/gsd/tests/skill-activation.test.ts +20 -17
  242. package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +7 -3
  243. package/src/resources/extensions/gsd/tests/stop-auto-race-null-unit.test.ts +1 -1
  244. package/src/resources/extensions/gsd/tests/token-tool-gating.test.ts +4 -2
  245. package/src/resources/extensions/gsd/tests/tool-surface-readiness.test.ts +184 -10
  246. package/src/resources/extensions/gsd/tests/uok-plan-v2-wiring.test.ts +1 -1
  247. package/src/resources/extensions/gsd/tests/workflow-mcp-readiness-cache.test.ts +119 -0
  248. package/src/resources/extensions/gsd/tests/workflow-mcp.test.ts +65 -2
  249. package/src/resources/extensions/gsd/tests/workflow-phase-contract-matrix.test.ts +332 -0
  250. package/src/resources/extensions/gsd/tests/workflow-templates.test.ts +92 -0
  251. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +1 -1
  252. package/src/resources/extensions/gsd/tests/worktree-project-root-degrade.test.ts +1 -1
  253. package/src/resources/extensions/gsd/tests/worktree-safety-phase.test.ts +100 -0
  254. package/src/resources/extensions/gsd/tests/worktree-safety.test.ts +72 -0
  255. package/src/resources/extensions/gsd/tool-surface-readiness.ts +126 -19
  256. package/src/resources/extensions/gsd/tools/complete-task.ts +87 -0
  257. package/src/resources/extensions/gsd/unit-context-composer.ts +1 -1
  258. package/src/resources/extensions/gsd/unit-registry.ts +34 -4
  259. package/src/resources/extensions/gsd/workflow-mcp-auto-prep.ts +2 -0
  260. package/src/resources/extensions/gsd/workflow-mcp-readiness-cache.ts +150 -0
  261. package/src/resources/extensions/gsd/worktree-safety.ts +41 -39
  262. package/src/resources/extensions/mcp-client/manager.ts +7 -1
  263. /package/dist/web/standalone/.next/static/{FBNo5cT_chy7YNoAQsU3o → xyMkEaICFHJoa98VgJyzY}/_buildManifest.js +0 -0
  264. /package/dist/web/standalone/.next/static/{FBNo5cT_chy7YNoAQsU3o → xyMkEaICFHJoa98VgJyzY}/_ssgManifest.js +0 -0
@@ -74,6 +74,7 @@ import {
74
74
  import { existsSync, readFileSync } from "node:fs";
75
75
  import { join } from "node:path";
76
76
  import { evaluateAllCompleteSettlement } from "../milestone-settlement.js";
77
+ import { hasHeldMilestoneLease, reclaimMissingMilestoneLease } from "./milestone-lease-reclaim.js";
77
78
 
78
79
  function now(): number {
79
80
  return Date.now();
@@ -209,6 +210,7 @@ export async function decideOrchestratorDispatch(
209
210
 
210
211
  if (active && activeSession && shouldAdoptActiveMilestone(state, activeSession, activeDispatchBasePath)) {
211
212
  activeSession.currentMilestoneId = active.id;
213
+ activeSession.milestoneLeaseToken = null;
212
214
  }
213
215
  const dispatchMid = active?.id ?? activeSession?.currentMilestoneId ?? "";
214
216
  const dispatchMidTitle = active?.title ?? "";
@@ -609,6 +611,37 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
609
611
  };
610
612
  }
611
613
 
614
+ private async mergePendingCompleteMilestone(milestoneId: string): Promise<{ ok: true } | { ok: false; reason: string }> {
615
+ const result = this.buildLifecycle().exitMilestone(
616
+ milestoneId,
617
+ { merge: true },
618
+ this.ctx.ui,
619
+ );
620
+ if (!result.ok) {
621
+ const detail = result.cause instanceof Error
622
+ ? result.cause.message
623
+ : result.reason;
624
+ return {
625
+ ok: false,
626
+ reason: `Milestone ${milestoneId} is complete, but the system-owned merge failed: ${detail}`,
627
+ };
628
+ }
629
+
630
+ this.s.milestoneMergedInPhases = true;
631
+ this.s.milestoneSettlement = { ok: true, reason: "settled" };
632
+ try {
633
+ const projectRoot = this.s.originalBasePath || this.s.canonicalProjectRoot || this.runtimeBasePath;
634
+ const { rebuildMarkdownProjectionsFromDb } = await import("../commands-maintenance.js");
635
+ await rebuildMarkdownProjectionsFromDb(projectRoot);
636
+ } catch (err) {
637
+ logWarning(
638
+ "engine",
639
+ `markdown projection rebuild after settlement merge failed: ${err instanceof Error ? err.message : String(err)}`,
640
+ );
641
+ }
642
+ return { ok: true };
643
+ }
644
+
612
645
  private clearPendingDispatch(): void {
613
646
  this.s.pendingOrchestrationDispatch = null;
614
647
  }
@@ -688,9 +721,6 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
688
721
  reason: `No Unit manifest is registered for ${unitType}`,
689
722
  };
690
723
  }
691
- if (isolationMode !== "worktree") {
692
- return { ok: true, reason: "not-required" };
693
- }
694
724
  const writeScope =
695
725
  manifest.tools.mode === "all" || manifest.tools.mode === "docs"
696
726
  ? "source-writing"
@@ -699,7 +729,23 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
699
729
  const activeBasePath = this.getLiveDispatchBasePath();
700
730
  const snapshot = await deriveState(activeBasePath);
701
731
  const milestoneId = snapshot.activeMilestone?.id ?? null;
702
- const expectedBranch = milestoneId ? autoWorktreeBranch(milestoneId) : null;
732
+ const buildExpectedBranch = (mode: ReturnType<typeof getIsolationMode>) =>
733
+ mode !== "none" && milestoneId ? autoWorktreeBranch(milestoneId) : null;
734
+ // The milestone lease coordinates concurrent workers on an isolated
735
+ // milestone worktree/branch. `none` mode has no per-milestone isolation
736
+ // and does not reliably claim a lease, so requiring one there would
737
+ // falsely fail dispatch; enforce it only in isolated modes.
738
+ const buildLease = (mode: ReturnType<typeof getIsolationMode>) =>
739
+ milestoneId && this.s.workerId
740
+ ? {
741
+ required: writeScope === "source-writing" && mode !== "none",
742
+ held: hasHeldMilestoneLease(this.s, milestoneId),
743
+ owner: this.s.workerId,
744
+ }
745
+ : undefined;
746
+ if (writeScope === "source-writing") {
747
+ reclaimMissingMilestoneLease(this.s, milestoneId, isolationMode, "orchestrator");
748
+ }
703
749
  let result = safety.validateUnitRoot({
704
750
  unitType,
705
751
  unitId,
@@ -708,7 +754,8 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
708
754
  unitRoot: activeBasePath,
709
755
  milestoneId,
710
756
  isolationMode,
711
- expectedBranch,
757
+ expectedBranch: buildExpectedBranch(isolationMode),
758
+ lease: buildLease(isolationMode),
712
759
  });
713
760
  if (!result.ok) {
714
761
  const repaired = await repairAutoWorktreeSafetyFailure({
@@ -725,16 +772,20 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
725
772
  this.rebuildScope(this.s.basePath, this.s.currentMilestoneId);
726
773
  return { ok: true };
727
774
  },
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
- }),
775
+ revalidate: () => {
776
+ const revalidatedMode = this.getEffectiveUnitIsolationMode(this.runtimeBasePath);
777
+ return safety.validateUnitRoot({
778
+ unitType,
779
+ unitId,
780
+ writeScope,
781
+ projectRoot: this.runtimeBasePath,
782
+ unitRoot: this.getLiveDispatchBasePath(),
783
+ milestoneId,
784
+ isolationMode: revalidatedMode,
785
+ expectedBranch: buildExpectedBranch(revalidatedMode),
786
+ lease: buildLease(revalidatedMode),
787
+ });
788
+ },
738
789
  });
739
790
  result = repaired.result;
740
791
  if (result.ok) {
@@ -942,6 +993,35 @@ export class AutoOrchestrator implements AutoOrchestrationModule {
942
993
  if (!decision) {
943
994
  const settlementBlock = this.evaluateNoRemainingUnitsSettlement(reconciliation.stateSnapshot);
944
995
  if (settlementBlock) {
996
+ const settlement = this.s.milestoneSettlement;
997
+ if (settlement && !settlement.ok && settlement.reason === "merge-pending") {
998
+ const merged = await this.mergePendingCompleteMilestone(settlement.milestoneId);
999
+ if (merged.ok) {
1000
+ const terminalOutcome = noRemainingUnitsOutcome(reconciliation.stateSnapshot);
1001
+ const stopped: AutoAdvanceResult = {
1002
+ kind: "stopped",
1003
+ reason: terminalOutcome.displayReason,
1004
+ stateSnapshot: reconciliation.stateSnapshot,
1005
+ terminalOutcome,
1006
+ };
1007
+ this.status.phase = "stopped";
1008
+ this.status.activeUnit = undefined;
1009
+ this.lastAdvanceKey = null;
1010
+ this.dispatchHistory.clearOnRecovery();
1011
+ this.bumpTransition();
1012
+ this.journalTransition({ name: "advance-stopped", reason: stopped.reason });
1013
+ this.postAdvanceRecord(stopped);
1014
+ return stopped;
1015
+ }
1016
+ settlementBlock.reason = merged.reason;
1017
+ settlementBlock.terminalOutcome = {
1018
+ code: "settlement-blocked",
1019
+ displayReason: merged.reason,
1020
+ nextAction: `Fix the merge failure, then retry \`/gsd dispatch complete-milestone ${settlement.milestoneId}\`.`,
1021
+ milestoneId: settlement.milestoneId,
1022
+ allMilestonesComplete: false,
1023
+ };
1024
+ }
945
1025
  this.status.phase = "paused";
946
1026
  this.status.activeUnit = undefined;
947
1027
  this.lastAdvanceKey = null;
@@ -0,0 +1,199 @@
1
+ // Project/App: gsd-pi
2
+ // File Purpose: Shared helpers used across auto-loop phase modules.
3
+
4
+ import { setRuntimeKv } from "../db/runtime-kv.js";
5
+ import { debugLog } from "../debug-logger.js";
6
+ import { normalizeRealPath } from "../paths.js";
7
+ import { resolveWorktreeProjectRoot, normalizeWorktreePathForCompare } from "../worktree-root.js";
8
+ import { decideVerificationRetry, verificationRetryKey } from "./verification-retry-policy.js";
9
+ import type { AutoSession } from "./session.js";
10
+ import type { IterationContext, IterationData, LoopState, PhaseResult } from "./types.js";
11
+ import type { Phase } from "../types.js";
12
+
13
+ const STUCK_RECOVERY_ATTEMPTS_KEY = "stuck_recovery_attempts";
14
+
15
+ /** Compare two paths for physical identity, tolerating trailing slashes and symlinks. */
16
+ export function isSamePathLocal(a: string, b: string): boolean {
17
+ return normalizeWorktreePathForCompare(a) === normalizeWorktreePathForCompare(b);
18
+ }
19
+
20
+ export function isIsolatedWorktreeSession(s: AutoSession): boolean {
21
+ return Boolean(s.originalBasePath)
22
+ && Boolean(s.basePath)
23
+ && !isSamePathLocal(s.originalBasePath, s.basePath);
24
+ }
25
+
26
+ export function persistStuckRecoveryAttempts(s: AutoSession, loopState: LoopState): void {
27
+ const scopeId = normalizeRealPath(
28
+ s.scope?.workspace.projectRoot ?? (s.originalBasePath || s.basePath),
29
+ );
30
+ if (!scopeId) return;
31
+ try {
32
+ setRuntimeKv("global", scopeId, STUCK_RECOVERY_ATTEMPTS_KEY, loopState.stuckRecoveryAttempts);
33
+ } catch (err) {
34
+ debugLog("autoLoop", {
35
+ phase: "save-stuck-state-failed",
36
+ error: err instanceof Error ? err.message : String(err),
37
+ });
38
+ }
39
+ }
40
+
41
+ export async function applyVerificationRetryPolicy(
42
+ ic: IterationContext,
43
+ unitType: string | undefined,
44
+ phase: "artifact-verification-retry" | "verification-retry" | "pre-execution-retry",
45
+ ): Promise<PhaseResult | null> {
46
+ const { ctx, pi, s, deps } = ic;
47
+ const retryInfo = s.pendingVerificationRetry;
48
+ const key = unitType && retryInfo
49
+ ? verificationRetryKey(unitType, retryInfo.unitId)
50
+ : undefined;
51
+ const decision = decideVerificationRetry({
52
+ unitType,
53
+ retryInfo,
54
+ previousFailureHash: key ? s.verificationRetryFailureHashes.get(key) : undefined,
55
+ });
56
+
57
+ if (decision.action === "pause") {
58
+ s.pendingVerificationRetry = null;
59
+ debugLog("autoLoop", {
60
+ phase: `${phase}-paused`,
61
+ reason: decision.reason,
62
+ unitType,
63
+ unitId: retryInfo?.unitId,
64
+ failureHash: decision.failureHash,
65
+ });
66
+ ctx.ui.notify(
67
+ decision.reason === "duplicate-failure-context"
68
+ ? `Verification retry for ${unitType ?? "unit"} ${retryInfo?.unitId ?? "unknown"} produced the same failure context. Pausing auto-mode instead of re-dispatching.`
69
+ : "Verification retry requested without retry context. Pausing auto-mode instead of re-dispatching.",
70
+ "warning",
71
+ );
72
+ await deps.pauseAuto(ctx, pi);
73
+ return { action: "break", reason: decision.reason };
74
+ }
75
+
76
+ s.verificationRetryFailureHashes.set(decision.key, decision.failureHash);
77
+ debugLog("autoLoop", {
78
+ phase: `${phase}-backoff`,
79
+ iteration: ic.iteration,
80
+ unitType,
81
+ unitId: retryInfo?.unitId,
82
+ attempt: retryInfo?.attempt,
83
+ delayMs: decision.delayMs,
84
+ baseDelayMs: decision.baseDelayMs,
85
+ failureHash: decision.failureHash,
86
+ });
87
+ await new Promise<void>((resolve) => setTimeout(resolve, decision.delayMs));
88
+ return null;
89
+ }
90
+
91
+ export function rememberRetryDispatch(
92
+ s: AutoSession,
93
+ unit: { type: string; id: string } | null,
94
+ iterData: IterationData,
95
+ ): void {
96
+ if (!unit) return;
97
+ s.pendingVerificationRetryDispatch = {
98
+ unitType: unit.type,
99
+ unitId: unit.id,
100
+ prompt: iterData.prompt,
101
+ pauseAfterUatDispatch: iterData.pauseAfterUatDispatch,
102
+ state: iterData.state,
103
+ mid: iterData.mid,
104
+ midTitle: iterData.midTitle,
105
+ };
106
+ }
107
+
108
+ /**
109
+ * Resolve the base path for milestone reports.
110
+ * Prefers originalBasePath (project root) over basePath (which may be a worktree).
111
+ */
112
+ export function _resolveReportBasePath(s: Pick<AutoSession, "originalBasePath" | "basePath">): string {
113
+ return resolveWorktreeProjectRoot(s.basePath, s.originalBasePath);
114
+ }
115
+
116
+ /**
117
+ * Resolve the authoritative project base for dispatch guards.
118
+ * Prior-milestone completion lives at the project root, even when the active
119
+ * unit is running inside an auto worktree.
120
+ */
121
+ export function _resolveDispatchGuardBasePath(
122
+ s: Pick<AutoSession, "originalBasePath" | "basePath">,
123
+ ): string {
124
+ return resolveWorktreeProjectRoot(s.basePath, s.originalBasePath);
125
+ }
126
+
127
+ const PLAN_V2_GATE_PHASES: ReadonlySet<Phase> = new Set([
128
+ "executing",
129
+ "summarizing",
130
+ "validating-milestone",
131
+ "completing-milestone",
132
+ ]);
133
+
134
+ export function shouldRunPlanV2Gate(phase: Phase): boolean {
135
+ return PLAN_V2_GATE_PHASES.has(phase);
136
+ }
137
+
138
+ export function _resolveCurrentUnitStartedAtForTest(
139
+ currentUnit: { startedAt: number } | null | undefined,
140
+ ): number | undefined {
141
+ return currentUnit?.startedAt;
142
+ }
143
+
144
+ export async function emitCancelledUnitEnd(
145
+ ic: IterationContext,
146
+ unitType: string,
147
+ unitId: string,
148
+ unitStartSeq: number,
149
+ errorContext?: { message: string; category: string; stopReason?: string; isTransient?: boolean; retryAfterMs?: number },
150
+ ): Promise<void> {
151
+ ic.deps.emitJournalEvent({
152
+ ts: new Date().toISOString(),
153
+ flowId: ic.flowId,
154
+ seq: ic.nextSeq(),
155
+ eventType: "unit-end",
156
+ data: {
157
+ unitType,
158
+ unitId,
159
+ status: "cancelled",
160
+ artifactVerified: false,
161
+ ...(errorContext ? { errorContext } : {}),
162
+ },
163
+ causedBy: { flowId: ic.flowId, seq: unitStartSeq },
164
+ });
165
+ }
166
+
167
+ export function _buildCancelledUnitStopReason(
168
+ unitType: string,
169
+ unitId: string,
170
+ errorContext?: { message: string; category: string },
171
+ ): {
172
+ notifyMessage: string;
173
+ stopReason: string;
174
+ loopReason: "session-failed" | "unit-aborted";
175
+ } {
176
+ const cancellationMessage = errorContext?.message ?? "unknown";
177
+ const isSessionCreationFailure = errorContext?.category === "session-failed";
178
+
179
+ if (isSessionCreationFailure) {
180
+ return {
181
+ notifyMessage: `Session creation failed for ${unitType} ${unitId}: ${cancellationMessage}. Stopping auto-mode.`,
182
+ stopReason: `Session creation failed: ${cancellationMessage}`,
183
+ loopReason: "session-failed",
184
+ };
185
+ }
186
+
187
+ return {
188
+ notifyMessage: `Unit ${unitType} ${unitId} aborted after dispatch: ${cancellationMessage}. Stopping auto-mode.`,
189
+ stopReason: `Unit aborted: ${cancellationMessage}`,
190
+ loopReason: "unit-aborted",
191
+ };
192
+ }
193
+
194
+ export function _isPauseOriginCancelledResult(
195
+ isPaused: boolean,
196
+ errorContext?: { message: string; category: string },
197
+ ): boolean {
198
+ return isPaused && !errorContext;
199
+ }