@humwick/server 0.130.0 → 0.130.2

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 (486) hide show
  1. package/README.md +5 -0
  2. package/docs/guides/tools-administration.md +6 -1
  3. package/docs/guides/tools-coordination.md +1 -0
  4. package/docs/guides/tools-tasks.md +8 -0
  5. package/docs/guides/workflows.md +58 -0
  6. package/docs/openapi.json +414 -1
  7. package/package.json +8 -17
  8. package/public/assets/{MessageBubble-BWpoBjl4.js → MessageBubble-BWLqMGKG.js} +2 -2
  9. package/public/assets/{PlanGraphPanel-C0auck3n.js → PlanGraphPanel-3TlIQpjk.js} +2 -2
  10. package/public/assets/{TraceView-DBnOx7AQ.js → TraceView-Wimm0Czv.js} +2 -2
  11. package/public/assets/{VaultDecisionCard-0kp2oNBC.js → VaultDecisionCard-Bau_vNax.js} +2 -2
  12. package/public/assets/{activity-yLztXEBt.js → activity-CrSurn-r.js} +2 -2
  13. package/public/assets/{agent-lineage-BbJDR1dW.js → agent-lineage-CknAJKcb.js} +2 -2
  14. package/public/assets/agent-liveness-CaNwK0Zf.js +2 -0
  15. package/public/assets/{agent-name-CTZBrSD9.js → agent-name-DKbiIhBo.js} +2 -2
  16. package/public/assets/agent-profiles-DwF6EQ4R.js +2 -0
  17. package/public/assets/{agent-project-badge-9TqzUUYE.js → agent-project-badge-Diz4Sjjb.js} +2 -2
  18. package/public/assets/{agent-tools-D4n40pn8.js → agent-tools-CRhpRQza.js} +2 -2
  19. package/public/assets/{agent-type-icon-D6FUarOf.js → agent-type-icon-LrUEU3lB.js} +2 -2
  20. package/public/assets/{agents-BYDslkJc.js → agents-B-v66C-4.js} +2 -2
  21. package/public/assets/{analytics-B-XSbEMC.js → analytics-BqCb-LKi.js} +2 -2
  22. package/public/assets/{artifact-viewer-DdWIfV6M.js → artifact-viewer-kf4pGuAR.js} +2 -2
  23. package/public/assets/{artifacts-oBOqks-2.js → artifacts-D32zyw4Y.js} +2 -2
  24. package/public/assets/{artifacts-DPN1q4pA.js → artifacts-DJevXcvg.js} +2 -2
  25. package/public/assets/{automation-4KcRFXEu.js → automation-BpRajx_5.js} +2 -2
  26. package/public/assets/{backlog-Cw9xPTCF.js → backlog-D_UjTdzX.js} +2 -2
  27. package/public/assets/{busy-health-CTu32MZt.js → busy-health-N3VEh4ao.js} +2 -2
  28. package/public/assets/{channels-BiXzg1G9.js → channels-9jopungq.js} +2 -2
  29. package/public/assets/{chat-Ctk2qwvA.js → chat-CSXrTB3C.js} +2 -2
  30. package/public/assets/{code-preview-Bm1wWqAp.js → code-preview-p1NnmqK0.js} +2 -2
  31. package/public/assets/{connectors-C36ax4Vw.js → connectors-CZdqlDNL.js} +2 -2
  32. package/public/assets/{cosmos-Jj9LK2Wf.js → cosmos-BgdsE4dG.js} +2 -2
  33. package/public/assets/{crate-agent-H6S7-B9T.js → crate-agent-30aXTKva.js} +2 -2
  34. package/public/assets/{dependency-graph-Cd1E23wa.js → dependency-graph-B_jvw2GE.js} +2 -2
  35. package/public/assets/{deploys-Bwfq146q.js → deploys-DoN6bAb5.js} +2 -2
  36. package/public/assets/{display-CfO7rTuF.js → display-BrKWFGJz.js} +2 -2
  37. package/public/assets/{files-DhhZI2Ih.js → files-D6XEu8Ng.js} +2 -2
  38. package/public/assets/fleet-C7jQWbw2.js +2 -0
  39. package/public/assets/{fleet-metrics-BkHP-P3R.js → fleet-metrics-BiDs3MLx.js} +2 -2
  40. package/public/assets/{formatted-body-Cm1RrzmN.js → formatted-body-CQBwc1fb.js} +3 -3
  41. package/public/assets/{formatted-body-impl-DQiOuOD1.js → formatted-body-impl-DyG0WsQS.js} +2 -2
  42. package/public/assets/{host-providers-dialog-CHqwXTov.js → host-providers-dialog-DKaW31dN.js} +2 -2
  43. package/public/assets/index-CRHep3M9.js +15 -0
  44. package/public/assets/index-MYAIwYTX.css +2 -0
  45. package/public/assets/{insights-fH1EL-qZ.js → insights-CzrtkpOE.js} +2 -2
  46. package/public/assets/{integrations-C5Oix6ng.js → integrations-aVsUmigt.js} +2 -2
  47. package/public/assets/{issue-ref-chip-ODyondIa.js → issue-ref-chip-BnSlM_95.js} +2 -2
  48. package/public/assets/{log-viewer-Cvfy6PW7.js → log-viewer-qe7Ee47Z.js} +2 -2
  49. package/public/assets/{maintenance-D8CDH5wZ.js → maintenance-NfjqFZAk.js} +2 -2
  50. package/public/assets/{managed-agents-egllbpij.js → managed-agents-BiH0HgaE.js} +2 -2
  51. package/public/assets/{markdown-preview-CYSFgVgK.js → markdown-preview-BixaT3Xr.js} +3 -3
  52. package/public/assets/{markdown-preview-impl-BteVIjX4.js → markdown-preview-impl-DNGlWIS3.js} +2 -2
  53. package/public/assets/{memory-C8WmXsyr.js → memory-DNsCl6UX.js} +2 -2
  54. package/public/assets/{messages-BzQdqlO6.js → messages-DopU1L1X.js} +2 -2
  55. package/public/assets/{orchestrators-B1HxzkNw.js → orchestrators-Cq7ckLQT.js} +2 -2
  56. package/public/assets/{overview-DCUnI4Z7.js → overview-C1DCTzzV.js} +2 -2
  57. package/public/assets/{pairs-ftCd2XcD.js → pairs-DE_m6rrE.js} +2 -2
  58. package/public/assets/{profile-icon-B2zH8DMH.js → profile-icon-B3rfh77F.js} +2 -2
  59. package/public/assets/project-profile-instructions-DQWZE0kA.js +2 -0
  60. package/public/assets/projects-Br2Bd2h1.js +2 -0
  61. package/public/assets/{prompt-settings-Bftq9czX.js → prompt-settings-BKvFsvGD.js} +2 -2
  62. package/public/assets/provider-display-DsuWMvVL.js +2 -0
  63. package/public/assets/{registry-DWCU5c8q.js → registry-Cw38_6gW.js} +2 -2
  64. package/public/assets/run-card-CpKqRbhg.js +2 -0
  65. package/public/assets/scroll-text-BKXS1ahr.js +2 -0
  66. package/public/assets/{secrets-C7GIUATz.js → secrets-DxI-vzSq.js} +2 -2
  67. package/public/assets/{service-access-settings-C3aujqTG.js → service-access-settings-D9s_VJbd.js} +2 -2
  68. package/public/assets/{settings-C6sZ9eBa.js → settings-CKZTVGIx.js} +2 -2
  69. package/public/assets/{shipping-Bu8p1gEw.js → shipping-B9YtnwtG.js} +2 -2
  70. package/public/assets/{stats-V9Z-GxUd.js → stats-DyUBKyWI.js} +2 -2
  71. package/public/assets/{status-dot-CVv0iGHL.js → status-dot-DYqlEUhJ.js} +2 -2
  72. package/public/assets/{store-BvtFdlGX.js → store-DcClXLH0.js} +3 -3
  73. package/public/assets/{tasks-CXU75HRF.js → tasks-Bh7Chr4-.js} +2 -2
  74. package/public/assets/{teams-BPf976zb.js → teams-bowI7qVY.js} +2 -2
  75. package/public/assets/{terminal-viewer-DE9BOe-8.js → terminal-viewer-BgVLHdsU.js} +3 -3
  76. package/public/assets/{terminal-viewer-impl-D04pjmGh.js → terminal-viewer-impl-Dz22UPy6.js} +2 -2
  77. package/public/assets/token-estimate-Co-Jdphh.js +2 -0
  78. package/public/assets/{use-agent-terminal-B1yR456R.js → use-agent-terminal-DSQQ-iY7.js} +2 -2
  79. package/public/assets/{use-decisions-D-S4tpDf.js → use-decisions-samMQhQf.js} +2 -2
  80. package/public/assets/use-project-list-59LheVP7.js +2 -0
  81. package/public/assets/{use-selectors-CnrAk2YP.js → use-selectors-BZa25xEB.js} +2 -2
  82. package/public/assets/{user-avatar-nBFIcR4M.js → user-avatar-DHxlvUvV.js} +2 -2
  83. package/public/assets/versioned-prompt-editor-BmED5DnJ.js +8 -0
  84. package/public/assets/{work-queue-TCjJxeT-.js → work-queue-CSvpuNLz.js} +2 -2
  85. package/public/assets/{workflow-marker-Cf3Hf2fN.js → workflow-marker-DAZcj5qt.js} +2 -2
  86. package/public/assets/{workflows-CXQX20Qj.js → workflows-DdmxRSyg.js} +2 -2
  87. package/public/assets/{workspaces-qSYzKYMA.js → workspaces-BxeKfVuF.js} +2 -2
  88. package/public/cosmos.html +4 -4
  89. package/public/index.html +31 -29
  90. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  91. package/runner/plugins/claude/hooks/gate-run-guard.provisioned.mjs +31 -1
  92. package/runner/src/adapters/claude-effort.ts +2 -4
  93. package/runner/src/adapters/codex-launch-config.ts +4 -5
  94. package/runner/src/adapters/codex.ts +1 -1
  95. package/runner/src/adapters/opencode-provider.ts +7 -22
  96. package/runner/src/adapters/opencode.ts +4 -4
  97. package/runner/src/agent-runner/credentials.ts +42 -12
  98. package/runner/src/agent-runner/inbox.ts +27 -0
  99. package/runner/src/agent-runner/lifecycle-milestones.ts +0 -2
  100. package/runner/src/bin/claude.ts +4 -0
  101. package/runner/src/bin/codex.ts +4 -0
  102. package/runner/src/bin/opencode.ts +4 -0
  103. package/runner/src/index.ts +5 -2
  104. package/runner/src/provider-setup.ts +34 -0
  105. package/runner/src/providers.ts +2 -1
  106. package/runner/src/runner-core.ts +18 -23
  107. package/runner/src/spawn-input.ts +2 -1
  108. package/runner/src/test-run-dedup.ts +59 -56
  109. package/scripts/cd-config.ts +24 -3
  110. package/scripts/gate-run-lease.ts +10 -7
  111. package/scripts/gate.sh +5 -1
  112. package/src/branch-land-notice.ts +93 -0
  113. package/src/branch-landed.ts +7 -76
  114. package/src/bus.ts +19 -20
  115. package/src/cd-deploy-notify.ts +30 -2
  116. package/src/cd-host-lag-notify.ts +7 -6
  117. package/src/ci/incidents.ts +2 -2
  118. package/src/ci/monitor.ts +5 -8
  119. package/src/ci/root-missing.ts +2 -7
  120. package/src/ci/transition-notify.ts +7 -39
  121. package/src/cli/cd-pauses.ts +19 -0
  122. package/src/cli/orchestrator.ts +1 -1
  123. package/src/cli/state.ts +2 -19
  124. package/src/cli/task-edit.ts +22 -0
  125. package/src/cli/task.ts +3 -1
  126. package/src/cli/workflow.ts +8 -2
  127. package/src/commands-db.ts +10 -6
  128. package/src/commands-write.ts +8 -0
  129. package/src/config-store-write.ts +13 -1
  130. package/src/config-store.ts +25 -14
  131. package/src/db/activity-async.ts +6 -1
  132. package/src/db/activity-write-ops.ts +13 -1
  133. package/src/db/activity.ts +1 -14
  134. package/src/db/agent-lifecycle-write-ops.ts +1 -0
  135. package/src/db/agent-meta.ts +2 -2
  136. package/src/db/agent-ownership-write-ops.ts +4 -0
  137. package/src/db/agent-search.ts +1 -15
  138. package/src/db/agents-async.ts +58 -7
  139. package/src/db/agents-write-ops.ts +28 -5
  140. package/src/db/agents.ts +81 -54
  141. package/src/db/artifacts-write-ops.ts +8 -3
  142. package/src/db/bus-outbox-write-ops.ts +1 -0
  143. package/src/db/channels-write-ops.ts +4 -0
  144. package/src/db/ci-incidents-async.ts +5 -5
  145. package/src/db/ci-incidents-write-ops.ts +2 -2
  146. package/src/db/claude-api-budget-ops.ts +5 -5
  147. package/src/db/claude-app-oauth.ts +4 -4
  148. package/src/db/codex-reset-consumes-write-ops.ts +3 -0
  149. package/src/db/command-row.ts +10 -2
  150. package/src/db/commands-list-query.ts +2 -0
  151. package/src/db/commands-spawn-read.ts +1 -1
  152. package/src/db/commands-write-ops.ts +21 -0
  153. package/src/db/config-store-write-ops.ts +9 -2
  154. package/src/db/continuation-archives-async.ts +5 -0
  155. package/src/db/continuation-archives-write-ops.ts +9 -0
  156. package/src/db/continuations.ts +2 -2
  157. package/src/db/db-writer-worker.ts +8 -1
  158. package/src/db/delivery-write-ops.ts +5 -0
  159. package/src/db/deploy-events-async.ts +1 -0
  160. package/src/db/deploy-events-read-ops.ts +2 -1
  161. package/src/db/deploy-events.ts +35 -4
  162. package/src/db/hosts-registration.ts +10 -2
  163. package/src/db/hosts-write-ops.ts +14 -0
  164. package/src/db/hosts.ts +9 -6
  165. package/src/db/inbox-write-ops.ts +4 -0
  166. package/src/db/inbox.ts +0 -14
  167. package/src/db/index.ts +2 -0
  168. package/src/db/insights-write-ops.ts +1 -0
  169. package/src/db/integrations-async.ts +8 -0
  170. package/src/db/integrations-ops.ts +15 -0
  171. package/src/db/integrations.ts +15 -21
  172. package/src/db/issue-lifecycle.ts +3 -4
  173. package/src/db/issue-refs-async.ts +20 -0
  174. package/src/db/issue-refs-write-ops.ts +29 -0
  175. package/src/db/issue-refs.ts +7 -8
  176. package/src/db/long-running-work.ts +2 -2
  177. package/src/db/macos-privacy.ts +1 -1
  178. package/src/db/main-connection-writes.ts +23 -2
  179. package/src/db/maintenance-job-reconcile.ts +61 -0
  180. package/src/db/maintenance-job-runs-async.ts +14 -0
  181. package/src/db/maintenance-job-write-ops.ts +9 -0
  182. package/src/db/mappers.ts +2 -14
  183. package/src/db/merge-lease.ts +1 -15
  184. package/src/db/message-reads-write-ops.ts +3 -0
  185. package/src/db/message-write-ops.ts +4 -0
  186. package/src/db/migrations.ts +7 -15
  187. package/src/db/orchestrators-async.ts +7 -3
  188. package/src/db/orchestrators-write-ops.ts +7 -1
  189. package/src/db/orchestrators.ts +21 -77
  190. package/src/db/pairs.ts +1 -13
  191. package/src/db/project-profile-instructions.ts +50 -0
  192. package/src/db/prompt-versions-ops.ts +1 -0
  193. package/src/db/prompt-versions.ts +9 -2
  194. package/src/db/provider-catalog-write-ops.ts +4 -4
  195. package/src/db/provider-config-history.ts +8 -3
  196. package/src/db/provider-flap-messages-write-ops.ts +1 -0
  197. package/src/db/provider-model-seed.ts +34 -0
  198. package/src/db/provider-quota-lease-write-ops.ts +1 -0
  199. package/src/db/provider-quota-write-ops.ts +2 -0
  200. package/src/db/provisioning-write-ops.ts +9 -8
  201. package/src/db/read-op-marshaling-fixtures.ts +5 -0
  202. package/src/db/read-ops.ts +4 -0
  203. package/src/db/routing-policy.ts +3 -4
  204. package/src/db/schema.ts +9 -3
  205. package/src/db/secrets-broker-write-ops.ts +5 -5
  206. package/src/db/secrets-vault-write.ts +7 -7
  207. package/src/db/services-write-ops.ts +3 -0
  208. package/src/db/spawn-delegation-state.ts +11 -4
  209. package/src/db/spawn-tree-cleanup.ts +3 -0
  210. package/src/db/stats-async.ts +4 -3
  211. package/src/db/task-entity.ts +23 -2
  212. package/src/db/task-list.ts +3 -1
  213. package/src/db/tasks.ts +1 -17
  214. package/src/db/team-spawn-delegation.ts +1 -1
  215. package/src/db/teams-write-ops.ts +4 -4
  216. package/src/db/timer-cutover-write-ops.ts +7 -0
  217. package/src/db/timer-ingress-write-ops.ts +9 -0
  218. package/src/db/timer-ingress.ts +7 -1
  219. package/src/db/timer-operator-write-ops.ts +14 -0
  220. package/src/db/timer-transfer-write-ops.ts +4 -0
  221. package/src/db/timer-write-ops.ts +14 -0
  222. package/src/db/token-db-write-ops.ts +21 -0
  223. package/src/db/token-standing.ts +15 -11
  224. package/src/db/user-settings-write-ops.ts +1 -0
  225. package/src/db/vault-backup.ts +2 -2
  226. package/src/db/vault-expiry.ts +2 -2
  227. package/src/db/vault-health.ts +3 -3
  228. package/src/db/vault-token-ops.ts +8 -8
  229. package/src/db/web-tool-call-ops.ts +3 -3
  230. package/src/db/workflow-contact.ts +1 -1
  231. package/src/db/workflow-task-read-ops.ts +30 -0
  232. package/src/db/write-ops.ts +15 -1
  233. package/src/db/writer-fault-seam.ts +5 -2
  234. package/src/db/writer-gateway.ts +21 -12
  235. package/src/dispatch-availability.ts +10 -6
  236. package/src/ephemeral/{landing-ingress-proof-worker.ts → landing-ingress-proof.test-fixture.ts} +4 -2
  237. package/src/host/disk-alert.ts +121 -0
  238. package/src/lifecycle-manager.ts +3 -2
  239. package/src/maintenance/cd-watcher.ts +3 -3
  240. package/src/maintenance/critical-job-watchdog.ts +16 -17
  241. package/src/maintenance/index.ts +1 -0
  242. package/src/maintenance/jobs.ts +3 -2
  243. package/src/maintenance/scheduler.ts +84 -128
  244. package/src/maintenance/stalled-delivery-pager.ts +6 -5
  245. package/src/maintenance/workspaces.ts +1 -1
  246. package/src/managed-policy.ts +31 -27
  247. package/src/mcp/index.ts +5 -2
  248. package/src/mcp/output-descriptions.ts +8 -8
  249. package/src/mcp/presentation.ts +4 -4
  250. package/src/mcp/project-profile-instructions.ts +32 -0
  251. package/src/mcp/tool-groups.ts +1 -1
  252. package/src/mcp/tools-spawn.ts +4 -3
  253. package/src/mcp-agent-action.ts +1 -2
  254. package/src/mcp-host-tools.ts +1 -1
  255. package/src/mcp-issue-ref-tools.ts +12 -11
  256. package/src/mcp-maintenance-tools.ts +2 -2
  257. package/src/mcp-profile-trust-tools.ts +4 -4
  258. package/src/mcp-provider-catalog.ts +2 -2
  259. package/src/mcp-task-tools.ts +11 -5
  260. package/src/mcp-team-template-tools.ts +3 -3
  261. package/src/mcp-workflow-tools.ts +10 -3
  262. package/src/notification-types.ts +2 -1
  263. package/src/operator-alarm.ts +26 -11
  264. package/src/package-pack.ts +42 -39
  265. package/src/project-instructions.ts +4 -0
  266. package/src/project-profile-instruction-text.ts +6 -0
  267. package/src/project-profile-instructions.ts +20 -0
  268. package/src/provider-catalog-store.ts +3 -49
  269. package/src/provider-config-store.ts +12 -11
  270. package/src/provider-model-seed.ts +1 -18
  271. package/src/provider-quota-config-store.ts +5 -4
  272. package/src/provider-secrets.test-fixture.ts +3 -3
  273. package/src/recipe-runner.ts +2 -2
  274. package/src/repo-config-source.ts +10 -4
  275. package/src/routes/agent-profiles.ts +6 -6
  276. package/src/routes/agents-spawn.ts +1 -1
  277. package/src/routes/agents.ts +6 -6
  278. package/src/routes/commands-listing.ts +4 -0
  279. package/src/routes/commands.ts +2 -2
  280. package/src/routes/continuation-archives.ts +2 -2
  281. package/src/routes/host-resource-control.ts +4 -1
  282. package/src/routes/index.ts +10 -1
  283. package/src/routes/integrations.ts +24 -50
  284. package/src/routes/issue-refs.ts +7 -7
  285. package/src/routes/orchestrator-bootstrap.ts +3 -3
  286. package/src/routes/orchestrator-host-registration.ts +2 -2
  287. package/src/routes/orchestrator-host-utilization.ts +3 -1
  288. package/src/routes/orchestrator-proxy.ts +2 -2
  289. package/src/routes/orchestrator.ts +4 -4
  290. package/src/routes/project-profile-instructions.ts +27 -0
  291. package/src/routes/project-trust.ts +2 -2
  292. package/src/routes/provider-config.ts +9 -8
  293. package/src/routes/provider-quota-config.ts +2 -2
  294. package/src/routes/settings.ts +5 -5
  295. package/src/routes/stats.ts +6 -6
  296. package/src/routes/task-http.ts +15 -1
  297. package/src/routes/task-issues.ts +11 -26
  298. package/src/routes/tasks.ts +22 -53
  299. package/src/routes/team-templates.ts +5 -5
  300. package/src/routes/teams-config.ts +2 -2
  301. package/src/routes/tokens.ts +12 -5
  302. package/src/routes/workflows.ts +20 -5
  303. package/src/routing-policy-normalize.ts +1 -2
  304. package/src/routing-step-defaults.ts +0 -2
  305. package/src/runner-token-mint-limit.ts +63 -0
  306. package/src/runtime-grant.ts +4 -2
  307. package/src/runtime-tokens.ts +50 -9
  308. package/src/security.ts +13 -20
  309. package/src/server-background.ts +1 -1
  310. package/src/server.ts +5 -2
  311. package/src/services/host-utilization.ts +23 -0
  312. package/src/services/idle-epics.ts +5 -6
  313. package/src/services/issue-lifecycle.ts +57 -61
  314. package/src/services/issue-refs.ts +9 -13
  315. package/src/services/kernel-timers-cutover-chaos-worker.ts +12 -7
  316. package/src/services/kernel-timers-ingress.ts +1 -1
  317. package/src/services/kernel-timers-request-key-migration-chaos-worker.ts +4 -1
  318. package/src/services/landed-ancestry.ts +19 -3
  319. package/src/services/memory-areas.ts +15 -51
  320. package/src/services/plan-ci-notice.ts +57 -0
  321. package/src/services/plan-ci-recovery.ts +2 -55
  322. package/src/services/plan-wake-digest.ts +1 -0
  323. package/src/services/profile-trust.ts +4 -3
  324. package/src/services/project-config-read.ts +70 -0
  325. package/src/services/project-profile-instructions.ts +54 -0
  326. package/src/services/provisioning-harness/budget-baseline.json +4 -4
  327. package/src/services/restart-spawn.ts +61 -49
  328. package/src/services/self-care-state.ts +2 -1
  329. package/src/services/self-effort.ts +5 -5
  330. package/src/services/send-message.ts +5 -1
  331. package/src/services/spawn-agent.ts +13 -2
  332. package/src/services/spawn-chain-inspector.ts +6 -13
  333. package/src/services/spawn-policy.ts +68 -0
  334. package/src/services/spawn-tree-cleanup.ts +2 -2
  335. package/src/services/task-dispatch.ts +3 -0
  336. package/src/services/task-state-reconcile.ts +6 -14
  337. package/src/services/team-templates.ts +9 -8
  338. package/src/services/transient-agent-reaper.ts +3 -1
  339. package/src/services/workflow-auto-start.ts +25 -13
  340. package/src/services/workflow-ci-main.ts +1 -1
  341. package/src/services/workflow-deferred-cleanup.ts +4 -2
  342. package/src/services/workflow-effect-driver.ts +2 -0
  343. package/src/services/workflow-effects.ts +18 -11
  344. package/src/services/workflow-land-notice.ts +10 -0
  345. package/src/services/workflow-pause-text.ts +43 -0
  346. package/src/services/workflow-reconcile.ts +13 -11
  347. package/src/services/workflow-run-view.ts +2 -0
  348. package/src/services/workflow-runs.ts +29 -13
  349. package/src/services/workflow-supervisor-state.ts +5 -0
  350. package/src/services/workflow-supervisor.ts +7 -3
  351. package/src/settings/registry.ts +1 -2
  352. package/src/spawn-command.ts +4 -4
  353. package/src/spawn-models.ts +10 -12
  354. package/src/spawn-placement.ts +1 -1
  355. package/src/spawn-targets.ts +1 -1
  356. package/src/startup-context-injection.ts +1 -0
  357. package/src/state-adoption/cd-cutover.ts +53 -7
  358. package/src/state-adoption/fleet-cutover.ts +35 -0
  359. package/src/state-adoption/fleet-plan.ts +36 -0
  360. package/src/state-adoption/index.ts +2 -2
  361. package/src/state-adoption/linux-plan.ts +2 -2
  362. package/src/state-adoption/linux.ts +2 -2
  363. package/src/state-adoption/macos-plan.ts +2 -2
  364. package/src/state-adoption/macos.ts +1 -1
  365. package/src/steward.ts +7 -6
  366. package/src/task-dispatch-live.ts +1 -1
  367. package/src/task-dispatcher.ts +1 -1
  368. package/src/teams-config-store.ts +4 -3
  369. package/src/token-db-write.ts +10 -0
  370. package/src/workspace-command-settle.ts +2 -1
  371. package/src/workspace-steward-wake.ts +2 -2
  372. package/node_modules/@humwick/kernel/LICENSE +0 -167
  373. package/node_modules/@humwick/kernel/async-entity-persistence.ts +0 -344
  374. package/node_modules/@humwick/kernel/async-event-log.ts +0 -107
  375. package/node_modules/@humwick/kernel/automations.pilot.ts +0 -147
  376. package/node_modules/@humwick/kernel/config.ts +0 -111
  377. package/node_modules/@humwick/kernel/contract.ts +0 -572
  378. package/node_modules/@humwick/kernel/control-authz.ts +0 -281
  379. package/node_modules/@humwick/kernel/control.ts +0 -645
  380. package/node_modules/@humwick/kernel/effects.ts +0 -493
  381. package/node_modules/@humwick/kernel/event-log.ts +0 -319
  382. package/node_modules/@humwick/kernel/http-transport.ts +0 -384
  383. package/node_modules/@humwick/kernel/identity-grammar.ts +0 -20
  384. package/node_modules/@humwick/kernel/identity.ts +0 -248
  385. package/node_modules/@humwick/kernel/index.ts +0 -28
  386. package/node_modules/@humwick/kernel/kernel-persistence.ts +0 -181
  387. package/node_modules/@humwick/kernel/landing-incident.ts +0 -306
  388. package/node_modules/@humwick/kernel/landing.ts +0 -953
  389. package/node_modules/@humwick/kernel/manifest-validation.ts +0 -460
  390. package/node_modules/@humwick/kernel/mcp-transport.ts +0 -109
  391. package/node_modules/@humwick/kernel/message-authority-chaos-worker.ts +0 -200
  392. package/node_modules/@humwick/kernel/message-authority.ts +0 -281
  393. package/node_modules/@humwick/kernel/module-host.ts +0 -722
  394. package/node_modules/@humwick/kernel/openapi-init.ts +0 -14
  395. package/node_modules/@humwick/kernel/package.json +0 -47
  396. package/node_modules/@humwick/kernel/persistence-schema.ts +0 -248
  397. package/node_modules/@humwick/kernel/persistence.ts +0 -510
  398. package/node_modules/@humwick/kernel/registry.ts +0 -60
  399. package/node_modules/@humwick/kernel/sqlite-kernel-persistence.ts +0 -499
  400. package/node_modules/@humwick/kernel/sqlite-module-host.ts +0 -87
  401. package/node_modules/@humwick/kernel/timers-chaos-worker.ts +0 -186
  402. package/node_modules/@humwick/kernel/timers.pilot.ts +0 -1411
  403. package/node_modules/@humwick/kernel/workflow-activation.ts +0 -25
  404. package/node_modules/@humwick/kernel/workflow-backstop.ts +0 -40
  405. package/node_modules/@humwick/kernel/workflow-cancel-tree.ts +0 -20
  406. package/node_modules/@humwick/kernel/workflow-chaos-worker.ts +0 -213
  407. package/node_modules/@humwick/kernel/workflow-composition.ts +0 -231
  408. package/node_modules/@humwick/kernel/workflow-container.ts +0 -72
  409. package/node_modules/@humwick/kernel/workflow-control.test-fixture.ts +0 -42
  410. package/node_modules/@humwick/kernel/workflow-control.ts +0 -178
  411. package/node_modules/@humwick/kernel/workflow-definition.ts +0 -507
  412. package/node_modules/@humwick/kernel/workflow-dispatch.ts +0 -60
  413. package/node_modules/@humwick/kernel/workflow-foreach.ts +0 -167
  414. package/node_modules/@humwick/kernel/workflow-journal-codec.ts +0 -339
  415. package/node_modules/@humwick/kernel/workflow-journal.ts +0 -922
  416. package/node_modules/@humwick/kernel/workflow-lane.ts +0 -48
  417. package/node_modules/@humwick/kernel/workflow-lease-owner.ts +0 -60
  418. package/node_modules/@humwick/kernel/workflow-recovery.test-fixture.ts +0 -19
  419. package/node_modules/@humwick/kernel/workflow-runtime.ts +0 -938
  420. package/node_modules/@humwick/kernel/workflow-script.ts +0 -11
  421. package/node_modules/@humwick/kernel/workflow-state.ts +0 -299
  422. package/node_modules/@humwick/kernel/workflow-step-commit.ts +0 -195
  423. package/node_modules/@humwick/kernel/workflow-transitions.ts +0 -317
  424. package/node_modules/@humwick/kernel/workflow-values.ts +0 -153
  425. package/node_modules/@humwick/kernel/workflow.pilot.ts +0 -376
  426. package/node_modules/@humwick/offload/LICENSE +0 -167
  427. package/node_modules/@humwick/offload/README.md +0 -57
  428. package/node_modules/@humwick/offload/dist/async-runner.d.ts +0 -18
  429. package/node_modules/@humwick/offload/dist/async-runner.d.ts.map +0 -1
  430. package/node_modules/@humwick/offload/dist/async-runner.js +0 -158
  431. package/node_modules/@humwick/offload/dist/async-runner.js.map +0 -1
  432. package/node_modules/@humwick/offload/dist/envelope.d.ts +0 -25
  433. package/node_modules/@humwick/offload/dist/envelope.d.ts.map +0 -1
  434. package/node_modules/@humwick/offload/dist/envelope.js +0 -80
  435. package/node_modules/@humwick/offload/dist/envelope.js.map +0 -1
  436. package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts +0 -10
  437. package/node_modules/@humwick/offload/dist/fixtures/worker-task.d.ts.map +0 -1
  438. package/node_modules/@humwick/offload/dist/fixtures/worker-task.js +0 -59
  439. package/node_modules/@humwick/offload/dist/fixtures/worker-task.js.map +0 -1
  440. package/node_modules/@humwick/offload/dist/index.d.ts +0 -5
  441. package/node_modules/@humwick/offload/dist/index.d.ts.map +0 -1
  442. package/node_modules/@humwick/offload/dist/index.js +0 -5
  443. package/node_modules/@humwick/offload/dist/index.js.map +0 -1
  444. package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts +0 -62
  445. package/node_modules/@humwick/offload/dist/subprocess-runner.d.ts.map +0 -1
  446. package/node_modules/@humwick/offload/dist/subprocess-runner.js +0 -295
  447. package/node_modules/@humwick/offload/dist/subprocess-runner.js.map +0 -1
  448. package/node_modules/@humwick/offload/dist/types.d.ts +0 -111
  449. package/node_modules/@humwick/offload/dist/types.d.ts.map +0 -1
  450. package/node_modules/@humwick/offload/dist/types.js +0 -176
  451. package/node_modules/@humwick/offload/dist/types.js.map +0 -1
  452. package/node_modules/@humwick/offload/dist/worker-pool.d.ts +0 -23
  453. package/node_modules/@humwick/offload/dist/worker-pool.d.ts.map +0 -1
  454. package/node_modules/@humwick/offload/dist/worker-pool.js +0 -435
  455. package/node_modules/@humwick/offload/dist/worker-pool.js.map +0 -1
  456. package/node_modules/@humwick/offload/dist/worker-runtime.d.ts +0 -2
  457. package/node_modules/@humwick/offload/dist/worker-runtime.d.ts.map +0 -1
  458. package/node_modules/@humwick/offload/dist/worker-runtime.js +0 -27
  459. package/node_modules/@humwick/offload/dist/worker-runtime.js.map +0 -1
  460. package/node_modules/@humwick/offload/dist/worker.d.ts +0 -5
  461. package/node_modules/@humwick/offload/dist/worker.d.ts.map +0 -1
  462. package/node_modules/@humwick/offload/dist/worker.js +0 -1
  463. package/node_modules/@humwick/offload/dist/worker.js.map +0 -1
  464. package/node_modules/@humwick/offload/package.json +0 -46
  465. package/node_modules/@humwick/offload/src/async-runner.ts +0 -170
  466. package/node_modules/@humwick/offload/src/envelope.ts +0 -92
  467. package/node_modules/@humwick/offload/src/fixtures/worker-task.ts +0 -49
  468. package/node_modules/@humwick/offload/src/index.ts +0 -4
  469. package/node_modules/@humwick/offload/src/subprocess-runner.ts +0 -334
  470. package/node_modules/@humwick/offload/src/types.ts +0 -235
  471. package/node_modules/@humwick/offload/src/worker-pool.ts +0 -463
  472. package/node_modules/@humwick/offload/src/worker-runtime.ts +0 -32
  473. package/node_modules/@humwick/offload/src/worker.ts +0 -5
  474. package/public/assets/agent-liveness-DyqxfB-t.js +0 -2
  475. package/public/assets/agent-profiles-BpI_jTxq.js +0 -2
  476. package/public/assets/fleet-BL4UXS_k.js +0 -2
  477. package/public/assets/index-B7ZerHLY.css +0 -2
  478. package/public/assets/index-BK0WV6hF.js +0 -15
  479. package/public/assets/projects-B_lmcqfO.js +0 -2
  480. package/public/assets/provider-display-DbLWpP3j.js +0 -2
  481. package/public/assets/run-card-CO_bguQf.js +0 -2
  482. package/public/assets/use-project-list-B-T2Bnnn.js +0 -2
  483. package/public/assets/versioned-prompt-editor-Diu8BIaM.js +0 -8
  484. package/runner/src/gate-run-lease-probe.ts +0 -38
  485. package/src/db/claude-catalog-reconcile.ts +0 -27
  486. package/src/routing-model-aliases.ts +0 -21
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env bun
2
- import { relayEnv } from "@humwick/sdk/env";
2
+ import { relayEnv, writeChildEnv } from "@humwick/sdk/env";
3
3
  /**
4
4
  * #2461 — the gate-run lease CLI. ONE implementation of the per-agent single-run invariant.
5
5
  *
@@ -49,6 +49,8 @@ import { readFileSync } from "node:fs";
49
49
  import { join } from "node:path";
50
50
  import {
51
51
  claimGateRunLease,
52
+ gateRunContext,
53
+ GATE_RUN_CONTEXT_ENV,
52
54
  gateRunLeaseDir,
53
55
  gateRunLeaseEnabled,
54
56
  gateRunWasSuperseded,
@@ -136,17 +138,18 @@ export async function claim(options: {
136
138
  // here, which is one read and therefore no disagreement.
137
139
  const category = carried ?? classifyGateRun(options.command, gateCommandsForCwd(options.cwd));
138
140
  if (!category) return { state: "skip", dir: "", epoch: "" };
139
- // The directory is a pure function of the agent id and the environment, so it cannot drift
140
- // between two calls in the same shell — but a caller that names one is asserting which snapshot
141
- // it decided in, and an assertion that does not hold must never publish.
142
- if (options.dir && options.dir !== gateRunLeaseDir(agentId, env)) return { state: "skip", dir: "", epoch: "" };
141
+ // Preflight captured HEAD. Reuse that identity even if the checkout moves before claim (#3754).
142
+ const carriedContext = options.dir?.split("/").at(-1);
143
+ const context = options.dir ? (/^[a-f0-9]{64}$/.test(carriedContext ?? "") ? carriedContext : undefined) : gateRunContext(options.cwd);
144
+ const scopedEnv = writeChildEnv({ ...env }, { [GATE_RUN_CONTEXT_ENV]: context });
145
+ if (options.dir && options.dir !== gateRunLeaseDir(agentId, scopedEnv)) return { state: "skip", dir: "", epoch: "" };
143
146
 
144
147
  const handle = await claimGateRunLease({
145
148
  agentId,
146
149
  category,
147
150
  command: options.command,
148
151
  selfPid: options.pid,
149
- env,
152
+ env: scopedEnv,
150
153
  ...(options.epoch ? { epoch: options.epoch } : {}),
151
154
  ...clampedLockWait(env),
152
155
  ...(options.log ? { log: options.log } : {}),
@@ -190,7 +193,7 @@ export function preflight(options: { cwd: string; command: string; env?: Record<
190
193
  if ((relayEnv(env, GATE_RUN_HELD_ENV) ?? "").trim()) return { state: "nested", dir: gateRunLeaseDir(agentId, env), category: "" };
191
194
  const category = classifyGateRun(options.command, gateCommandsForCwd(options.cwd));
192
195
  if (!category) return { state: "skip", dir: "", category: "" };
193
- return { state: "claim", dir: gateRunLeaseDir(agentId, env), category };
196
+ return { state: "claim", dir: gateRunLeaseDir(agentId, env, options.cwd), category };
194
197
  }
195
198
 
196
199
  /** A carried category is honoured only if it is one this protocol actually has. Anything else is
package/scripts/gate.sh CHANGED
@@ -1,6 +1,10 @@
1
1
  #!/usr/bin/env sh
2
2
  # Explicit override, managed native delegate, then the bundled compatibility launcher.
3
+ # CI runs this checkout's own launcher: the managed delegate execs the host's DEPLOYED runtime,
4
+ # so a broken deploy would turn every CI run red (T7319). Both share the host admission ledger.
3
5
  GS="${GATE_SLOT_BIN:-}"
6
+ BUNDLED="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)/gate-slot"
7
+ [ -x "$GS" ] || { [ "${GITHUB_ACTIONS:-}" = true ] && GS="$BUNDLED"; }
4
8
  [ -x "$GS" ] || GS="$HOME/.local/bin/gate-slot"
5
- [ -x "$GS" ] || GS="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)/gate-slot"
9
+ [ -x "$GS" ] || GS="$BUNDLED"
6
10
  exec "$GS" "$@"
@@ -0,0 +1,93 @@
1
+ import { isHumanAgentId } from "@humwick/sdk";
2
+ import type { BranchLandedInput, resolveLandedTask } from "./branch-landed";
3
+ import { getAgent, getTaskDetail } from "./db";
4
+ import { renderTemplate } from "./prompt-resolver";
5
+ import { routeNotification, INFORMATIONAL_TTL_MS } from "./notification-router";
6
+ import { stampLifecycleSignal, taskSignalKey } from "./lifecycle-signal-registry";
7
+ import { resolveCoordinatorAgentId } from "./steward-identity";
8
+ import { resolveTaskOwnerAgentId } from "./task-owner";
9
+ import { audienceWithTaskOwnerRole } from "./task-owner-notices";
10
+ import { notifyLandUnconfirmed, verifyPublishedLand } from "./services/landed-ancestry";
11
+
12
+ export async function announceVerifiedLand(input: BranchLandedInput, landedTask: ReturnType<typeof resolveLandedTask>, idempotencyKey?: string): Promise<void> {
13
+ const { workspace } = input;
14
+ const base = workspace.baseRef ?? "main";
15
+ const verification = input.mergedSha && input.landVerifiedSha === input.mergedSha
16
+ ? "confirmed" : await verifyPublishedLand(workspace.repoRoot, input.mergedSha, workspace.baseRef);
17
+ if (verification !== "confirmed") {
18
+ notifyLandUnconfirmed({ workspace, sha: input.mergedSha, targetRef: base.startsWith("origin/") ? base : `origin/${base}`, kind: verification });
19
+ return;
20
+ }
21
+ const landedBranch = workspace.branch;
22
+ const shortSha = input.mergedSha?.slice(0, 12);
23
+ const landedTaskPayload = landedTask ? { taskId: landedTask.taskId, taskLabel: landedTask.taskLabel } : {};
24
+ const author = workspace.ownerAgentId;
25
+ const shaLabel = shortSha ? ` as \`${shortSha}\`` : "";
26
+ const subjectLabel = input.subject ? ` — "${input.subject}"` : "";
27
+ const payload = {
28
+ verified: true,
29
+ kind: "branch.landed",
30
+ workspaceId: workspace.id,
31
+ repoRoot: workspace.repoRoot,
32
+ branch: landedBranch,
33
+ base,
34
+ sha: input.mergedSha,
35
+ author,
36
+ newBranch: input.newBranch,
37
+ pushed: input.pushed,
38
+ ...landedTaskPayload,
39
+ };
40
+
41
+ // The branch author cares most — push regardless of online (store-ahead delivers it on
42
+ // next poll if they've moved on, #234). A live owner continues in its worktree.
43
+ if (author) {
44
+ const branchLabel = landedBranch ? `\`${landedBranch}\`` : "Your branch";
45
+ const continueLabel = input.newBranch
46
+ ? ` You're now on \`${input.newBranch}\` — keep working there.`
47
+ : " Worktree reclaimed.";
48
+ // Durable (ttl null): the author's own branch landing must reach them even after they go
49
+ // offline (store-ahead #234) — not a bystander notice that goes stale.
50
+ const notices = routeNotification({
51
+ type: "branch.landed",
52
+ scope: { author, repoRoot: workspace.repoRoot, workspaceId: workspace.id },
53
+ recipients: [author],
54
+ ttlMs: null,
55
+ message: {
56
+ subject: "Your branch landed",
57
+ body: renderTemplate("notify.land.success", {
58
+ branch: branchLabel,
59
+ base,
60
+ sha: `${shaLabel}${subjectLabel}`,
61
+ publishLabel: "",
62
+ continueLabel,
63
+ }) + " verified: true.",
64
+ payload: { ...payload, notification: "landed-success" },
65
+ idempotencyKey,
66
+ replyExpected: false,
67
+ },
68
+ });
69
+ if (landedTask && input.mergedSha) {
70
+ for (const notice of notices) stampLifecycleSignal(notice.to, taskSignalKey(landedTask.taskId, "landed-on-main", input.mergedSha));
71
+ }
72
+ }
73
+
74
+ // Coordinator copy (#2837), informational. No explicit recipients: the router records the rule decision (#446).
75
+ const mainScope = { author, repoRoot: workspace.repoRoot, workspaceId: workspace.id, teamId: landedTask?.teamId ?? (author ? getAgent(author)?.teamId : undefined), coordinatorAgentIds: [...new Set([resolveCoordinatorAgentId(author), landedTask && resolveTaskOwnerAgentId(getTaskDetail(landedTask.taskId))].filter((id): id is string => !!id && !isHumanAgentId(id)))] };
76
+ const branchLabel = landedBranch ? `\`${landedBranch}\`` : "A branch";
77
+ const authorLabel = author ? ` by \`${author}\`` : "";
78
+ const notices = routeNotification({
79
+ type: "branch.landed",
80
+ scope: mainScope, ...audienceWithTaskOwnerRole("branch.landed", mainScope, landedTask?.taskId), // #2862
81
+ ttlMs: INFORMATIONAL_TTL_MS,
82
+ message: {
83
+ subject: `Merged to ${base}`,
84
+ body: `🔀 ${branchLabel}${authorLabel} merged to \`${base}\`${shaLabel}${subjectLabel}. verified: true.`,
85
+ payload: { ...payload, notification: "landed-success" },
86
+ idempotencyKey,
87
+ replyExpected: false,
88
+ },
89
+ });
90
+ if (landedTask && input.mergedSha) {
91
+ for (const notice of notices) stampLifecycleSignal(notice.to, taskSignalKey(landedTask.taskId, "landed-on-main", input.mergedSha));
92
+ }
93
+ }
@@ -1,3 +1,4 @@
1
+ import { announceVerifiedLand } from "./branch-land-notice";
1
2
  import { errMessage, isHumanAgentId, type BaseWorktreeSyncResult } from "@humwick/sdk";
2
3
  import { emitRelayEvent } from "./events";
3
4
  import { routeNotification, INFORMATIONAL_TTL_MS } from "./notification-router";
@@ -32,6 +33,8 @@ export interface BranchLandedInput extends LandedTaskAttributionInput {
32
33
  workspace: Pick<WorkspaceRecord, "id" | "repoRoot" | "branch" | "baseRef" | "baseSha" | "ownerAgentId" | "orchestratorId">;
33
34
  /** SHA the base now points at after the land. */
34
35
  mergedSha?: string;
36
+ /** Landing host proof from its fresh origin ancestry check. Must match mergedSha. */
37
+ landVerifiedSha?: string;
35
38
  /** Original command settlement clock when recovering an older land. */
36
39
  landedAt?: number;
37
40
  /** Subject line of the landed commit, when the orchestrator reported it. */
@@ -168,7 +171,7 @@ async function landedCommitSubjects(input: BranchLandedInput, log: BranchLandedL
168
171
  }, log);
169
172
  }
170
173
 
171
- function resolveLandedTask(input: LandedTaskAttributionInput): {
174
+ export function resolveLandedTask(input: LandedTaskAttributionInput): {
172
175
  taskId: number;
173
176
  taskLabel: string;
174
177
  projectId?: string;
@@ -348,79 +351,7 @@ export function announceBranchLanded(input: BranchLandedInput): void {
348
351
  }
349
352
  })());
350
353
 
351
- const author = workspace.ownerAgentId;
352
- const shaLabel = shortSha ? ` as \`${shortSha}\`` : "";
353
- const subjectLabel = input.subject ? ` — "${input.subject}"` : "";
354
- const payload = {
355
- kind: "branch.landed",
356
- workspaceId: workspace.id,
357
- repoRoot: workspace.repoRoot,
358
- branch: landedBranch,
359
- base,
360
- sha: input.mergedSha,
361
- author,
362
- newBranch: input.newBranch,
363
- pushed: input.pushed,
364
- ...landedTaskPayload,
365
- };
366
-
367
- // A local-only land (push disabled, or base has no upstream) has NOT reached the
368
- // remote — say so rather than implying a published merge an agent would report as
369
- // shipped (#285). `undefined` (older orchestrators) keeps the message generic.
370
- const publishLabel = input.pushed === false ? ` Not yet pushed to \`origin/${base}\` — local only.` : "";
371
-
372
- // The branch author cares most — push regardless of online (store-ahead delivers it on
373
- // next poll if they've moved on, #234). A live owner continues in its worktree.
374
- if (author) {
375
- const branchLabel = landedBranch ? `\`${landedBranch}\`` : "Your branch";
376
- const continueLabel = input.newBranch
377
- ? ` You're now on \`${input.newBranch}\` — keep working there.`
378
- : " Worktree reclaimed.";
379
- // Durable (ttl null): the author's own branch landing must reach them even after they go
380
- // offline (store-ahead #234) — not a bystander notice that goes stale.
381
- const notices = routeNotification({
382
- type: "branch.landed",
383
- scope: { author, repoRoot: workspace.repoRoot, workspaceId: workspace.id },
384
- recipients: [author],
385
- ttlMs: null,
386
- message: {
387
- subject: "Your branch landed",
388
- body: renderTemplate("notify.land.success", {
389
- branch: branchLabel,
390
- base,
391
- sha: `${shaLabel}${subjectLabel}`,
392
- publishLabel,
393
- continueLabel,
394
- }),
395
- payload: { ...payload, notification: "landed-success" },
396
- idempotencyKey,
397
- replyExpected: false,
398
- },
399
- });
400
- if (landedTask && input.mergedSha) {
401
- for (const notice of notices) stampLifecycleSignal(notice.to, taskSignalKey(landedTask.taskId, "landed-on-main", input.mergedSha));
402
- }
403
- }
404
-
405
- // Coordinator copy (#2837), informational. No explicit recipients: the router records the rule decision (#446).
406
- const mainScope = { author, repoRoot: workspace.repoRoot, workspaceId: workspace.id, teamId: landedTask?.teamId ?? (author ? getAgent(author)?.teamId : undefined), coordinatorAgentIds: [...new Set([resolveCoordinatorAgentId(author), landedTask && resolveTaskOwnerAgentId(getTaskDetail(landedTask.taskId))].filter((id): id is string => !!id && !isHumanAgentId(id)))] };
407
- const branchLabel = landedBranch ? `\`${landedBranch}\`` : "A branch";
408
- const authorLabel = author ? ` by \`${author}\`` : "";
409
- const notices = routeNotification({
410
- type: "branch.landed",
411
- scope: mainScope, ...audienceWithTaskOwnerRole("branch.landed", mainScope, landedTask?.taskId), // #2862
412
- ttlMs: INFORMATIONAL_TTL_MS,
413
- message: {
414
- subject: `Merged to ${base}`,
415
- body: `🔀 ${branchLabel}${authorLabel} merged to \`${base}\`${shaLabel}${subjectLabel}.${publishLabel}`,
416
- payload: { ...payload, notification: "landed-success" },
417
- idempotencyKey,
418
- replyExpected: false,
419
- },
420
- });
421
- if (landedTask && input.mergedSha) {
422
- for (const notice of notices) stampLifecycleSignal(notice.to, taskSignalKey(landedTask.taskId, "landed-on-main", input.mergedSha));
423
- }
354
+ trackLandLifecycleDrive(announceVerifiedLand(input, landedTask, idempotencyKey));
424
355
  }
425
356
 
426
357
  /**
@@ -682,7 +613,7 @@ const DRAINED_LAND_STRAND_BOOKKEEPING = {
682
613
  * (record the receipt, announce a real land, drain the steward/strand bookkeeping so no
683
614
  * watchdog re-wakes or re-pages a branch with nothing left to land).
684
615
  */
685
- export async function reconcileLandedWorkspace(ws: WorkspaceRecord, preview: WorkspaceMergePreview): Promise<LandedWorkspaceReconciliation> {
616
+ export async function reconcileLandedWorkspace(ws: WorkspaceRecord, preview: WorkspaceMergePreview, landVerifiedSha?: string): Promise<LandedWorkspaceReconciliation> {
686
617
  const observedSha = typeof preview.prMergeSha === "string"
687
618
  ? preview.prMergeSha
688
619
  : typeof preview.landedSha === "string"
@@ -753,7 +684,7 @@ export async function reconcileLandedWorkspace(ws: WorkspaceRecord, preview: Wor
753
684
  metadata: { source: "server", maintenanceJobId: "workspace-conflict-scan", workspaceId: ws.id, fromStatus: ws.status, toStatus: nextStatus, ...(ownerAlive ? { ownerAlive: true, keptLive: true } : {}), ...(sha ? { landedSha: sha } : {}), ...(landedCommitCount === 0 ? { landedCommitCount: 0 } : {}) },
754
685
  });
755
686
  try {
756
- notifyBranchLanded({ workspace: ws, mergedSha: sha, landedTipSha: sha, commitShas: sha ? [sha] : [], pushed: true, prLand: preview.prMerged === true, ...(landedCommitCount === 0 ? { landedCommitCount } : {}) });
687
+ notifyBranchLanded({ workspace: ws, mergedSha: sha, landVerifiedSha, landedTipSha: sha, commitShas: sha ? [sha] : [], pushed: true, prLand: preview.prMerged === true, ...(landedCommitCount === 0 ? { landedCommitCount } : {}) });
757
688
  } catch {
758
689
  // Notification is best-effort; the status change + activity event still stand.
759
690
  }
package/src/bus.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Server, ServerWebSocket } from "bun";
2
- import { ValidationError, applyAgentLifecycleUpdate, getAgent, getDb, orphanTasksForAgentAsync, recordHeartbeat, setStatus, validateAgentSession } from "./db";
2
+ import { ValidationError, applyAgentLifecycleUpdateAsync, getAgent, getDb, orphanTasksForAgentAsync, recordHeartbeatAsync, validateAgentSession } from "./db";
3
3
  import { getOutboxCursor, hasReplayGap, replayEventsSlice, type BusEvent } from "./bus-outbox";
4
4
  import { emitAgentStatus } from "./agent-status-events";
5
5
  import { AgentStatusSubscribers, matchesSubscription, wantsAgentStatus } from "./transport-subscriptions";
@@ -34,7 +34,7 @@ import {
34
34
  type BusFrame,
35
35
  type RegisterFrame,
36
36
  } from "@humwick/sdk/protocol";
37
- import { errMessage, isRecord } from "@humwick/sdk";
37
+ import { errMessage, fireAndForget, isRecord } from "@humwick/sdk";
38
38
  import { getComponentAuth, isComponentAuthorizedFor, isAuthorized, isOriginAllowed, unauthorized } from "./security";
39
39
  import type { AgentCard, ComponentToken, ContextState, Message, ProviderCapabilities, QuotaState, RegisterAgentInput, Task } from "./types";
40
40
 
@@ -138,8 +138,11 @@ export function busHandleClose(ws: BusWebSocket): void {
138
138
  // on the establishing socket id, so a foreign socket's close cannot evict the owner's binding and a stale
139
139
  // close cannot evict a newer register's binding).
140
140
  if (!conn.transportReconnect) {
141
- setStatus(conn.agentId, "stale", { instanceId: conn.instanceId, epoch: conn.epoch });
142
- queueAgentStatusEvent(conn.agentId);
141
+ const agentId = conn.agentId;
142
+ void fireAndForget(`[bus] mark ${agentId} stale on close`, async () => {
143
+ await applyAgentLifecycleUpdateAsync(agentId, { status: "stale" }, { instanceId: conn.instanceId, epoch: conn.epoch });
144
+ queueAgentStatusEvent(agentId);
145
+ });
143
146
  }
144
147
  }
145
148
  }
@@ -162,7 +165,7 @@ export async function expireStaleBusAgents(graceMs = busStaleGraceMs(), lagGrace
162
165
  // but do NOT revoke the token — a reconnect accepts the EXISTING token and re-marks
163
166
  // live. The #484 restart-strand revoke now fires on instance takeover in registerAgent
164
167
  // (a fresh instanceId → epoch bump), never on a heartbeat lapse.
165
- setStatus(row.id, "offline");
168
+ await applyAgentLifecycleUpdateAsync(row.id, { status: "offline" });
166
169
  await emitAgentStatus(row.id);
167
170
  const tasks = await orphanTasksForAgentAsync(row.id);
168
171
  for (const task of tasks) {
@@ -187,7 +190,7 @@ async function handleFrame(ws: BusWebSocket, frame: ReturnType<typeof validateCl
187
190
  await handleRegister(ws, frame);
188
191
  return;
189
192
  case "heartbeat":
190
- await withRegistered(ws, frame, (conn) => {
193
+ await withRegistered(ws, frame, async (conn) => {
191
194
  if (conn.agentId) {
192
195
  // #633 — a runner whose provider terminally exited stays alive and keeps sending idle
193
196
  // keepalives (semanticStatus is never "offline"). Those must NOT resurrect an agent the
@@ -199,11 +202,10 @@ async function handleFrame(ws: BusWebSocket, frame: ReturnType<typeof validateCl
199
202
  if (!heldOffline) {
200
203
  const wasUnavailable = current ? isAgentUnavailable(current) : false;
201
204
  const runtime = runtimeFromMeta(frame.payload.meta);
202
- // #1468 — coalesce the steady-state liveness write; recordHeartbeat writes through
203
- // synchronously only on a status change / resurrection (and persists last_seen + runtime
204
- // then). This replaces the old heartbeat()+setStatus() pair that rewrote the row twice
205
- // per beat even when nothing changed.
206
- recordHeartbeat(conn.agentId, { guard: { instanceId: conn.instanceId, epoch: conn.epoch }, status: frame.payload.status, runtime });
205
+ // #1468 — coalesce the steady-state liveness write; only a status change / resurrection
206
+ // writes (last_seen + runtime), on the writer thread (#1870 S7). This replaces the old
207
+ // heartbeat()+setStatus() pair that rewrote the row twice per beat even when nothing changed.
208
+ await recordHeartbeatAsync(conn.agentId, { guard: { instanceId: conn.instanceId, epoch: conn.epoch }, status: frame.payload.status, runtime });
207
209
  queueAgentStatusEvent(conn.agentId);
208
210
  // #416 — flush queued messages if the agent transitioned from unavailable to available.
209
211
  if (wasUnavailable) {
@@ -225,19 +227,16 @@ async function handleFrame(ws: BusWebSocket, frame: ReturnType<typeof validateCl
225
227
  await withRegistered(ws, frame, async (conn) => {
226
228
  if (!conn.agentId) return sendError(ws, frame.id, "AGENT_REQUIRED", "status frames require an agent registration");
227
229
  const guard = { instanceId: conn.instanceId, epoch: conn.epoch };
228
- // #1895 (S3.2 L10 review, D2) — DELIBERATELY left on the sync write path: this is the
229
- // per-status-frame hot WS seam (every heartbeat/status update from every live agent), not the
230
- // cold/admin lifecycle surface that leaf migrates. `withRegistered`'s callback runs with no
231
- // thread hop mid-frame, so routing these writes through their async facades would not move
232
- // them off-loop — it would only add a round-trip.
233
- // #2111 — but the three writes ARE now one. This used to be getAgent(before) + setStatus
230
+ // #1870 S7 — the per-status-frame write runs on the writer thread; this socket's FIFO frame
231
+ // queue keeps its frames ordered across the hop, and the lifecycle ordinal fences it against
232
+ // every other lifecycle writer. #2111 — the three writes are one. This used to be getAgent(before) + setStatus
234
233
  // (guard read + before read + UPDATE in its own BEGIN IMMEDIATE) + markReady (guard read +
235
234
  // UPDATE) + mergeAgentMeta (two reads + UPDATE) + getAgent(after): ~7 row reads and 3 UPDATEs
236
235
  // of one row per frame. `applyAgentLifecycleUpdate` does one guard read, one UPDATE and hands
237
236
  // back the before/after cards the audit calls below need. The flap ledger is different: it is
238
237
  // a cold durable history and must stay ordered with its status edge, so await it within this
239
238
  // socket's existing FIFO frame queue.
240
- const applied = applyAgentLifecycleUpdate(
239
+ const applied = await applyAgentLifecycleUpdateAsync(
241
240
  conn.agentId,
242
241
  { status: frame.payload.agentStatus, ready: frame.payload.ready, meta: frame.payload.meta },
243
242
  guard,
@@ -378,7 +377,7 @@ async function handleRegister(ws: BusWebSocket, frame: RegisterFrame): Promise<v
378
377
  machine: payload.machine,
379
378
  capabilities: payload.capabilities,
380
379
  status: runnerManaged ? "idle" : "online",
381
- ready: true,
380
+ ready: !runnerManaged,
382
381
  instanceId: payload.instanceId,
383
382
  ...(providerCapabilities ? { providerCapabilities } : {}),
384
383
  ...(context ? { context } : {}),
@@ -400,7 +399,7 @@ async function handleRegister(ws: BusWebSocket, frame: RegisterFrame): Promise<v
400
399
  // newly registered agent stale. Fence the install on liveness and clean up the provisional
401
400
  // registration with the same instance/epoch guard used by an established connection's close.
402
401
  if (!liveBusSocketIds.has(ws.data.id)) {
403
- if (payload.agentId && setStatus(payload.agentId, "stale", { instanceId: payload.instanceId, epoch })) {
402
+ if (payload.agentId && (await applyAgentLifecycleUpdateAsync(payload.agentId, { status: "stale" }, { instanceId: payload.instanceId, epoch })).changed) {
404
403
  queueAgentStatusEvent(payload.agentId);
405
404
  }
406
405
  return;
@@ -1,3 +1,7 @@
1
+ import { resolve } from "node:path";
2
+ import { getDeployEventForCommitAsync, deployChangesForCommitsAsync } from "./db/deploy-events-async";
3
+ import type { DeployChanges } from "./db/deploy-events";
4
+ import { runGit } from "./services/git-process";
1
5
  import { VERSION } from "./config";
2
6
  import { reportedGitSha } from "./git-sha";
3
7
  import { routeNotification } from "./notification-router";
@@ -17,6 +21,7 @@ registerDefaultAudienceRules("cd.deploy_live", [audiencePredicates.persistentCoo
17
21
  export interface CdDeployLiveInput {
18
22
  /** Defaults to this process's package version. */
19
23
  version?: string;
24
+ repoRoot?: string;
20
25
  /** Defaults to the running process's attested commit sha (undefined on an npm install). */
21
26
  gitSha?: string;
22
27
  }
@@ -32,7 +37,7 @@ export interface CdDeployLiveInput {
32
37
  * there is no stable identity to key the one-per-deploy dedup on, and this notice is specifically
33
38
  * about the CD-deploy restart glitch that only that deployment model produces.
34
39
  */
35
- export function notifyCdDeployLive(input: CdDeployLiveInput = {}): void {
40
+ export async function notifyCdDeployLive(input: CdDeployLiveInput = {}): Promise<void> {
36
41
  const version = input.version ?? VERSION;
37
42
  const gitSha = input.gitSha ?? reportedGitSha();
38
43
  if (!gitSha) {
@@ -43,6 +48,7 @@ export function notifyCdDeployLive(input: CdDeployLiveInput = {}): void {
43
48
  return;
44
49
  }
45
50
  const shortSha = gitSha.slice(0, 12);
51
+ const contents = await deployNoticeContents(gitSha, input.repoRoot ?? resolve(import.meta.dir, ".."));
46
52
 
47
53
  routeNotification({
48
54
  type: "cd.deploy_live",
@@ -50,10 +56,32 @@ export function notifyCdDeployLive(input: CdDeployLiveInput = {}): void {
50
56
  ttlMs: null,
51
57
  message: {
52
58
  subject: `Humwick ${version} is now running`,
53
- body: `Humwick v${version} (\`${shortSha}\`) is now running after a restart. Any tool-call failures in the last ~1-2 min were the deploy, not an incident — you're good now; retry anything that failed.`,
59
+ body: `Humwick v${version} (\`${shortSha}\`) is now running after a restart. Interrupted tool calls were the deploy, not an incident; retry them.${contents}`,
54
60
  payload: { kind: "cd.deploy-live", version, gitSha },
55
61
  idempotencyKey: `cd-deploy-live:${gitSha}`,
56
62
  replyExpected: false,
57
63
  },
58
64
  });
59
65
  }
66
+
67
+ async function deployNoticeContents(gitSha: string, repoRoot: string): Promise<string> {
68
+ const event = await getDeployEventForCommitAsync(gitSha);
69
+ if (!event) return "";
70
+ let changes: DeployChanges | undefined = event.changes;
71
+ if (changes?.state !== "ready") {
72
+ if (!event.previousSha) return "\nContents unavailable: no previous deployed SHA.";
73
+ const result = await runGit(["-C", repoRoot, "log", "--format=%H%x00%s", `${event.previousSha}..${gitSha}`, "--"], 5000, 1024 * 1024);
74
+ if (result.unavailable || result.exitCode !== 0) return "\nContents unavailable: deploy range could not be read.";
75
+ const commits = result.stdout.trim().split("\n").filter(Boolean).map(line => {
76
+ const [sha, ...subject] = line.split("\x00");
77
+ return { sha: sha!, subject: subject.join("\x00") };
78
+ });
79
+ changes = { state: "ready", ...await deployChangesForCommitsAsync(commits) };
80
+ }
81
+ const lines = changes.tasks.flatMap(task => [
82
+ `T${task.id} ${task.label.replace(/\s+/g, " ")}${task.issues.length ? ` — ${task.issues.map(issue => `${issue.repo}#${issue.externalKey} (${issue.relation ?? "references"})`).join(", ")}` : ""}`,
83
+ ...(task.onDeploy ? [` onDeploy: ${task.onDeploy.replace(/\s+/g, " ")}`] : []),
84
+ ]);
85
+ lines.push(`${changes.unmatchedCommits.length} non-Task commit(s).`);
86
+ return `\n${lines.join("\n")}`;
87
+ }
@@ -1,9 +1,10 @@
1
1
  import { resolveCdFleetAllowlist } from "../scripts/cd-config.ts";
2
2
  import { isCdFleetHostAllowlisted } from "../scripts/cd-fleet-membership.ts";
3
- import { getConfig, setConfig } from "./config-store.ts";
4
- import { createActivityEvent } from "./db/activity.ts";
3
+ import { getConfig } from "./config-store.ts";
4
+ import { setConfigAsync } from "./config-store-write.ts";
5
+ import { createActivityEventAsync } from "./db/activity-async.ts";
5
6
  import { computeFleetConvergenceAsync, type FleetConvergence } from "./fleet-convergence.ts";
6
- import { raiseOperatorAlarm } from "./operator-alarm.ts";
7
+ import { raiseOperatorAlarmAsync } from "./operator-alarm.ts";
7
8
  import { listOrchestratorsAsync } from "./db/orchestrators-async.ts";
8
9
 
9
10
  /** Server-side: a durable alarm per lag episode, and a recovery record when it clears. */
@@ -17,7 +18,7 @@ export async function notifyCdHostLag(convergence?: FleetConvergence, allowlist
17
18
  // Keep the episode's identity while targets advance, until this Host catches up.
18
19
  const since = previous[host.id] ?? host.lag.since;
19
20
  current[host.id] = since;
20
- raiseOperatorAlarm({ clientId: `cd-host-lag:${host.id}:${since}`, source: "cd-host-lag", view: "deploys",
21
+ await raiseOperatorAlarmAsync({ clientId: `cd-host-lag:${host.id}:${since}`, source: "cd-host-lag", view: "deploys",
21
22
  subject: `CD deploy lag on ${host.id}`, dedupeEvent: true,
22
23
  detail: `${host.id} is ${Math.floor(host.lag.ageMs / 60_000)} minutes behind ${status.targetSha.slice(0, 12)}: ${host.deferred?.reason ?? host.reason}`,
23
24
  metadata: { orchestratorId: host.id, since, targetSha: status.targetSha, deferred: host.deferred } });
@@ -29,8 +30,8 @@ export async function notifyCdHostLag(convergence?: FleetConvergence, allowlist
29
30
  if (!host || !isCdFleetHostAllowlisted(host, allowlist)) { delete current[id]; continue; }
30
31
  if (!status.targetSha || host.gitSha !== status.targetSha) { current[id] = since; continue; }
31
32
  delete current[id];
32
- createActivityEvent({ clientId: `cd-host-lag-resolved:${id}:${since}`, kind: "state", view: "deploys",
33
+ await createActivityEventAsync({ clientId: `cd-host-lag-resolved:${id}:${since}`, kind: "state", view: "deploys",
33
34
  title: `CD deploy lag cleared on ${id}`, metadata: { source: "cd-host-lag", orchestratorId: id, since, resolved: true } });
34
35
  }
35
- if (JSON.stringify(current) !== JSON.stringify(previous)) setConfig("cd-host-lag", "alarms", current);
36
+ if (JSON.stringify(current) !== JSON.stringify(previous)) await setConfigAsync("cd-host-lag", "alarms", current);
36
37
  }
@@ -169,7 +169,7 @@ export function ingestCiObservation(observation: CiObservation, now: number = Da
169
169
 
170
170
  /** Gateway-routed form for async-capable polling jobs. The complete observation transition is one
171
171
  * writer operation, so no gateway await exposes a stale watch state to a later incident decision. */
172
- export async function ingestCiObservationAsync(observation: CiObservation): Promise<CiIncidentIngestResult> {
172
+ export async function ingestCiObservationAsync(observation: CiObservation, now?: number): Promise<CiIncidentIngestResult> {
173
173
  const transition = transitionInput(observation);
174
- return formatTransitionResult(await ingestCiObservationTransitionAsync(transition.input), transition.watchKey, transition.fingerprint);
174
+ return formatTransitionResult(await ingestCiObservationTransitionAsync(transition.input, now), transition.watchKey, transition.fingerprint);
175
175
  }
package/src/ci/monitor.ts CHANGED
@@ -12,8 +12,8 @@ import { isPathWithinBase } from "../utils";
12
12
  import { computeCiWatchKey, isFailingJob } from "./incidents.ts";
13
13
  import { ghApi, type GitHubApi } from "../issue-tracker/github.ts";
14
14
  import { resolveCoordinatorAgentId } from "../steward-identity.ts";
15
- import { notifyCiRootMissing, notifyCiRootMissingAsync, type CiRootMissing } from "./root-missing.ts";
16
- import { notifyCiTransition, notifyCiTransitionAsync, type CiTransitionNotifyResult } from "./transition-notify.ts";
15
+ import { notifyCiRootMissing, type CiRootMissing } from "./root-missing.ts";
16
+ import { notifyCiTransition, type CiTransitionNotifyResult } from "./transition-notify.ts";
17
17
  import { workflowNotTriggered } from "./not-triggered.ts";
18
18
  import type { CiJobRef, CiObservation, CiObservationStatus, CiRunRef } from "./provider.ts";
19
19
 
@@ -343,7 +343,7 @@ export interface CiMonitorDeps {
343
343
  rootsForProject: (projectId: string) => ProjectRoot[];
344
344
  loadConfig: (root: ProjectRoot) => CiMonitorConfig | null | Promise<CiMonitorConfig | null>;
345
345
  api: GitHubApi;
346
- notify: typeof notifyCiTransition;
346
+ notify: (...args: Parameters<typeof notifyCiTransition>) => CiTransitionNotifyResult | Promise<CiTransitionNotifyResult>;
347
347
  resolveCoordinator: (rootPath: string) => string | undefined;
348
348
  /** Commits workflows wait on: each watch of their root reports its verdict on them too. */
349
349
  shaWaits: () => Promise<CiShaWait[]>;
@@ -419,7 +419,6 @@ export async function runCiMonitor(input: Partial<CiMonitorDeps> = {}): Promise<
419
419
  readinessMs: 0, historyMs: 0, historyApiCalls: 0,
420
420
  transitions: { went_red: 0, back_green: 0, never_matched: 0, config_mismatch: 0, none: 0 },
421
421
  };
422
- const useAsync = deps.notify === notifyCiTransition && !deps.now;
423
422
  // A repository counts as missing only if no root of it has the config, so a duplicate root cannot flap the notice.
424
423
  const missingRoots = new Map<string, CiRootMissing>();
425
424
  const presentRepositories = new Set<string>();
@@ -464,9 +463,7 @@ export async function runCiMonitor(input: Partial<CiMonitorDeps> = {}): Promise<
464
463
  const observation = await observeGitHubCiMonitorWatch(repository, watch, deps.api, runsPayload);
465
464
  if (deps.signal?.aborted) break;
466
465
  const notificationDeps = { resolveCoordinator: () => deps.resolveCoordinator(root.rootPath), ...(deps.now ? { now: deps.now() } : {}) };
467
- const transition = useAsync
468
- ? await notifyCiTransitionAsync(observation, notificationDeps)
469
- : deps.notify(observation, notificationDeps);
466
+ const transition = await deps.notify(observation, notificationDeps);
470
467
  result.transitions[transition.transition] += 1;
471
468
  // The branch-tip row keys the watch; the same key carries its verdict on each waited commit.
472
469
  const watchKey = computeCiWatchKey(observation);
@@ -495,7 +492,7 @@ export async function runCiMonitor(input: Partial<CiMonitorDeps> = {}): Promise<
495
492
  if (presentRepositories.has(key) || deps.signal?.aborted) continue;
496
493
  const notifyDeps = { resolveCoordinator: () => deps.resolveCoordinator(missing.rootPath), ...(deps.now ? { now: deps.now() } : {}) };
497
494
  try {
498
- if (useAsync ? await notifyCiRootMissingAsync(missing, notifyDeps) : notifyCiRootMissing(missing, notifyDeps)) result.missingRoots += 1;
495
+ if (await notifyCiRootMissing(missing, notifyDeps)) result.missingRoots += 1;
499
496
  } catch (error) {
500
497
  result.errors += 1;
501
498
  console.warn(`ci monitor ${missing.repository} root-missing notice skipped: ${errMessage(error)}`);
@@ -1,4 +1,3 @@
1
- import { markCiRootMissingNotified } from "../db/ci-incidents.ts";
2
1
  import { markCiRootMissingNotifiedAsync } from "../db/ci-incidents-async.ts";
3
2
  import { routeCiIncidentNotification } from "./notifications.ts";
4
3
  import { resolveCoordinator, type CiTransitionNotifyDeps } from "./transition-notify.ts";
@@ -26,10 +25,6 @@ function notify(input: CiRootMissing, deps: Deps, fired: boolean): boolean {
26
25
  return true;
27
26
  }
28
27
 
29
- export function notifyCiRootMissing(input: CiRootMissing, deps: Deps = {}): boolean {
30
- return notify(input, deps, markCiRootMissingNotified(input.repository, deps.now));
31
- }
32
-
33
- export async function notifyCiRootMissingAsync(input: CiRootMissing, deps: Deps = {}): Promise<boolean> {
34
- return notify(input, deps, await markCiRootMissingNotifiedAsync(input.repository));
28
+ export async function notifyCiRootMissing(input: CiRootMissing, deps: Deps = {}): Promise<boolean> {
29
+ return notify(input, deps, await markCiRootMissingNotifiedAsync(input.repository, deps.now));
35
30
  }