@humwick/server 0.130.2 → 0.130.3

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 (570) hide show
  1. package/bundled/prompts/manifest.json +1 -0
  2. package/bundled/prompts/task.hydration.md +1 -1
  3. package/bundled/roles/builder.md +1 -1
  4. package/docs/guides/sub-coordinators.md +12 -5
  5. package/docs/guides/tools-coordination.md +1 -0
  6. package/docs/guides/workflows.md +16 -0
  7. package/docs/openapi.json +73 -4
  8. package/package.json +8 -7
  9. package/public/assets/{MessageBubble-BWLqMGKG.js → MessageBubble-Bq9kr21N.js} +2 -2
  10. package/public/assets/{PlanGraphPanel-3TlIQpjk.js → PlanGraphPanel-Dqiroy06.js} +2 -2
  11. package/public/assets/{TraceView-Wimm0Czv.js → TraceView-DYU962-H.js} +2 -2
  12. package/public/assets/{VaultDecisionCard-Bau_vNax.js → VaultDecisionCard-DhPfzioE.js} +2 -2
  13. package/public/assets/{activity-CrSurn-r.js → activity-DzCcQTee.js} +2 -2
  14. package/public/assets/{agent-lineage-CknAJKcb.js → agent-lineage-SgDt9i3T.js} +2 -2
  15. package/public/assets/agent-liveness-Bq-s73jW.js +2 -0
  16. package/public/assets/{agent-name-DKbiIhBo.js → agent-name-CcY3Aijy.js} +2 -2
  17. package/public/assets/{agent-profiles-DwF6EQ4R.js → agent-profiles-cxtRBn6O.js} +2 -2
  18. package/public/assets/{agent-project-badge-Diz4Sjjb.js → agent-project-badge-DGYbIhaI.js} +2 -2
  19. package/public/assets/{agent-tools-CRhpRQza.js → agent-tools-DHbftV0N.js} +2 -2
  20. package/public/assets/{agent-type-icon-LrUEU3lB.js → agent-type-icon-CY113sp-.js} +2 -2
  21. package/public/assets/{agents-B-v66C-4.js → agents-BPzY7IlQ.js} +2 -2
  22. package/public/assets/{analytics-BqCb-LKi.js → analytics-DENFPv_a.js} +2 -2
  23. package/public/assets/{artifact-viewer-kf4pGuAR.js → artifact-viewer-KRvSc7sl.js} +2 -2
  24. package/public/assets/{artifacts-DJevXcvg.js → artifacts-C9gSmL3s.js} +2 -2
  25. package/public/assets/{artifacts-D32zyw4Y.js → artifacts-DT-HkI5O.js} +2 -2
  26. package/public/assets/{automation-BpRajx_5.js → automation-BsmjQhKD.js} +2 -2
  27. package/public/assets/{backlog-D_UjTdzX.js → backlog-8NYH_62t.js} +2 -2
  28. package/public/assets/{busy-health-N3VEh4ao.js → busy-health-D3hwvYb4.js} +2 -2
  29. package/public/assets/{channels-9jopungq.js → channels-DCJ5WL7O.js} +2 -2
  30. package/public/assets/{chat-CSXrTB3C.js → chat-DAIl357U.js} +3 -3
  31. package/public/assets/{code-preview-p1NnmqK0.js → code-preview-CzrZfr9U.js} +2 -2
  32. package/public/assets/{connectors-CZdqlDNL.js → connectors-xTxtlyou.js} +2 -2
  33. package/public/assets/{cosmos-BgdsE4dG.js → cosmos-BpebFLK2.js} +2 -2
  34. package/public/assets/{crate-agent-30aXTKva.js → crate-agent-BHvI5wXC.js} +2 -2
  35. package/public/assets/{dependency-graph-B_jvw2GE.js → dependency-graph-DGT0o3wJ.js} +2 -2
  36. package/public/assets/{deploys-DoN6bAb5.js → deploys-hqWOHSHE.js} +2 -2
  37. package/public/assets/{display-BrKWFGJz.js → display-CDeH4I8T.js} +2 -2
  38. package/public/assets/{files-D6XEu8Ng.js → files-BTeGVmTg.js} +2 -2
  39. package/public/assets/{fleet-C7jQWbw2.js → fleet-DgXtNgCa.js} +2 -2
  40. package/public/assets/{fleet-metrics-BiDs3MLx.js → fleet-metrics-BHEt5yc_.js} +2 -2
  41. package/public/assets/{formatted-body-CQBwc1fb.js → formatted-body-MLtodyPp.js} +3 -3
  42. package/public/assets/{formatted-body-impl-DyG0WsQS.js → formatted-body-impl-CAe664Z8.js} +2 -2
  43. package/public/assets/{host-providers-dialog-DKaW31dN.js → host-providers-dialog-mapF4Fj9.js} +2 -2
  44. package/public/assets/{index-CRHep3M9.js → index-CqqgOI5R.js} +5 -5
  45. package/public/assets/{insights-CzrtkpOE.js → insights-DNyf7IzF.js} +2 -2
  46. package/public/assets/{integrations-aVsUmigt.js → integrations-DlYOHq7T.js} +2 -2
  47. package/public/assets/{issue-ref-chip-BnSlM_95.js → issue-ref-chip-CeWBNWn7.js} +2 -2
  48. package/public/assets/{log-viewer-qe7Ee47Z.js → log-viewer-Cib8nqdE.js} +2 -2
  49. package/public/assets/{maintenance-NfjqFZAk.js → maintenance-DSn1cPm7.js} +2 -2
  50. package/public/assets/{managed-agents-BiH0HgaE.js → managed-agents-C3CkM81m.js} +2 -2
  51. package/public/assets/{markdown-preview-BixaT3Xr.js → markdown-preview-W4VQQPAv.js} +3 -3
  52. package/public/assets/{markdown-preview-impl-DNGlWIS3.js → markdown-preview-impl-CMsTdhjq.js} +2 -2
  53. package/public/assets/{memory-DNsCl6UX.js → memory-BV17qtO4.js} +2 -2
  54. package/public/assets/{messages-DopU1L1X.js → messages-Bm_1AqSA.js} +2 -2
  55. package/public/assets/{orchestrators-Cq7ckLQT.js → orchestrators-Dg-vfP09.js} +2 -2
  56. package/public/assets/{overview-C1DCTzzV.js → overview-DcYCrvlr.js} +2 -2
  57. package/public/assets/{pairs-DE_m6rrE.js → pairs-8o9nuG3V.js} +2 -2
  58. package/public/assets/{profile-icon-B3rfh77F.js → profile-icon-BsRyBMea.js} +2 -2
  59. package/public/assets/{project-profile-instructions-DQWZE0kA.js → project-profile-instructions-DETKFn_E.js} +2 -2
  60. package/public/assets/{projects-Br2Bd2h1.js → projects-M_m6AHws.js} +2 -2
  61. package/public/assets/{prompt-settings-BKvFsvGD.js → prompt-settings-C_mNCgeL.js} +2 -2
  62. package/public/assets/provider-display-BEeLXC_D.js +2 -0
  63. package/public/assets/{registry-Cw38_6gW.js → registry-DDHHHE5N.js} +2 -2
  64. package/public/assets/run-card-Dt4I4jaP.js +2 -0
  65. package/public/assets/{secrets-DxI-vzSq.js → secrets-BkVwxI5O.js} +2 -2
  66. package/public/assets/{service-access-settings-D9s_VJbd.js → service-access-settings-Crq-6a-B.js} +2 -2
  67. package/public/assets/{settings-CKZTVGIx.js → settings-CYcavMFu.js} +2 -2
  68. package/public/assets/shipping-H6gzEeZB.js +2 -0
  69. package/public/assets/{stats-DyUBKyWI.js → stats-BJVeWkpV.js} +2 -2
  70. package/public/assets/{status-dot-DYqlEUhJ.js → status-dot-BcHyw1Vw.js} +2 -2
  71. package/public/assets/store-DKPDIZBe.js +9 -0
  72. package/public/assets/{tasks-Bh7Chr4-.js → tasks-qJjlQPpx.js} +2 -2
  73. package/public/assets/{teams-bowI7qVY.js → teams-Cd5Sk1uX.js} +2 -2
  74. package/public/assets/{terminal-viewer-BgVLHdsU.js → terminal-viewer-CpY5_m7W.js} +3 -3
  75. package/public/assets/{terminal-viewer-impl-Dz22UPy6.js → terminal-viewer-impl-DI_2llFR.js} +2 -2
  76. package/public/assets/{use-agent-terminal-DSQQ-iY7.js → use-agent-terminal-0yJA_buM.js} +2 -2
  77. package/public/assets/{use-decisions-samMQhQf.js → use-decisions-uJXHf34W.js} +2 -2
  78. package/public/assets/{use-project-list-59LheVP7.js → use-project-list-CpWl6eHQ.js} +2 -2
  79. package/public/assets/{use-selectors-BZa25xEB.js → use-selectors-BdxBW8mL.js} +2 -2
  80. package/public/assets/{user-avatar-DHxlvUvV.js → user-avatar-3IndfpOc.js} +2 -2
  81. package/public/assets/{versioned-prompt-editor-BmED5DnJ.js → versioned-prompt-editor-CIVg7XB1.js} +2 -2
  82. package/public/assets/{work-queue-CSvpuNLz.js → work-queue-B9rnLwHZ.js} +2 -2
  83. package/public/assets/{workflow-marker-DAZcj5qt.js → workflow-marker-X8wxyhzC.js} +2 -2
  84. package/public/assets/{workflows-DdmxRSyg.js → workflows-o5YyMFW7.js} +2 -2
  85. package/public/assets/{workspaces-BxeKfVuF.js → workspaces-CzEGoAng.js} +2 -2
  86. package/public/cosmos.html +4 -4
  87. package/public/index.html +28 -28
  88. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  89. package/runner/src/adapters/claude-headless.ts +1 -1
  90. package/runner/src/adapters/claude-launch-exit.ts +26 -0
  91. package/runner/src/adapters/claude-session-probe.ts +1 -1
  92. package/runner/src/adapters/claude-tmux.ts +38 -10
  93. package/runner/src/adapters/claude.ts +28 -75
  94. package/runner/src/adapters/provider-quota-harvest.ts +20 -71
  95. package/runner/src/agent-runner/lifecycle-milestones.ts +2 -2
  96. package/runner/src/agent-runner/liveness-exchange.ts +104 -0
  97. package/runner/src/claude-system-prompt.ts +49 -0
  98. package/runner/src/launch-assembly.ts +14 -10
  99. package/runner/src/profile-home.ts +1 -1
  100. package/runner/src/project-instructions.ts +2 -2
  101. package/runner/src/provider-command.ts +18 -0
  102. package/runner/src/provider-setup.ts +2 -1
  103. package/runner/src/runner-core.ts +14 -15
  104. package/runner/src/runner-helpers.ts +0 -8
  105. package/runner/src/session-scratch.ts +6 -2
  106. package/runner/test-support/provisioning-context.ts +4 -2
  107. package/runner/test-support/runner-harness.ts +2 -1
  108. package/scripts/steward-policy-cleanup.ts +2 -2
  109. package/src/agent-authz.ts +2 -2
  110. package/src/agent-drive-arbiter.ts +3 -8
  111. package/src/agent-exit-cleanup-async.ts +2 -2
  112. package/src/agent-exit-cleanup.ts +23 -19
  113. package/src/agent-lifecycle-events.ts +112 -85
  114. package/src/agent-ref.ts +3 -2
  115. package/src/agent-status-events.ts +43 -14
  116. package/src/auth/password.ts +4 -3
  117. package/src/auth/session-refresh.ts +1 -1
  118. package/src/auth/session.test-fixture.ts +2 -2
  119. package/src/auth/session.ts +7 -7
  120. package/src/automations/crud.ts +8 -81
  121. package/src/automations/dispatch.ts +33 -58
  122. package/src/automations/index.ts +1 -1
  123. package/src/automations/persistence.ts +65 -0
  124. package/src/automations/precheck.ts +18 -16
  125. package/src/automations/read-async.ts +11 -0
  126. package/src/automations/reconcile.ts +30 -39
  127. package/src/automations/storage.ts +33 -10
  128. package/src/automations/write-async.ts +33 -0
  129. package/src/branch-land-notice.ts +3 -3
  130. package/src/branch-landed.ts +25 -23
  131. package/src/bus.ts +21 -19
  132. package/src/cd-deploy-notify.ts +2 -2
  133. package/src/ci/notifications.ts +4 -4
  134. package/src/ci/root-missing.ts +3 -3
  135. package/src/ci/transition-notify.ts +5 -5
  136. package/src/claude-app/oauth-http.ts +3 -3
  137. package/src/cli/workflow.ts +12 -3
  138. package/src/commands-db.ts +4 -4
  139. package/src/commands-write.ts +8 -0
  140. package/src/compaction-watch.ts +10 -8
  141. package/src/config-store-write.ts +2 -2
  142. package/src/config.ts +4 -11
  143. package/src/connectors.ts +10 -8
  144. package/src/context-advisory.ts +22 -21
  145. package/src/db/agent-action-write.ts +36 -0
  146. package/src/db/agent-control-async.ts +9 -0
  147. package/src/db/agent-control-write.ts +49 -0
  148. package/src/db/agent-effort-observe.ts +22 -0
  149. package/src/db/agent-meta.ts +14 -3
  150. package/src/db/agents-async.ts +8 -5
  151. package/src/db/agents.ts +15 -12
  152. package/src/db/auth-identities.ts +2 -2
  153. package/src/db/automation-read-ops.ts +11 -0
  154. package/src/db/automation-write-ops.ts +46 -0
  155. package/src/db/blackboard.ts +2 -2
  156. package/src/db/browser-session-write.ts +32 -0
  157. package/src/db/bus-outbox-write-ops.ts +3 -1
  158. package/src/db/checkout-refresh-schema.ts +47 -0
  159. package/src/db/checkout-refresh.ts +5 -5
  160. package/src/db/command-agent-profile-backfill.ts +39 -0
  161. package/src/db/command-agent-profiles.ts +5 -1
  162. package/src/db/command-retention.ts +126 -0
  163. package/src/db/commands-planner-stats.test-fixture.ts +8 -0
  164. package/src/db/commands-read-ops.ts +16 -0
  165. package/src/db/connection.ts +1 -182
  166. package/src/db/context-carry-write.ts +74 -0
  167. package/src/db/continuations.ts +4 -4
  168. package/src/db/db-error-registry.ts +12 -0
  169. package/src/db/gateway.ts +26 -133
  170. package/src/db/history-retention-ops.ts +13 -0
  171. package/src/db/inbox-async.ts +2 -2
  172. package/src/db/inbox-read-ops.ts +1 -1
  173. package/src/db/inbox.ts +9 -3
  174. package/src/db/issue-associations.ts +2 -2
  175. package/src/db/issue-refs-async.ts +4 -1
  176. package/src/db/issue-refs-read-ops.ts +6 -0
  177. package/src/db/issue-refs.ts +8 -8
  178. package/src/db/kernel-event-log-schema.ts +2 -0
  179. package/src/db/land-boundaries.ts +51 -5
  180. package/src/db/land-gate-attestations.ts +2 -2
  181. package/src/db/landing-receipts.ts +2 -2
  182. package/src/db/lifecycle-context-write.ts +5 -0
  183. package/src/db/lifecycle-tail-async.ts +76 -0
  184. package/src/db/lifecycle-tail-write-ops.ts +62 -0
  185. package/src/db/lifecycle-write-window.ts +2 -1
  186. package/src/db/lineage-pair-dedupe-sql.ts +3 -3
  187. package/src/db/main-connection-mode.ts +11 -0
  188. package/src/db/main-connection-writes.ts +20 -2
  189. package/src/db/maintenance-job-runs-async.ts +2 -2
  190. package/src/db/maintenance-job-write-ops.ts +1 -1
  191. package/src/db/maintenance-pauses.ts +2 -2
  192. package/src/db/message-send.ts +4 -0
  193. package/src/db/messages.ts +31 -25
  194. package/src/db/migrations.ts +18 -1
  195. package/src/db/notification-write-ops.ts +19 -0
  196. package/src/db/operator-answer-write.ts +19 -0
  197. package/src/db/orchestrators.ts +10 -4
  198. package/src/db/pairs-async.ts +22 -1
  199. package/src/db/pairs-write-ops.ts +8 -3
  200. package/src/db/pairs.ts +41 -48
  201. package/src/db/plan-dispatch-schema.ts +5 -1
  202. package/src/db/plan-ready-notices.ts +43 -0
  203. package/src/db/plan-tools-include-migration.ts +36 -0
  204. package/src/db/plans-write-ops.ts +2 -0
  205. package/src/db/presence-buffer.ts +5 -0
  206. package/src/db/presence-loop.ts +18 -23
  207. package/src/db/presence-write.ts +0 -6
  208. package/src/db/project-entries-async.ts +14 -0
  209. package/src/db/project-entries-read-ops.ts +5 -1
  210. package/src/db/project-entries-write-ops.ts +8 -0
  211. package/src/db/project-entries.ts +15 -12
  212. package/src/db/project-journal.ts +2 -2
  213. package/src/db/project-trust-approvals.ts +2 -2
  214. package/src/db/prompt-templates.ts +4 -4
  215. package/src/db/read-op-marshaling-fixtures.ts +18 -0
  216. package/src/db/read-ops.ts +4 -0
  217. package/src/db/retention.ts +13 -2
  218. package/src/db/review-publish-write.ts +8 -0
  219. package/src/db/runtime-admin-async.ts +19 -0
  220. package/src/db/runtime-admin-write-ops.ts +36 -0
  221. package/src/db/runtime-tail-async.ts +288 -0
  222. package/src/db/runtime-tail-write-ops.ts +97 -0
  223. package/src/db/schema.ts +4 -1
  224. package/src/db/spawn-budget.ts +5 -0
  225. package/src/db/spawn-delegation.ts +1 -11
  226. package/src/db/sql-audit-indexes.ts +3 -0
  227. package/src/db/stats-async.ts +5 -3
  228. package/src/db/task-entity.ts +5 -4
  229. package/src/db/team-claim-policy.ts +60 -0
  230. package/src/db/teams-async.ts +4 -0
  231. package/src/db/teams-write-ops.ts +4 -0
  232. package/src/db/terminal-events.ts +15 -0
  233. package/src/db/timer-cutover-bodies.ts +292 -0
  234. package/src/db/timer-cutover-core.ts +37 -278
  235. package/src/db/timer-cutover-state.ts +40 -0
  236. package/src/db/timer-cutover-write-ops.ts +1 -40
  237. package/src/db/token-db-write-ops.ts +2 -0
  238. package/src/db/token-standing-async.ts +12 -0
  239. package/src/db/token-standing.ts +6 -9
  240. package/src/db/token-usage-retention.ts +33 -0
  241. package/src/db/token-usage-write-ops.ts +1 -1
  242. package/src/db/token-usage.ts +4 -1
  243. package/src/db/user-invites-async.ts +13 -0
  244. package/src/db/user-invites.ts +3 -3
  245. package/src/db/users.ts +14 -6
  246. package/src/db/workspaces.ts +8 -5
  247. package/src/db/write-ops.ts +31 -12
  248. package/src/db/writer-fault-seam.ts +2 -9
  249. package/src/db/writer-fault-test-ops.ts +18 -0
  250. package/src/db/writer-gateway.ts +42 -46
  251. package/src/dev.ts +8 -3
  252. package/src/event-loop-lag.ts +4 -2
  253. package/src/event-loop-yield.ts +2 -2
  254. package/src/events.ts +10 -8
  255. package/src/host-provider-store.ts +5 -4
  256. package/src/hub-metrics-report.ts +5 -1
  257. package/src/hub-metrics.ts +38 -18
  258. package/src/injection-sweep-pacing.ts +6 -8
  259. package/src/land-gate-notifications.ts +11 -10
  260. package/src/land-gate-queue-progress.ts +3 -3
  261. package/src/land-settle-dispatch.ts +52 -92
  262. package/src/lifecycle-context-pressure.ts +11 -10
  263. package/src/lifecycle-manager.ts +104 -98
  264. package/src/maintenance/breaker.ts +18 -16
  265. package/src/maintenance/checkout-refresh.ts +18 -1
  266. package/src/maintenance/critical-job-watchdog.ts +3 -3
  267. package/src/maintenance/events.ts +3 -3
  268. package/src/maintenance/history-retention-job.ts +30 -0
  269. package/src/maintenance/jobs.ts +29 -67
  270. package/src/maintenance/long-running-work.ts +3 -1
  271. package/src/maintenance/offline-agent-prune-job.ts +28 -0
  272. package/src/maintenance/orphaned-sessions.ts +5 -4
  273. package/src/maintenance/pauses.ts +4 -10
  274. package/src/maintenance/plan-ready-notice-job.ts +71 -0
  275. package/src/maintenance/scheduler.ts +18 -13
  276. package/src/maintenance/stalled-delivery-pager.ts +4 -4
  277. package/src/maintenance/teams.ts +19 -30
  278. package/src/maintenance/workspaces.ts +17 -27
  279. package/src/managed-policy-escalation.ts +7 -7
  280. package/src/managed-policy.ts +3 -3
  281. package/src/managed-provider-gate.ts +5 -4
  282. package/src/managed-spawn-reservation.ts +5 -4
  283. package/src/mcp/index.ts +8 -8
  284. package/src/mcp/output-descriptions.ts +1 -1
  285. package/src/mcp/presentation.ts +2 -1
  286. package/src/mcp/runtime-output.ts +6 -1
  287. package/src/mcp/self-care-visibility.ts +2 -2
  288. package/src/mcp/spawn-targets-matrix.ts +10 -1
  289. package/src/mcp/tool-groups.ts +3 -2
  290. package/src/mcp/tool-roles.ts +81 -0
  291. package/src/mcp/tools-workspace.ts +1 -1
  292. package/src/mcp-blackboard-tools.ts +6 -5
  293. package/src/mcp-decision-tools.ts +7 -7
  294. package/src/mcp-egress-tools.ts +10 -9
  295. package/src/mcp-issue-activity-tools.ts +2 -2
  296. package/src/mcp-issue-association-tools.ts +4 -4
  297. package/src/mcp-issue-ref-tools.ts +3 -3
  298. package/src/mcp-merge-tools.ts +5 -5
  299. package/src/mcp-notification-subscription-tools.ts +14 -15
  300. package/src/mcp-output-levels.test-fixture.ts +1 -1
  301. package/src/mcp-profile-trust-tools.ts +1 -1
  302. package/src/mcp-project-journal-tools.ts +4 -12
  303. package/src/mcp-project-tools.ts +17 -18
  304. package/src/mcp-routing-policy-tools.ts +3 -2
  305. package/src/mcp-team-tools.ts +6 -6
  306. package/src/mcp-workflow-tools.ts +5 -3
  307. package/src/memory-area-injection.ts +13 -12
  308. package/src/memory-boundary-capture.ts +6 -6
  309. package/src/memory-injection.ts +45 -43
  310. package/src/merge-pause-maintenance.ts +5 -4
  311. package/src/notification-router.ts +44 -17
  312. package/src/notify.ts +5 -5
  313. package/src/observed-reset-refresh.ts +4 -4
  314. package/src/operator-alarm.ts +2 -5
  315. package/src/project-ingest.ts +6 -6
  316. package/src/project-instructions.ts +8 -1
  317. package/src/project-trust.ts +12 -11
  318. package/src/prompt-resolver.ts +3 -3
  319. package/src/provider-quota-async.ts +5 -7
  320. package/src/provider-timeline-event.ts +4 -7
  321. package/src/quota-band-delivery.ts +2 -2
  322. package/src/recipe-runner.ts +4 -3
  323. package/src/retention-config-store.ts +4 -3
  324. package/src/reviewer-pipeline.ts +11 -10
  325. package/src/routes/_route.ts +4 -4
  326. package/src/routes/_shared.ts +13 -12
  327. package/src/routes/agent-effort.ts +5 -5
  328. package/src/routes/agent-heartbeat-quota.ts +23 -0
  329. package/src/routes/agent-keep.ts +1 -1
  330. package/src/routes/agent-reporting.ts +1 -1
  331. package/src/routes/agent-self-effort.ts +5 -5
  332. package/src/routes/agent-sessions.ts +24 -24
  333. package/src/routes/agents-spawn.ts +1 -1
  334. package/src/routes/agents.ts +17 -119
  335. package/src/routes/auth.ts +14 -15
  336. package/src/routes/authority-audit.ts +2 -2
  337. package/src/routes/automations.ts +6 -5
  338. package/src/routes/channel-binding-delete.ts +1 -1
  339. package/src/routes/channel-output.ts +3 -3
  340. package/src/routes/claude-api-budget.ts +5 -5
  341. package/src/routes/commands-listing.ts +1 -1
  342. package/src/routes/commands.ts +29 -27
  343. package/src/routes/context-resets.ts +2 -2
  344. package/src/routes/coordinator-teams.ts +1 -1
  345. package/src/routes/decisions.ts +2 -2
  346. package/src/routes/host-secret-files.ts +1 -1
  347. package/src/routes/hosts.ts +11 -11
  348. package/src/routes/inbox.ts +3 -2
  349. package/src/routes/index.ts +2 -1
  350. package/src/routes/integrations.ts +9 -7
  351. package/src/routes/issue-activity.ts +2 -2
  352. package/src/routes/issue-associations.ts +4 -4
  353. package/src/routes/issue-refs.ts +3 -3
  354. package/src/routes/kernel-timers-operator.ts +1 -1
  355. package/src/routes/memory.ts +1 -1
  356. package/src/routes/merges.ts +11 -11
  357. package/src/routes/messages.ts +23 -17
  358. package/src/routes/orchestrator-bootstrap.ts +1 -1
  359. package/src/routes/orchestrator-host-registration.ts +2 -0
  360. package/src/routes/orchestrator-host-utilization.ts +2 -2
  361. package/src/routes/orchestrator-proxy.ts +2 -2
  362. package/src/routes/orchestrator.ts +27 -18
  363. package/src/routes/pairs.ts +8 -8
  364. package/src/routes/project-profile-instructions.ts +1 -1
  365. package/src/routes/project-trust.ts +1 -1
  366. package/src/routes/projects.ts +16 -16
  367. package/src/routes/prompt-templates.ts +12 -12
  368. package/src/routes/provider-quotas.ts +10 -10
  369. package/src/routes/run-command.ts +1 -1
  370. package/src/routes/secrets-backup.ts +2 -2
  371. package/src/routes/secrets-import.ts +1 -1
  372. package/src/routes/secrets-vault.ts +7 -7
  373. package/src/routes/settings.ts +1 -1
  374. package/src/routes/shipping.ts +9 -1
  375. package/src/routes/spawn-policy.ts +8 -7
  376. package/src/routes/sse.ts +2 -2
  377. package/src/routes/team-templates.ts +7 -7
  378. package/src/routes/teams.ts +10 -10
  379. package/src/routes/tokens.ts +18 -17
  380. package/src/routes/users.ts +24 -24
  381. package/src/routes/viewer-read.ts +3 -3
  382. package/src/routes/web-tool-calls.ts +4 -4
  383. package/src/routes/workflows.ts +2 -2
  384. package/src/routes/workspaces.ts +17 -16
  385. package/src/routing-policy-push.ts +6 -6
  386. package/src/runtime-grant.ts +17 -11
  387. package/src/runtime-tokens.ts +20 -28
  388. package/src/secrets-broker/config.ts +1 -1
  389. package/src/secrets-broker/service.ts +2 -2
  390. package/src/security.ts +3 -1
  391. package/src/self-resume-carry.ts +21 -110
  392. package/src/self-resume-supersede.ts +4 -3
  393. package/src/self-resume.ts +54 -66
  394. package/src/server-background.ts +1 -1
  395. package/src/server.ts +21 -22
  396. package/src/services/agent-action.ts +12 -31
  397. package/src/services/agent-effort.ts +7 -32
  398. package/src/services/agent-hang-watchdog-job.ts +2 -2
  399. package/src/services/agent-heartbeat.ts +166 -0
  400. package/src/services/agent-reporting.ts +1 -1
  401. package/src/services/browser-inventory.ts +3 -3
  402. package/src/services/browser-session-state.ts +3 -2
  403. package/src/services/browser-session.ts +21 -27
  404. package/src/services/bus-command-update.ts +9 -9
  405. package/src/services/checkout-refresh-state.ts +1 -0
  406. package/src/services/checkout-refresh.test-fixture.ts +3 -2
  407. package/src/services/command-host.ts +7 -2
  408. package/src/services/coordinator-digest.ts +3 -2
  409. package/src/services/dispatch-command.ts +12 -13
  410. package/src/services/effective-launch-driver.ts +14 -9
  411. package/src/services/host-changed-paths.test-fixture.ts +5 -6
  412. package/src/services/host-project-readiness.ts +2 -2
  413. package/src/services/host-providers.ts +1 -1
  414. package/src/services/host-utilization.ts +9 -9
  415. package/src/services/idle-agent-digest.ts +17 -12
  416. package/src/services/idle-epics.ts +4 -4
  417. package/src/services/interrupt-agent.ts +12 -9
  418. package/src/services/issue-activity.ts +3 -3
  419. package/src/services/issue-associations.ts +15 -18
  420. package/src/services/issue-lifecycle-comments.ts +3 -2
  421. package/src/services/issue-lifecycle.ts +14 -13
  422. package/src/services/issue-refs.ts +4 -5
  423. package/src/services/kernel-timers-cutover-chaos-worker.ts +1 -1
  424. package/src/services/kernel-timers-ingress-chaos-worker.ts +6 -1
  425. package/src/services/kernel-timers-ingress.ts +3 -3
  426. package/src/services/kernel-timers-message-authority-chaos-worker.ts +3 -10
  427. package/src/services/kernel-timers-operator-chaos-worker.ts +3 -2
  428. package/src/services/kernel-timers-outbox.ts +1 -1
  429. package/src/services/kernel-timers-stage10-operator.ts +1 -1
  430. package/src/services/kernel-timers.ts +4 -3
  431. package/src/services/land-gate-placement.ts +11 -2
  432. package/src/services/land-issue-relations.ts +5 -4
  433. package/src/services/land-restart-retry.ts +7 -6
  434. package/src/services/landed-ancestry.ts +6 -5
  435. package/src/services/legacy-landing-host.ts +4 -1
  436. package/src/services/legacy-landing-recovery.ts +8 -6
  437. package/src/services/managed-running.ts +17 -17
  438. package/src/services/memory-areas.ts +3 -3
  439. package/src/services/merge-pause.ts +9 -15
  440. package/src/services/operator-decisions.ts +37 -41
  441. package/src/services/orchestrator-registration-recovery.ts +6 -2
  442. package/src/services/orchestrator-upgrade.ts +14 -12
  443. package/src/services/permission-decision.ts +4 -3
  444. package/src/services/plan-ci-notice.ts +1 -1
  445. package/src/services/plan-conformance.ts +4 -4
  446. package/src/services/plan-dispatch-policy.ts +10 -3
  447. package/src/services/plan-dispatch.ts +35 -14
  448. package/src/services/plan-graph.ts +39 -261
  449. package/src/services/plan-import.ts +1 -1
  450. package/src/services/plan-live-bindings.ts +8 -37
  451. package/src/services/plan-task-create.ts +1 -1
  452. package/src/services/plan-terminal-refs.ts +2 -12
  453. package/src/services/plan-wake-digest.ts +8 -3
  454. package/src/services/profile-trust.ts +2 -2
  455. package/src/services/project.ts +11 -10
  456. package/src/services/prompt-templates.ts +6 -5
  457. package/src/services/provider-hold-nudge.ts +9 -9
  458. package/src/services/provider-hold-record.ts +13 -12
  459. package/src/services/provider-state-audit.ts +19 -18
  460. package/src/services/provisioning-harness/driver.ts +1 -1
  461. package/src/services/provisioning-harness/fixture-matrix.ts +3 -3
  462. package/src/services/provisioning-harness/lifecycle.ts +24 -22
  463. package/src/services/provisioning-harness/prepare.ts +16 -17
  464. package/src/services/rate-limit-resume.ts +10 -9
  465. package/src/services/red-main-auto-revert.ts +7 -5
  466. package/src/services/red-main-controller-deps.ts +20 -3
  467. package/src/services/red-main-incident.ts +3 -1
  468. package/src/services/red-main-quarantine.ts +2 -3
  469. package/src/services/register-agent.ts +22 -22
  470. package/src/services/restart-project-role.ts +1 -1
  471. package/src/services/restart-spawn.ts +17 -16
  472. package/src/services/review-publish.ts +7 -24
  473. package/src/services/review-ref-reconcile.ts +29 -38
  474. package/src/services/runtime-dependency-alert.ts +27 -0
  475. package/src/services/scheduler-command.ts +11 -9
  476. package/src/services/scheduler.ts +5 -5
  477. package/src/services/self-effort-grant.ts +5 -25
  478. package/src/services/send-message.ts +16 -33
  479. package/src/services/shutdown-agent.ts +17 -14
  480. package/src/services/spawn-agent.ts +12 -41
  481. package/src/services/spawn-chain-inspector.ts +1 -1
  482. package/src/services/spawn-cwd-placement.ts +21 -5
  483. package/src/services/spawn-issue-activity.ts +8 -6
  484. package/src/services/spawn-launch.ts +17 -1
  485. package/src/services/spawn-loss-escalation.ts +1 -1
  486. package/src/services/spawn-registration-watchdog.ts +2 -2
  487. package/src/services/spawn-repo-probe.ts +7 -5
  488. package/src/services/spawn-tree-cleanup.ts +7 -8
  489. package/src/services/steward-reaper.ts +4 -4
  490. package/src/services/task-context-hydration.ts +25 -1
  491. package/src/services/task-delivery.ts +20 -34
  492. package/src/services/task-entity.ts +40 -203
  493. package/src/services/task-issue-link.ts +13 -20
  494. package/src/services/task-issue-weave.ts +12 -11
  495. package/src/services/task-lifecycle.ts +27 -31
  496. package/src/services/task-repo-cwd.ts +37 -0
  497. package/src/services/task-review-hold.ts +4 -17
  498. package/src/services/task-semantic-events.ts +13 -11
  499. package/src/services/task-state-reconcile.ts +3 -4
  500. package/src/services/task-validation.ts +2 -2
  501. package/src/services/team-templates.ts +5 -5
  502. package/src/services/team.ts +31 -98
  503. package/src/services/terminal-provider-exit.ts +6 -5
  504. package/src/services/timer-message-fire-chaos-worker.ts +7 -3
  505. package/src/services/timer-message-fire-outbox.ts +1 -1
  506. package/src/services/transient-agent-reaper.ts +22 -19
  507. package/src/services/turn-reconcile-audit.ts +9 -9
  508. package/src/services/user-onboarding.ts +8 -6
  509. package/src/services/user-profile.ts +6 -9
  510. package/src/services/work-finality.ts +16 -4
  511. package/src/services/workflow-auto-start.ts +2 -1
  512. package/src/services/workflow-caller.ts +61 -4
  513. package/src/services/workflow-child-proof-worker.ts +1 -1
  514. package/src/services/workflow-control-proof-worker.ts +1 -1
  515. package/src/services/workflow-coordinator.ts +8 -2
  516. package/src/services/workflow-decisions.ts +5 -5
  517. package/src/services/workflow-deferred-cleanup.ts +1 -1
  518. package/src/services/workflow-effect-driver.ts +42 -19
  519. package/src/services/workflow-effects.ts +41 -27
  520. package/src/services/workflow-pins.ts +7 -4
  521. package/src/services/workflow-reconcile.ts +1 -0
  522. package/src/services/workflow-resume-pins.ts +3 -3
  523. package/src/services/workflow-routing-defaults.ts +18 -0
  524. package/src/services/workflow-run-view.ts +4 -3
  525. package/src/services/workflow-run.test-fixture.ts +1 -1
  526. package/src/services/workflow-runs.ts +34 -22
  527. package/src/services/workflow-supervisor-state.ts +21 -1
  528. package/src/services/workflow-supervisor.ts +4 -3
  529. package/src/services/workspace-recovery.ts +4 -3
  530. package/src/spawn-admission.ts +10 -2
  531. package/src/spawn-placement.ts +27 -9
  532. package/src/spawn-targets.ts +8 -8
  533. package/src/sse-agent-status.ts +15 -6
  534. package/src/sse.ts +49 -24
  535. package/src/startup-context-injection.ts +61 -57
  536. package/src/steward-handoff.ts +4 -3
  537. package/src/steward-policy-cleanup.ts +9 -8
  538. package/src/steward.ts +2 -2
  539. package/src/task-dispatch-live.ts +5 -2
  540. package/src/task-dispatcher.ts +2 -2
  541. package/src/token-db.ts +2 -2
  542. package/src/token-usage-async.ts +2 -4
  543. package/src/user-awaiting-reply.ts +5 -5
  544. package/src/workspace-actions.ts +24 -29
  545. package/src/workspace-auto-merge.ts +14 -12
  546. package/src/workspace-changed-paths-client.ts +16 -5
  547. package/src/workspace-cleanup-stale.ts +30 -7
  548. package/src/workspace-command-settle.ts +24 -16
  549. package/src/workspace-config.ts +1 -1
  550. package/src/workspace-conflict-resolver.ts +9 -7
  551. package/src/workspace-dead-owner-recovery.ts +5 -4
  552. package/src/workspace-escalation.ts +12 -11
  553. package/src/workspace-human-escalation.ts +3 -3
  554. package/src/workspace-land-gate-watchdog.ts +3 -3
  555. package/src/workspace-land-refusal.ts +20 -0
  556. package/src/workspace-land-stopped.ts +1 -0
  557. package/src/workspace-merge.ts +10 -26
  558. package/src/workspace-nothing-to-land-notice.ts +2 -2
  559. package/src/workspace-orphans.ts +18 -37
  560. package/src/workspace-pr-completion.ts +10 -8
  561. package/src/workspace-rekey.ts +3 -3
  562. package/src/workspace-steward-failure.ts +2 -2
  563. package/src/workspace-steward-wake.ts +2 -2
  564. package/public/assets/agent-liveness-CaNwK0Zf.js +0 -2
  565. package/public/assets/provider-display-DsuWMvVL.js +0 -2
  566. package/public/assets/run-card-CpKqRbhg.js +0 -2
  567. package/public/assets/shipping-B9YtnwtG.js +0 -2
  568. package/public/assets/store-DcClXLH0.js +0 -9
  569. package/runner/src/agent-runner/http-liveness.ts +0 -85
  570. package/src/db/on-loop-write-transaction.ts +0 -34
@@ -1,3 +1,6 @@
1
+ import { prepareCommandWriteAsync, createCommandAsync, submitPreparedCommandAsync } from "./commands-write";
2
+ import type { ReviewCleanupInput } from "./db/review-publish-write";
3
+ import { getGateway } from "./db/gateway";
1
4
  import { recordWorkspaceAudit } from "./workspace-action-audit";
2
5
  import { WORKSPACE_MERGE_HOLD_MESSAGE } from "./db/workspace-merge-hold";
3
6
  import { stewardGenerationCanceled } from "./db/workspace-steward-fence";
@@ -14,22 +17,13 @@ import { stringValue } from "@humwick/sdk";
14
17
  // `requestWorkspaceMerge`, the core does not emit the command event; it returns
15
18
  // the Command and the caller emits via its own `emitCommand` (kept module-local).
16
19
 
17
- import { createCommand } from "./commands-db";
20
+
18
21
  import { requestWorkspaceRekey } from "./workspace-rekey";
19
22
  import { isWorkspaceSteward, workspaceStewardRefusal } from "./workspace-steward-authority";
20
23
  import { getStewardConfig } from "./config-store";
21
24
  import { cancelPendingLegacyLandingsAsync } from "./commands-landing-async";
22
25
  import { workspaceOwnerOrchestrator } from "./workspace-host";
23
- import {
24
- getWorkspace,
25
- claimWorkspaceMetadataAsync,
26
- listOrchestrators,
27
- patchWorkspaceMetadataAsync,
28
- releaseWorkspaceClaimMetadataAsync,
29
- setWorkspaceMergeHoldAsync,
30
- transitionWorkspaceLandStateAsync,
31
- updateWorkspaceStatusAsync,
32
- } from "./db";
26
+ import { getWorkspace, claimWorkspaceMetadataAsync, listOrchestrators, patchWorkspaceMetadataAsync, releaseWorkspaceClaimMetadataAsync, setWorkspaceMergeHoldAsync, transitionWorkspaceLandStateAsync, updateWorkspaceStatusAsync, REVIEW_HOLD_REJECT_MESSAGE, workspaceLandBarrier } from "./db";
33
27
  import { isOwnerAlive, requestWorkspaceMerge } from "./workspace-merge";
34
28
  import { buildWorkspaceCleanupCommand } from "./workspace-cleanup-stale";
35
29
  // Re-export the land-strategy contract so the MCP land tool validates against the same
@@ -38,15 +32,13 @@ export { LAND_STRATEGIES } from "./workspace-merge";
38
32
  import { claimMetadataPatch, workspaceActiveClaim, workspaceStewardHandbackPending } from "./workspace-claim";
39
33
  import { DIRTY_WORKTREE_LAND_SKIP_REASON, LAND_IN_FLIGHT_STATUSES, READY_TO_LAND_STATUSES, TERMINAL_WORKSPACE_STATUSES, worktreeReapable } from "./workspace-phase";
40
34
  import { LAND_BLOCK_REJECT_MESSAGE, stripReservedWorkspaceMetadataKeys } from "./land-block";
41
- import { REVIEW_HOLD_REJECT_MESSAGE, workspaceLandBarrier } from "./db";
42
35
  import { CLEAR_MERGE_NO_PROGRESS, scheduleRepoMerge } from "./workspace-auto-merge";
43
36
  import { archiveLandAttempt, CLEAR_LAST_ATTEMPT_VERDICT, CLEAR_MERGE_RETRY } from "./workspace-merge-progress";
44
37
  import { fetchHostMergePreview, refreshWorkspaceGitState } from "./workspace-probe";
45
38
  import { recordLandStopped } from "./workspace-land-stopped";
46
39
  import { finishWorkspaceStewardHandoff } from "./steward-handoff";
47
40
  import { stewardHandoffIdentity } from "./steward-provenance";
48
- import type { Command, WorkspaceAutoMergePolicy, WorkspaceLandingPolicy, WorkspaceMergeStrategy, WorkspaceRecord, WorkspaceStatus } from "./types";
49
- import type { WorkspaceLandGateLevel } from "./types";
41
+ import type { Command, WorkspaceAutoMergePolicy, WorkspaceLandingPolicy, WorkspaceMergeStrategy, WorkspaceRecord, WorkspaceStatus, WorkspaceLandGateLevel } from "./types";
50
42
  import type { WorkspaceLandGateAuth } from "./workspace-land-gate";
51
43
 
52
44
  // Single source of truth for the action verb set. The route's `optionalEnum` and
@@ -326,7 +318,7 @@ export async function applyWorkspaceAction(workspace: WorkspaceRecord, input: Ap
326
318
  return { ok: false, httpStatus: 422, error: `workspace ${workspace.id} has no isolated worktree to refresh` };
327
319
  }
328
320
  const checkOnly = input.checkOnly === true;
329
- const built = buildWorkspaceDepsRefreshCommand(workspace, agentId ?? "agent", checkOnly);
321
+ const built = (await buildWorkspaceDepsRefreshCommand(workspace, agentId ?? "agent", checkOnly));
330
322
  if (!built.ok) return { ok: false, httpStatus: built.status, error: built.error };
331
323
  await recordWorkspaceAudit({
332
324
  action,
@@ -416,11 +408,11 @@ export async function applyWorkspaceAction(workspace: WorkspaceRecord, input: Ap
416
408
  error: `workspace ${workspace.id} cannot be cleaned up safely: ${safety.error}; pass force:true with a detail reason only if intentionally discarding work`,
417
409
  };
418
410
  }
419
- const built = buildWorkspaceCleanupCommand(workspace, agentId ?? "dashboard", {
411
+ const built = (await buildWorkspaceCleanupCommand(workspace, agentId ?? "dashboard", {
420
412
  force: input.force === true,
421
413
  reason: detail,
422
414
  autoReclaim: input.autoReclaim,
423
- });
415
+ }));
424
416
  if (!built.ok) return { ok: false, httpStatus: built.status, error: built.error };
425
417
  command = built.command;
426
418
  }
@@ -496,17 +488,17 @@ export async function applyWorkspaceAction(workspace: WorkspaceRecord, input: Ap
496
488
  // captured delivered `sha`. #1452 round-5 H4: the relay deliberately does NOT derive or return a
497
489
  // ref — the AUTHORITATIVE ref is whatever the HOST reports back on the command result (the host may
498
490
  // run a different sanitizer version), and the ledger records it only after that settlement.
499
- export function buildWorkspacePublishReviewCommand(
491
+ export async function buildWorkspacePublishReviewCommand(
500
492
  workspace: WorkspaceRecord,
501
493
  requestedBy: string,
502
- opts: { taskId?: number; sha?: string; reviewRef?: string } = {},
503
- ): { ok: true; command: Command } | { ok: false; status: number; error: string } {
494
+ opts: { taskId?: number; sha?: string; reviewRef?: string; cleanup?: ReviewCleanupInput } = {},
495
+ ): Promise<{ ok: true; command: Command } | { ok: false; status: number; error: string }> {
504
496
  if (workspace.mode !== "isolated" || !workspace.worktreePath) {
505
497
  return { ok: false, status: 422, error: `workspace ${workspace.id} has no worktree to publish for review` };
506
498
  }
507
499
  const owner = workspaceOwnerOrchestrator(workspace, listOrchestrators(), { onlineOnly: false });
508
500
  if (!owner) return { ok: false, status: 409, error: "no orchestrator owns this workspace path" };
509
- const command = createCommand({
501
+ const prepared = await prepareCommandWriteAsync({
510
502
  type: "workspace.publish-review",
511
503
  source: "system",
512
504
  target: owner.agentId,
@@ -527,6 +519,9 @@ export function buildWorkspacePublishReviewCommand(
527
519
  queued: owner.status !== "online",
528
520
  },
529
521
  });
522
+ const command = opts.cleanup
523
+ ? await getGateway().write("commands.createReviewPublish", { command: prepared, cleanup: opts.cleanup }) as unknown as Command
524
+ : await submitPreparedCommandAsync(prepared);
530
525
  return { ok: true, command };
531
526
  }
532
527
 
@@ -537,10 +532,10 @@ export function buildWorkspacePublishReviewCommand(
537
532
  // caller passes the EXACT host-confirmed `ref` from the ledger and the host deletes THAT ref verbatim
538
533
  // (after asserting it is under refs/review/*) — it no longer re-derives the target from branch/
539
534
  // workspaceId, which could diverge across a relay/host sanitizer skew and leak the real ref.
540
- export function buildReviewRefUnpublishCommandFromFields(
535
+ export async function buildReviewRefUnpublishCommandFromFields(
541
536
  fields: { workspaceId: string; repoRoot: string; worktreePath?: string; branch?: string; orchestratorId?: string; ref?: string },
542
537
  requestedBy: string,
543
- ): { ok: true; command: Command } | { ok: false; status: number; error: string } {
538
+ ): Promise<{ ok: true; command: Command } | { ok: false; status: number; error: string }> {
544
539
  const synthetic = {
545
540
  orchestratorId: fields.orchestratorId,
546
541
  sourceCwd: fields.repoRoot,
@@ -550,7 +545,7 @@ export function buildReviewRefUnpublishCommandFromFields(
550
545
  } as unknown as WorkspaceRecord;
551
546
  const owner = workspaceOwnerOrchestrator(synthetic, listOrchestrators(), { onlineOnly: false });
552
547
  if (!owner) return { ok: false, status: 409, error: "no orchestrator owns this repo path" };
553
- const command = createCommand({
548
+ const command = (await createCommandAsync({
554
549
  type: "workspace.unpublish-review",
555
550
  source: "system",
556
551
  target: owner.agentId,
@@ -566,20 +561,20 @@ export function buildReviewRefUnpublishCommandFromFields(
566
561
  requestedAt: Date.now(),
567
562
  queued: owner.status !== "online",
568
563
  },
569
- });
564
+ }));
570
565
  return { ok: true, command };
571
566
  }
572
567
 
573
568
  // Build a `workspace.deps-refresh` command for a worktree's owning orchestrator
574
569
  // (issue #51). checkOnly just reports staleness. Same owner-resolution as cleanup.
575
- function buildWorkspaceDepsRefreshCommand(
570
+ async function buildWorkspaceDepsRefreshCommand(
576
571
  workspace: WorkspaceRecord,
577
572
  requestedBy: string,
578
573
  checkOnly: boolean,
579
- ): { ok: true; command: Command } | { ok: false; status: number; error: string } {
574
+ ): Promise<{ ok: true; command: Command } | { ok: false; status: number; error: string }> {
580
575
  const owner = workspaceOwnerOrchestrator(workspace, listOrchestrators(), { onlineOnly: false });
581
576
  if (!owner) return { ok: false, status: 409, error: "no online orchestrator owns this workspace path" };
582
- const command = createCommand({
577
+ const command = (await createCommandAsync({
583
578
  type: "workspace.deps-refresh",
584
579
  source: "system",
585
580
  target: owner.agentId,
@@ -594,7 +589,7 @@ function buildWorkspaceDepsRefreshCommand(
594
589
  requestedAt: Date.now(),
595
590
  queued: owner.status !== "online",
596
591
  },
597
- });
592
+ }));
598
593
  return { ok: true, command };
599
594
  }
600
595
 
@@ -1,3 +1,5 @@
1
+ import { workspaceLandRefused } from "./workspace-land-refusal";
2
+ import { refreshPendingLandQueueLeaseAsync } from "./db/runtime-tail-async";
1
3
  // Event-driven workspace merge-back engine (#237).
2
4
  //
3
5
  // The branch merge-back used to be driven entirely by a 2-min maintenance poll, so an
@@ -30,8 +32,8 @@ import {
30
32
  patchWorkspaceMetadataAsync,
31
33
  updateWorkspaceStatus,
32
34
  workspaceLandBarrier, updateWorkspaceStatusAsync} from "./db";
33
- import { findLatestCommandByCorrelation } from "./commands-db";
34
- import { refreshPendingLandQueueLease } from "./db/commands-claim-admission";
35
+ import { findLatestCommandByCorrelationAsync } from "./commands-write";
36
+
35
37
  import { notifyBranchLandFailed } from "./branch-landed";
36
38
  import { resolveStewardIdentity } from "./steward-identity";
37
39
  import { emitCommandEvent } from "./command-events";
@@ -144,14 +146,14 @@ async function escalateNoProgressMerge(ws: WorkspaceRecord, _tip?: string): Prom
144
146
  const payload = { kind: "workspace.auto-merge-stuck", workspaceId: ws.id, repoRoot: ws.repoRoot, branch: ws.branch, baseRef: ws.baseRef, attempts: MAX_NO_PROGRESS_MERGE_ATTEMPTS, reason: mergeError };
145
147
  let escalated = false;
146
148
  if (recipients.length) {
147
- notifyBranchLandFailed({ workspace: ws,
149
+ await notifyBranchLandFailed({ workspace: ws,
148
150
  commandId: typeof meta.mergeCommandId === "string" ? meta.mergeCommandId : undefined,
149
151
  recipients,
150
152
  reason: `auto-merge backed off after ${MAX_NO_PROGRESS_MERGE_ATTEMPTS} no-progress attempts (${mergeError})`,
151
153
  });
152
154
  escalated = true;
153
155
  } else {
154
- const human = notifyWorkspaceHumanEscalation({ subject, body, payload, source: "workspace-auto-merge" });
156
+ const human = (await notifyWorkspaceHumanEscalation({ subject, body, payload, source: "workspace-auto-merge" }));
155
157
  escalated = human.accepted;
156
158
  if (!human.accepted) {
157
159
  console.warn(`[workspace-auto-merge] no-progress escalation for ${ws.id} had zero agent recipients and no human channel: ${human.reason ?? "unknown reason"}`);
@@ -180,7 +182,7 @@ async function notifyProtectedTipRestore(ws: WorkspaceRecord, preview: Workspace
180
182
  // whose delivered tip was discarded CANNOT reach landed-on-main by any land path until the carry is
181
183
  // explicitly confirmed. Returns ok=false if it could NOT durably record the obligation — the caller
182
184
  // fails closed on that (withholds the steward hand-off) rather than risk a silent divergent land.
183
- const carry = markWorkspaceTasksCarryPending(ws, discardedHead);
185
+ const carry = await markWorkspaceTasksCarryPending(ws, discardedHead);
184
186
  const body = `Workspace \`${ws.branch ?? ws.id}\` restored protected tip \`${preview.protectedTip?.slice(0, 12) ?? "unknown"}\`; discarded HEAD \`${discardedHead.slice(0, 12)}\` was preserved at \`${discardedRef}\`.`;
185
187
  await createActivityEventAsync({
186
188
  clientId: `workspace-protected-tip-restore-${ws.id}-${Date.now()}`,
@@ -198,7 +200,7 @@ async function notifyProtectedTipRestore(ws: WorkspaceRecord, preview: Workspace
198
200
  const { coordinatorAgentId } = resolveStewardIdentity(current);
199
201
  const recipients = [...new Set([coordinatorAgentId, current.ownerAgentId].filter((r): r is string => Boolean(r)))];
200
202
  if (recipients.length) {
201
- routeNotification({
203
+ await routeNotification({
202
204
  type: "workspace.land_gate_warning",
203
205
  scope: { workspaceId: current.id, repoRoot: current.repoRoot, author: current.ownerAgentId, parent: coordinatorAgentId ?? undefined },
204
206
  recipients,
@@ -492,7 +494,7 @@ async function landCandidates(
492
494
  }
493
495
  }
494
496
  if (p.conflict === true || protectedTipRestored) {
495
- emitWorkspaceTaskSemanticNotifications({
497
+ await emitWorkspaceTaskSemanticNotifications({
496
498
  workspace: ws,
497
499
  transition: "land-conflict",
498
500
  actor: "workspace-auto-merge",
@@ -616,7 +618,7 @@ function landableWorkspaces(repoRoot?: string, baseRef?: string): WorkspaceRecor
616
618
  // `review_requested` with NO authorization; after the coordinator's clear the flag is off
617
619
  // and the promoted delivery lands normally). Covers all three sweep triggers (event,
618
620
  // backstop, watchdog) and the conflict→steward hand-off at this single selection filter.
619
- && !workspaceLandBarrier(ws).blocked
621
+ && !workspaceLandBarrier(ws).blocked && !workspaceLandRefused(ws)
620
622
  // #1473 — nor is a workspace bound to a deliverable Task that has NOT authorized a land: a pushed
621
623
  // `agent/*` branch in a ready-to-land status is not, by itself, a land authorization (a "HOLD" is
622
624
  // coordinator convention only). Excluding it here keeps it out of BOTH the auto-land dispatch and
@@ -761,9 +763,9 @@ function commandIsTerminal(command: Command | null): boolean {
761
763
  return Boolean(command && TERMINAL_COMMAND_STATUSES.has(command.status));
762
764
  }
763
765
 
764
- function latestWorkspaceCommand(ws: WorkspaceRecord): Command | null {
766
+ async function latestWorkspaceCommand(ws: WorkspaceRecord): Promise<Command | null> {
765
767
  const type = LAND_IN_FLIGHT_STATUSES.has(ws.status) ? "workspace.merge" : "workspace.cleanup";
766
- return findLatestCommandByCorrelation(type, ws.id);
768
+ return findLatestCommandByCorrelationAsync(type, ws.id);
767
769
  }
768
770
 
769
771
  async function recoverAgedInFlightWorkspaces(now: number, signal?: AbortSignal): Promise<Record<string, unknown>> {
@@ -803,9 +805,9 @@ async function recoverAgedInFlightWorkspaces(now: number, signal?: AbortSignal):
803
805
  // young merge_planned row the 20-min age gate would otherwise skip. Only a merge_planned row can be
804
806
  // executor-orphaned, so a young cleanup_requested/non-merge row still pays NO command lookup (the
805
807
  // pre-#2094 cost) — fetch only when the row is old enough for the existing recovery OR could be an orphan.
806
- let command = (LAND_IN_FLIGHT_STATUSES.has(ws.status) || oldEnough(ws)) ? latestWorkspaceCommand(ws) : null;
808
+ let command = (LAND_IN_FLIGHT_STATUSES.has(ws.status) || oldEnough(ws)) ? await latestWorkspaceCommand(ws) : null;
807
809
  if (command?.status === "pending" && command.type === "workspace.merge") {
808
- if (refreshPendingLandQueueLease(command.id, now)) {
810
+ if ((await refreshPendingLandQueueLeaseAsync(command.id, now))) {
809
811
  stillActive.push(ws.id);
810
812
  continue;
811
813
  }
@@ -1,6 +1,7 @@
1
1
  import type { ChangedPathDiff } from "@humwick/sdk";
2
2
  import { decideDiffGate, type DiffGateDecision } from "./services/diff-gate";
3
3
  import { fetchOwningHostJson } from "./workspace-host-client";
4
+ import { workspaceHeadAlreadyOnBase } from "./services/task-nothing-to-land";
4
5
  import type { WorkspaceRecord } from "./types";
5
6
 
6
7
  /**
@@ -87,11 +88,21 @@ export async function resolveDeliveryDiffDecision(
87
88
  ...(reprobe.ok ? { headSha: reprobe.headSha } : {}),
88
89
  };
89
90
  }
90
- return { decision: decideDiffGate(reprobe), ...(reprobe.headSha ? { headSha: reprobe.headSha } : {}) };
91
+ return await classify(workspace, reprobe);
91
92
  }
93
+ return await classify(workspace, probe);
94
+ }
95
+
96
+ /** A head the owning host proves is already on the freshly fetched base lands nothing, so no
97
+ * gate can protect anything: accept it without one (#3214). Probed only on the would-gate path. */
98
+ async function classify(workspace: WorkspaceRecord, probe: ChangedPathDiff): Promise<DeliveryDiffEvidence> {
92
99
  const decision = decideDiffGate(probe);
93
- return {
94
- decision,
95
- ...(probe.ok && probe.headSha ? { headSha: probe.headSha } : {}),
96
- };
100
+ if (!probe.ok || !probe.headSha) return { decision };
101
+ if (decision.requireGates && await workspaceHeadAlreadyOnBase(workspace, probe.headSha)) {
102
+ return {
103
+ decision: { requireGates: false, reason: `delivered head ${probe.headSha.slice(0, 12)} is already on ${workspace.baseRef ?? "main"}: nothing lands`, paths: probe.paths },
104
+ headSha: probe.headSha,
105
+ };
106
+ }
107
+ return { decision, headSha: probe.headSha };
97
108
  }
@@ -1,3 +1,4 @@
1
+ import { createCommandAsync } from "./commands-write";
1
2
  // Cleanup-stale workspace reconciliation: builds the `workspace.cleanup` command and runs the
2
3
  // `workspace cleanup-stale --check/--execute` sweep (#208/#965/#1066). Kept as a standalone leaf
3
4
  // module (no workspace-auto-merge.ts dependency) so the transient-agent reap lifecycle (#1477)
@@ -7,7 +8,7 @@
7
8
 
8
9
  import { statSync } from "node:fs";
9
10
  import { emitCommandEvent } from "./command-events";
10
- import { createCommand } from "./commands-db";
11
+
11
12
  import { getAgent, listWorkspaces, updateWorkspaceStatusAsync } from "./db";
12
13
  import { fetchWorkspaceGitState } from "./workspace-git-state-client";
13
14
  import { workspaceOwnerOrchestrator } from "./workspace-host";
@@ -15,15 +16,15 @@ import { workspaceActiveClaim } from "./workspace-claim";
15
16
  import { isOwnerAlive, isOwnerProcessConfirmedGone, liveAgentCwds, worktreeInUseByLiveAgent } from "./workspace-merge";
16
17
  import { refResolvesInRepo, verifyLandedOrEquivalentContent } from "./services/landed-ancestry";
17
18
  import { TERMINAL_WORKSPACE_STATUSES } from "./workspace-phase";
18
- import type { Command, WorkspaceRecord } from "./types";
19
+ import type { Command, WorkspaceRecord, WorkspaceOrphan } from "./types";
19
20
 
20
21
  // Build a `workspace.cleanup` command for the worktree's owning orchestrator.
21
22
  // Moved here (from routes.ts) so the MCP surface reaches it without importing routes.
22
- export function buildWorkspaceCleanupCommand(
23
+ export async function buildWorkspaceCleanupCommand(
23
24
  workspace: WorkspaceRecord,
24
25
  requestedBy: string,
25
26
  opts: { force?: boolean; reason?: string; autoReclaim?: "origin-captured" } = {},
26
- ): { ok: true; command: Command } | { ok: false; status: number; error: string } {
27
+ ): Promise<{ ok: true; command: Command } | { ok: false; status: number; error: string }> {
27
28
  if (
28
29
  opts.force !== true &&
29
30
  workspace.mode === "isolated" &&
@@ -38,7 +39,7 @@ export function buildWorkspaceCleanupCommand(
38
39
  }
39
40
  const owner = workspaceOwnerOrchestrator(workspace);
40
41
  if (!owner) return { ok: false, status: 409, error: "no online orchestrator owns this workspace path; retry when the host is online or use DELETE /api/workspaces/:id to purge the record" };
41
- const command = createCommand({
42
+ const command = (await createCommandAsync({
42
43
  type: "workspace.cleanup",
43
44
  source: "system",
44
45
  target: owner.agentId,
@@ -58,7 +59,7 @@ export function buildWorkspaceCleanupCommand(
58
59
  ...(opts.autoReclaim === "origin-captured" ? { autoReclaim: "origin-captured" } : {}),
59
60
  queued: false,
60
61
  },
61
- });
62
+ }));
62
63
  return { ok: true, command };
63
64
  }
64
65
 
@@ -190,7 +191,7 @@ export async function cleanupStaleWorkspaces(opts: CleanupStaleWorkspacesOptions
190
191
  } else {
191
192
  // Owner re-confirmed offline just above; force past buildWorkspaceCleanupCommand's
192
193
  // live-owner guard and carry a reason so the host records an intentional force-discard.
193
- const built = buildWorkspaceCleanupCommand(ws, "cleanup-stale", forced ? { force: true, reason: "operator force-discard: abandoned branch, owner offline" } : {});
194
+ const built = (await buildWorkspaceCleanupCommand(ws, "cleanup-stale", forced ? { force: true, reason: "operator force-discard: abandoned branch, owner offline" } : {}));
194
195
  if (built.ok) {
195
196
  await updateWorkspaceStatusAsync(ws.id, "cleanup_requested", { lastWorkspaceAction: "cleanup-stale", lastWorkspaceActionAt: Date.now(), cleanupProof: { ...proof, forced } });
196
197
  emitCommandEvent(built.command, "command.requested");
@@ -229,3 +230,25 @@ export async function cleanupStaleWorkspaces(opts: CleanupStaleWorkspacesOptions
229
230
  }
230
231
  return { dryRun, landedOnly, force, repoRoot, ...(workspaceId ? { workspaceId } : {}), ...(workspaceIds ? { workspaceIds } : {}), scanned: candidates.length, eligible: rows.filter((r) => r.discardable).length, cleaned, candidates: rows };
231
232
  }
233
+
234
+ export async function dispatchOrphanCleanup(targetAgentId: string, orphan: WorkspaceOrphan): Promise<string> {
235
+ const command = (await createCommandAsync({
236
+ type: "workspace.cleanup",
237
+ source: "system",
238
+ target: targetAgentId,
239
+ params: {
240
+ action: "cleanup",
241
+ worktreePath: orphan.worktreePath,
242
+ repoRoot: orphan.repoRoot,
243
+ branch: orphan.branch,
244
+ baseRef: orphan.baseRef,
245
+ baseSha: orphan.baseSha,
246
+ deleteBranch: true,
247
+ reclaim: true,
248
+ requestedBy: "workspace-orphan-reaper",
249
+ requestedAt: Date.now(),
250
+ },
251
+ }));
252
+ emitCommandEvent(command, `command.${command.status}`);
253
+ return command.id;
254
+ }
@@ -1,9 +1,12 @@
1
+ import { DELEGATED_LAND_REFUSAL_CODE } from "@humwick/sdk/worktree-config";
2
+ import { refuseWorkspaceLand } from "./workspace-land-refusal";
3
+ import { releaseMergeLeaseAsync, insertLandGateAttestationAsync } from "./db/runtime-tail-async";
1
4
  import { commandFailureReason, settleWorkspaceCleanupCommand, type WorkspaceCommandSettleResult } from "./workspace-cleanup-settle";
2
5
  export { type WorkspaceCommandSettleResult } from "./workspace-cleanup-settle";
3
6
  import { fireAndForget, isRecord, sanitizeFsName, stringValue, type LandGateAttestation, type LandGateRunResult } from "@humwick/sdk";
4
7
  import { storeTextArtifact } from "./artifact-text";
5
8
  import { announceBranchLanded, notifyBaseWorktreeStrand, notifyBranchLandFailed, notifyLandGateFailed, notifyLandGateSkipped, notifyLandGateWarnings, recordLandingReceipt } from "./branch-landed";
6
- import { getWorkspace, getArtifactAsync, insertLandGateAttestation, listOrchestrators, markWorkspaceLanded, patchWorkspaceMetadataAsync, releaseMergeLease, setWorkspaceBranchAsync, updateWorkspaceStatusAsync, markWorkspaceLandedAsync} from "./db";
9
+ import { getWorkspace, getArtifactAsync, listOrchestrators, markWorkspaceLanded, patchWorkspaceMetadataAsync, setWorkspaceBranchAsync, updateWorkspaceStatusAsync, markWorkspaceLandedAsync } from "./db";
7
10
  import { parseOwnerRepoFromRemote, repoFromGitRemote } from "./services/git-remote";
8
11
  import { deferLandSettleSideEffect } from "./land-settle-dispatch";
9
12
  import { recordConfirmedLandBoundary } from "./services/land-boundary-settle";
@@ -205,7 +208,7 @@ export async function settleWorkspaceMergeCommand(command: Command, opts: Worksp
205
208
  command = proven;
206
209
  }
207
210
  const terminalSettled = WORKSPACE_MERGE_SETTLED_STATUSES.has(command.status);
208
- if (terminalSettled && command.landingContainmentMode === "legacy-unfenced-v0") releaseMergeLease({ commandId: command.id });
211
+ if (terminalSettled && command.landingContainmentMode === "legacy-unfenced-v0") (await releaseMergeLeaseAsync({ commandId: command.id }));
209
212
  const settledRepoRoot = typeof command.params.repoRoot === "string" ? command.params.repoRoot : undefined;
210
213
  const settledBaseRef = typeof command.params.baseRef === "string" ? command.params.baseRef : undefined;
211
214
  let transitionCompleted = false;
@@ -360,13 +363,13 @@ async function settleWorkspaceMergeCommandResult(command: Command, markTransitio
360
363
  if (retryableNonLand) {
361
364
  if (ancestryUnconfirmed && landedWorkspace) {
362
365
  const ws = transitioned ?? landedWorkspace;
363
- deferLandSettleSideEffect("land-unconfirmed", () => notifyLandUnconfirmed({ workspace: ws, commandId: command.id, sha: authoritativeLandedSha, targetRef: landTargetRef, kind: landAncestry }));
366
+ deferLandSettleSideEffect("land-unconfirmed", async () => await notifyLandUnconfirmed({ workspace: ws, commandId: command.id, sha: authoritativeLandedSha, targetRef: landTargetRef, kind: landAncestry }));
364
367
  }
365
368
  return { settled: true };
366
369
  }
367
370
  const noopBase = nothingBase ?? (mergeResult.noop === true && !resultError && mergeResult.landMechanism !== "plain-git" && (resultStatus === "merged" || resultStatus === "active") && typeof baseSha === "string" && /^[0-9a-f]{40,64}$/.test(baseSha) ? baseSha : undefined);
368
371
  if (noopBase && landedWorkspace) await finishWorkspaceStewardHandoff(landedWorkspace);
369
- if (noopBase && landedWorkspace) deferLandSettleSideEffect("nothing-to-land", () => notifyNothingToLand(landedWorkspace, noopBase, command.id, typeof command.params.expectedHeadSha === "string" ? command.params.expectedHeadSha : undefined));
372
+ if (noopBase && landedWorkspace) deferLandSettleSideEffect("nothing-to-land", async () => await notifyNothingToLand(landedWorkspace, noopBase, command.id, typeof command.params.expectedHeadSha === "string" ? command.params.expectedHeadSha : undefined));
370
373
  const landConfirmed = !nothingBase && workspaceMergeProvesLand(mergeResult, command.params);
371
374
  const continuationBranch = normalizedStatus === "active" ? landedWorkspace?.branch : undefined;
372
375
  // #1790 F1 — build the land notice up front so the durable RECEIPT can be written SYNCHRONOUSLY,
@@ -393,7 +396,7 @@ async function settleWorkspaceMergeCommandResult(command: Command, markTransitio
393
396
  ...(prLanded || landedCommitCount === undefined ? {} : { landedCommitCount }),
394
397
  }
395
398
  : undefined;
396
- if (landedNotice) recordLandingReceipt(landedNotice);
399
+ if (landedNotice) (await recordLandingReceipt(landedNotice));
397
400
  // #1744 F1 — record the tree-keyed land-gate attestation. Placed HERE, not at the executor, so
398
401
  // that "the full gate passed on tree T" only becomes deployable evidence once the relay has
399
402
  // CONFIRMED (ancestry-gated above, #1713) that T actually reached the base ref: a gated attempt
@@ -408,7 +411,7 @@ async function settleWorkspaceMergeCommandResult(command: Command, markTransitio
408
411
  const repo = landRepo(landedWorkspace.repoRoot);
409
412
  // No resolvable origin ⇒ no shared identity with cd-watcher's detection clone ⇒ no row.
410
413
  if (repo) {
411
- insertLandGateAttestation({
414
+ (await insertLandGateAttestationAsync({
412
415
  repo,
413
416
  treeSha: attestation.treeSha,
414
417
  commitSha: authoritativeLandedSha,
@@ -419,7 +422,7 @@ async function settleWorkspaceMergeCommandResult(command: Command, markTransitio
419
422
  gatesRan: attestation.gatesRan,
420
423
  workspaceId: landedWorkspace.id,
421
424
  ...(attestation.suiteCoverage ? { suiteCoverage: attestation.suiteCoverage } : {}),
422
- });
425
+ }));
423
426
  }
424
427
  } catch (error) {
425
428
  console.warn(`[land-gate-attestation] failed to record tree ${attestation.treeSha.slice(0, 12)} for ${workspaceId}: ${String(error)}`);
@@ -439,7 +442,7 @@ async function settleWorkspaceMergeCommandResult(command: Command, markTransitio
439
442
  preservedWipPaths: Array.isArray(baseWorktreeSync.preservedWipPaths) ? baseWorktreeSync.preservedWipPaths.filter((p): p is string => typeof p === "string") : undefined,
440
443
  message: typeof baseWorktreeSync.message === "string" ? baseWorktreeSync.message : undefined,
441
444
  };
442
- deferLandSettleSideEffect("base-worktree-strand", () => notifyBaseWorktreeStrand({ workspace: ws, sync: strandSync }));
445
+ deferLandSettleSideEffect("base-worktree-strand", async () => await notifyBaseWorktreeStrand({ workspace: ws, sync: strandSync }));
443
446
  }
444
447
  // #1713 — reaching here means the land is either ancestry-CONFIRMED, a remote-verified PR land, or
445
448
  // a proven zero-commit no-op (handled inside announceBranchLanded, #1620); an unconfirmed
@@ -450,7 +453,7 @@ async function settleWorkspaceMergeCommandResult(command: Command, markTransitio
450
453
  // i.e. the serialized writes this issue is about — so it runs off the settle hot path.
451
454
  if (landedNotice) {
452
455
  const notice = landedNotice;
453
- deferLandSettleSideEffect("branch-landed", () => announceBranchLanded(notice));
456
+ deferLandSettleSideEffect("branch-landed", async () => await announceBranchLanded(notice));
454
457
  }
455
458
  const gateSkipped = normalizeGateSkipped(mergeResult.gateSkipped);
456
459
  if (gateSkipped && landedWorkspace) {
@@ -462,7 +465,7 @@ async function settleWorkspaceMergeCommandResult(command: Command, markTransitio
462
465
  },
463
466
  });
464
467
  const ws = landedWorkspace;
465
- deferLandSettleSideEffect("land-gate-skipped", () => notifyLandGateSkipped({ workspace: ws, ...gateSkipped }));
468
+ deferLandSettleSideEffect("land-gate-skipped", async () => await notifyLandGateSkipped({ workspace: ws, ...gateSkipped }));
466
469
  }
467
470
  const gateWarnings = mergeResult.merged === true ? normalizeGateWarnings(mergeResult.gateWarnings) : [];
468
471
  if (gateWarnings.length && landedWorkspace) {
@@ -500,7 +503,7 @@ async function settleWorkspaceMergeCommandResult(command: Command, markTransitio
500
503
  console.warn(`land-gate-warnings artifact upload failed for ${warnWorkspace.id}: ${String(error)}`);
501
504
  }
502
505
  try {
503
- notifyLandGateWarnings({ workspace: warnWorkspace, warnings: gateWarnings, artifactId, fullOutput: !anyTruncated });
506
+ await notifyLandGateWarnings({ workspace: warnWorkspace, warnings: gateWarnings, artifactId, fullOutput: !anyTruncated });
504
507
  } catch (error) {
505
508
  console.warn(`land-gate-warnings notify threw for ${warnWorkspace.id}: ${String(error)}`);
506
509
  }
@@ -537,6 +540,11 @@ async function settleWorkspaceMergeCommandResult(command: Command, markTransitio
537
540
  if (await settleRestartKilledLand(command, current)) markTransitionCompleted();
538
541
  return { settled: true };
539
542
  }
543
+ if (!alreadyLanded && isRecord(command.result) && command.result.landingBlockerCode === DELEGATED_LAND_REFUSAL_CODE) {
544
+ await refuseWorkspaceLand(current, reason, command.id);
545
+ markTransitionCompleted();
546
+ return { settled: true };
547
+ }
540
548
  const transitioned = await updateWorkspaceStatusAsync(command.correlationId, nextStatus, {
541
549
  mergeCommandId: command.id,
542
550
  landGateQueue: undefined,
@@ -553,12 +561,12 @@ async function settleWorkspaceMergeCommandResult(command: Command, markTransitio
553
561
  // announcements off it, so they run off the settle hot path (same as the success path's fan-out).
554
562
  if (nextStatus === "conflict" && !alreadyLanded) {
555
563
  // #2704 — the settle is the one conflict entry that never woke a steward (case A): give it its resolver.
556
- deferLandSettleSideEffect("land-conflict-resolver", () => superviseLandConflictLater(current.id, reason, landedHead ? { tip: landedHead } : {}));
557
- deferLandSettleSideEffect("land-conflict-semantic", () => emitWorkspaceTaskSemanticNotifications({
564
+ deferLandSettleSideEffect("land-conflict-semantic", async () => await emitWorkspaceTaskSemanticNotifications({
558
565
  workspace: current, transition: "land-conflict", actor: "workspace-merge",
559
566
  idempotencyKey: landFailureEventKey(current, command.id),
560
567
  outcome: { reason, commandId: command.id, status: nextStatus },
561
568
  }));
569
+ deferLandSettleSideEffect("land-conflict-resolver", () => superviseLandConflictLater(current.id, reason, landedHead ? { tip: landedHead } : {}));
562
570
  }
563
571
  if (gateFailure) {
564
572
  const gateFailedAt = Date.now();
@@ -572,9 +580,9 @@ async function settleWorkspaceMergeCommandResult(command: Command, markTransitio
572
580
  });
573
581
  } else if (!alreadyLanded && nextStatus !== "conflict") {
574
582
  // A conflict's owner hears from its resolver instead: the steward hand-off, or the hand-back (#2704).
575
- deferLandSettleSideEffect("land-failed", () => {
576
- notifyBranchLandFailed({ workspace: current, commandId: command.id, reason });
577
- notifyLandUnconfirmed({ workspace: current, commandId: command.id, targetRef: current.baseRef ?? "main", kind: "merge-failed", detail: reason });
583
+ deferLandSettleSideEffect("land-failed", async () => {
584
+ await notifyBranchLandFailed({ workspace: current, commandId: command.id, reason });
585
+ await notifyLandUnconfirmed({ workspace: current, commandId: command.id, targetRef: current.baseRef ?? "main", kind: "merge-failed", detail: reason });
578
586
  });
579
587
  }
580
588
  return { settled: true };
@@ -3,5 +3,5 @@ import type { WorkspaceConfig } from "@humwick/sdk";
3
3
  // Single source for the isolated-worktree symlink default (config-store + settings registry).
4
4
  // Only the untracked rig config is linked; AGENTS.md is tracked (#3516), so a worktree gets it from git.
5
5
  export const WORKSPACE_CONFIG_DEFAULTS: WorkspaceConfig = {
6
- symlinkPaths: [".claude-rig"],
6
+ symlinkPaths: [],
7
7
  };
@@ -81,7 +81,8 @@ async function withdrawArmedLand(ws: WorkspaceRecord, reason: string): Promise<"
81
81
  export async function handBackLandConflict(ws: WorkspaceRecord, now: number, why: string): Promise<ConflictHandback> {
82
82
  const meta = ws.metadata as Record<string, unknown>;
83
83
  if (conflictHandedBackForArm(meta)) return "skipped";
84
- const instructions = handbackInstructions(ws, why);
84
+ const cause = typeof meta.mergeError === "string" ? meta.mergeError : undefined;
85
+ const instructions = handbackInstructions(ws, cause && !why.includes(cause) ? `${why}: ${cause}` : why);
85
86
  const withdrawn = await withdrawArmedLand(ws, instructions);
86
87
  // The steward's shutdown fences the row out of every other lane until it settles: the sweep
87
88
  // retries this pending hand-back (workspace-steward-watchdog.ts), never the steward path.
@@ -106,7 +107,7 @@ export async function handBackLandConflict(ws: WorkspaceRecord, now: number, why
106
107
  // One notice per recipient: it also wakes the owner, so no separate `landed-failure` (whose per-arm key
107
108
  // the land-conflict Task notice already holds). A notify failure falls through to the operator alarm.
108
109
  try {
109
- routeNotification({
110
+ await routeNotification({
110
111
  type: "workspace.stranded_escalation", forceDelivery: true, ttlMs: null,
111
112
  scope: { workspaceId: ws.id, repoRoot: ws.repoRoot, author: ws.ownerAgentId, parent: coordinator ?? undefined },
112
113
  recipients,
@@ -130,14 +131,14 @@ export async function handBackLandConflict(ws: WorkspaceRecord, now: number, why
130
131
  }
131
132
  }
132
133
 
133
- raiseOperatorAlarm({
134
+ (await raiseOperatorAlarm({
134
135
  clientId: `steward-handoff-unescalatable-${ws.id}:${strandKey}`,
135
136
  source: "workspace-steward-handoff-watchdog",
136
137
  subject: "Land conflict has no one to hand it back to",
137
138
  detail: `${branchLabel} in ${ws.repoRoot} has an unresolved land conflict and no owner, coordinator, or fallback to hand it back to (${why}). Configure AGENT_RELAY_WORKSPACE_STEWARD_FALLBACK or land/reclaim the worktree manually.`,
138
139
  view: "orchestrators",
139
140
  metadata: { maintenanceJobId: "workspace-steward-handoff-watchdog", workspaceId: ws.id, repoRoot: ws.repoRoot, branch: ws.branch, reason: why },
140
- });
141
+ }));
141
142
  await transitionWorkspaceLandStateAsync(ws.id, "merge-error", { stewardHandoffEscalatedAt: now, stewardUnavailable: true, conflictHandbackPending: undefined, ...stewardEnded });
142
143
  if (withdrawn === "none") await finishWorkspaceStewardHandoff(ws);
143
144
  await createActivityEventAsync({
@@ -167,14 +168,15 @@ export async function superviseLandConflict(ws: WorkspaceRecord, reason: string,
167
168
 
168
169
  const inFlight = new Set<Promise<unknown>>();
169
170
 
170
- /** Fire-and-forget form for settle paths that must not await the wake (#1790). */
171
- export function superviseLandConflictLater(workspaceId: string, reason: string, opts: { tip?: string } = {}): void {
171
+ /** Track the wake so deferred settle queues can drain its committed effects (#1790/#1870). */
172
+ export function superviseLandConflictLater(workspaceId: string, reason: string, opts: { tip?: string } = {}): Promise<void> {
172
173
  const ws = getWorkspace(workspaceId);
173
- if (!ws) return;
174
+ if (!ws) return Promise.resolve();
174
175
  const run = superviseLandConflict(ws, reason, opts)
175
176
  .catch((error) => console.warn(`[workspace-conflict-resolver] supervising ${workspaceId} failed; the hand-off watchdog retries: ${errMessage(error)}`))
176
177
  .finally(() => inFlight.delete(run));
177
178
  inFlight.add(run);
179
+ return run.then(() => {});
178
180
  }
179
181
 
180
182
  export async function settleConflictSupervisionForTests(): Promise<void> {
@@ -1,19 +1,20 @@
1
+ import { createCommandAsync } from "./commands-write";
1
2
  // Host-bound rescue for an unpushed dead-owner workspace. Kept separate from
2
3
  // the orphan sweep so command construction remains reusable without inflating
3
4
  // the disk⇄DB reconciler.
4
5
  import type { WorkspaceRecord } from "./types";
5
- import { createCommand } from "./commands-db";
6
+
6
7
  import { emitCommandEvent } from "./command-events";
7
8
 
8
- export function dispatchDeadOwnerRescue(orch: { agentId: string }, workspace: WorkspaceRecord): string {
9
- const command = createCommand({
9
+ export async function dispatchDeadOwnerRescue(orch: { agentId: string }, workspace: WorkspaceRecord): Promise<string> {
10
+ const command = (await createCommandAsync({
10
11
  type: "workspace.reconcile", source: "system", target: orch.agentId, correlationId: workspace.id,
11
12
  params: {
12
13
  action: "reconcile", workspaceId: workspace.id, repoRoot: workspace.repoRoot,
13
14
  worktreePath: workspace.worktreePath, branch: workspace.branch, baseRef: workspace.baseRef,
14
15
  baseSha: workspace.baseSha, autoReclaim: "dead-owner", requestedBy: "workspace-dead-owner-reaper", requestedAt: Date.now(),
15
16
  },
16
- });
17
+ }));
17
18
  emitCommandEvent(command, `command.${command.status}`);
18
19
  return command.id;
19
20
  }