@north-light/crouter 0.3.312 → 0.3.314

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 (497) hide show
  1. package/dist/api/client.d.ts +27 -30
  2. package/dist/api/client.js +80 -67
  3. package/dist/api/dto/broker-ops.d.ts +10 -20
  4. package/dist/api/dto/canvas.d.ts +1 -10
  5. package/dist/api/dto/health.d.ts +113 -0
  6. package/dist/api/dto/human-requests.d.ts +14 -3
  7. package/dist/api/dto/human.d.ts +2 -48
  8. package/dist/api/dto/human.js +3 -2
  9. package/dist/api/dto/inbox.d.ts +14 -0
  10. package/dist/api/dto/mail.d.ts +43 -0
  11. package/dist/api/dto/nodes.d.ts +11 -8
  12. package/dist/api/dto/recovery.d.ts +96 -0
  13. package/dist/api/dto/reviews.d.ts +2 -2
  14. package/dist/api/routes.d.ts +9 -6
  15. package/dist/api/routes.js +11 -11
  16. package/dist/build-root.d.ts +4 -0
  17. package/dist/build-root.js +11 -1
  18. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/__tests__/integration/provider-rotation.test.ts +35 -47
  19. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +1 -1
  20. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +12 -5
  21. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +12 -5
  22. package/dist/cli.js +10 -1
  23. package/dist/clients/__tests__/helpers/human-daemon.d.ts +11 -0
  24. package/dist/clients/__tests__/helpers/human-daemon.js +60 -0
  25. package/dist/clients/attach/chrome/canvas-panels.js +1 -1
  26. package/dist/clients/attach/chrome/inbox-strip.d.ts +3 -3
  27. package/dist/clients/attach/chrome/inbox-strip.js +17 -9
  28. package/dist/clients/attach/chrome/ticket-panel.d.ts +2 -2
  29. package/dist/clients/attach/chrome/ticket-panel.js +77 -46
  30. package/dist/clients/attach/overlays/graph.js +6 -9
  31. package/dist/clients/attach/render/chat-view.d.ts +5 -4
  32. package/dist/clients/attach/render/chat-view.js +22 -13
  33. package/dist/clients/attach/render/page-block.d.ts +11 -7
  34. package/dist/clients/attach/render/page-block.js +64 -55
  35. package/dist/clients/attach/viewer.js +757 -746
  36. package/dist/clients/inbox/__tests__/integration/inbox-controller.test.js +56 -56
  37. package/dist/clients/inbox/__tests__/integration/stale-row-activation.test.js +45 -32
  38. package/dist/clients/inbox/controller.d.ts +42 -14
  39. package/dist/clients/inbox/controller.js +240 -124
  40. package/dist/clients/inbox/dto-adapt.d.ts +28 -0
  41. package/dist/clients/inbox/dto-adapt.js +93 -0
  42. package/dist/clients/inbox/page-adapter.d.ts +5 -4
  43. package/dist/clients/inbox/page-adapter.js +12 -12
  44. package/dist/clients/inbox/resolve.d.ts +10 -5
  45. package/dist/clients/inbox/resolve.js +13 -12
  46. package/dist/clients/inbox/review/review-client.d.ts +0 -1
  47. package/dist/clients/inbox/review/review-client.js +0 -4
  48. package/dist/clients/inbox/review-adapter.d.ts +2 -1
  49. package/dist/clients/inbox/review-adapter.js +3 -5
  50. package/dist/clients/inbox/surface.d.ts +2 -2
  51. package/dist/clients/inbox/surface.js +19 -8
  52. package/dist/clients/inbox/tui.d.ts +3 -3
  53. package/dist/commands/__tests__/human.test.js +31 -15
  54. package/dist/commands/__tests__/integration/dashboard-snapshot.test.js +36 -11
  55. package/dist/commands/{sys/__tests__ → __tests__/integration}/migrate.test.js +142 -36
  56. package/dist/commands/__tests__/revive-now-gate.test.js +2 -0
  57. package/dist/commands/api-client.d.ts +5 -4
  58. package/dist/commands/api-client.js +13 -7
  59. package/dist/commands/canvas-history/shared.js +1 -1
  60. package/dist/commands/canvas-history.js +1 -1
  61. package/dist/commands/canvas-roster.js +1 -1
  62. package/dist/commands/canvas.js +1 -2
  63. package/dist/commands/human/feedback.js +20 -17
  64. package/dist/commands/human/prompts.js +45 -36
  65. package/dist/commands/human/queue.js +73 -123
  66. package/dist/commands/human/review.js +6 -16
  67. package/dist/commands/memory/__tests__/command-selector-and-mutation-guards.test.js +2 -0
  68. package/dist/commands/memory/__tests__/memory-list-and-lint-ignore.test.js +2 -0
  69. package/dist/commands/memory/__tests__/repository-root-lint.test.js +2 -0
  70. package/dist/commands/node-inspect-artifacts.js +1 -1
  71. package/dist/commands/node-lifecycle-revive.d.ts +2 -2
  72. package/dist/commands/node-lifecycle-revive.js +9 -19
  73. package/dist/commands/pkg/plugin-manage.js +0 -1
  74. package/dist/commands/profile/show.js +4 -12
  75. package/dist/commands/surface-tmux-spread.js +1 -5
  76. package/dist/commands/sys/__tests__/config-model-ladders.test.js +23 -30
  77. package/dist/commands/sys/__tests__/sync-project-guidance.test.js +37 -11
  78. package/dist/commands/sys/branch.d.ts +2 -0
  79. package/dist/commands/sys/branch.js +19 -0
  80. package/dist/commands/sys/config.js +106 -33
  81. package/dist/commands/sys/daemon.d.ts +2 -0
  82. package/dist/commands/sys/daemon.js +130 -7
  83. package/dist/commands/sys/doctor.js +5 -15
  84. package/dist/commands/sys/migrate.js +21 -92
  85. package/dist/commands/sys/setup-settings-runner.js +4 -2
  86. package/dist/commands/sys.js +2 -15
  87. package/dist/core/__tests__/boot-fault-attempt.test.js +23 -1
  88. package/dist/core/__tests__/boot.test.js +32 -25
  89. package/dist/core/__tests__/broker-launch-candidates.test.js +49 -0
  90. package/dist/core/__tests__/canvas-inbox-watcher-hold.test.js +149 -176
  91. package/dist/core/__tests__/canvas-inbox-watcher-naming.test.js +59 -10
  92. package/dist/core/__tests__/canvas-inbox-watcher.test.js +76 -20
  93. package/dist/core/__tests__/canvas.test.js +18 -47
  94. package/dist/core/__tests__/child-death-wake.test.js +29 -7
  95. package/dist/core/__tests__/cli-help-contract.test.js +2 -0
  96. package/dist/core/__tests__/close.test.js +29 -10
  97. package/dist/core/__tests__/collectible.test.js +2 -1
  98. package/dist/core/__tests__/config-change-delta.test.js +2 -0
  99. package/dist/core/__tests__/context-intro.test.js +13 -1
  100. package/dist/core/__tests__/cron-armed-context-failure.test.js +17 -12
  101. package/dist/core/__tests__/cron-held-settlement.test.js +21 -3
  102. package/dist/core/__tests__/cron-node-sink-parked-root.test.js +29 -10
  103. package/dist/core/__tests__/cron-self-cancel-delivery.test.js +14 -2
  104. package/dist/core/__tests__/cron-timeout-descendants.test.js +13 -1
  105. package/dist/core/__tests__/daemon-boot.test.js +51 -14
  106. package/dist/core/__tests__/fixtures/fake-engine.d.ts +1 -1
  107. package/dist/core/__tests__/fixtures/fake-engine.js +8 -3
  108. package/dist/core/__tests__/focuses.test.js +10 -5
  109. package/dist/core/__tests__/helpers/harness.js +50 -18
  110. package/dist/core/__tests__/history-inbox.test.js +12 -16
  111. package/dist/core/__tests__/human-action-delivery.test.js +48 -28
  112. package/dist/core/__tests__/human-actions.test.js +7 -3
  113. package/dist/core/__tests__/inline-memory-refs.test.js +7 -2
  114. package/dist/core/__tests__/integration/broker-fork-seam.test.js +37 -10
  115. package/dist/core/__tests__/integration/broker-sdk-wiring.test.js +42 -0
  116. package/dist/core/__tests__/integration/broker-snapshot-history.test.js +42 -29
  117. package/dist/core/__tests__/integration/broker-wedge-supervision.test.js +36 -35
  118. package/dist/core/__tests__/integration/command-plugins.test.js +15 -6
  119. package/dist/core/__tests__/integration/deferred-no-wake.test.js +113 -92
  120. package/dist/core/__tests__/integration/fresh-home-commands.test.js +49 -0
  121. package/dist/core/__tests__/integration/host-teardown-process-group.test.js +9 -5
  122. package/dist/core/__tests__/integration/lifecycle-hooks.test.js +16 -3
  123. package/dist/core/__tests__/integration/plugin-revalidate.test.js +4 -0
  124. package/dist/core/__tests__/integration/profile-pause.test.js +4 -4
  125. package/dist/core/__tests__/integration/refresh-stall-recycle.test.js +9 -12
  126. package/dist/core/__tests__/integration/revive.test.js +67 -21
  127. package/dist/core/__tests__/integration/spawn-root.test.js +51 -8
  128. package/dist/core/__tests__/integration/subscription-delivery.test.js +33 -21
  129. package/dist/core/__tests__/integration/worktree-land.test.js +5 -2
  130. package/dist/core/__tests__/integration/worktree-reap.test.js +15 -1
  131. package/dist/core/__tests__/kickoff.test.js +36 -39
  132. package/dist/core/__tests__/lifecycle-terminal-reasons.test.js +2 -1
  133. package/dist/core/__tests__/lifecycle.test.js +2 -1
  134. package/dist/core/__tests__/live-lifecycle-prompt.test.js +13 -1
  135. package/dist/core/__tests__/memory-resolver-precedence.test.js +2 -0
  136. package/dist/core/__tests__/migration.test.js +145 -31
  137. package/dist/core/__tests__/model-pin-durability.test.js +4 -1
  138. package/dist/core/__tests__/model-routes-config.test.js +13 -5
  139. package/dist/core/__tests__/node-outcome.test.js +93 -26
  140. package/dist/core/__tests__/on-read-crouter-home-fence.test.js +2 -1
  141. package/dist/core/__tests__/on-read-dedup-resume.test.js +2 -1
  142. package/dist/core/__tests__/on-read-nested-store.test.js +2 -1
  143. package/dist/core/__tests__/passive-subscription.test.js +50 -157
  144. package/dist/core/__tests__/plugin-kinds.test.js +6 -4
  145. package/dist/core/__tests__/plugin-link-symlinked-scope-root.test.js +6 -1
  146. package/dist/core/__tests__/plugin-page-components.test.js +6 -4
  147. package/dist/core/__tests__/preview-registry-sync.test.js +2 -0
  148. package/dist/core/__tests__/profile-project-memory-delivery.test.js +4 -1
  149. package/dist/core/__tests__/prune.test.js +11 -5
  150. package/dist/core/__tests__/push-final-guard.test.js +14 -7
  151. package/dist/core/__tests__/relaunch-root.test.js +30 -2
  152. package/dist/core/__tests__/remote-canvas-target.test.js +7 -1
  153. package/dist/core/__tests__/repository-root-identity.test.js +4 -0
  154. package/dist/core/__tests__/review-model-floor.test.js +6 -3
  155. package/dist/core/__tests__/revive-all.test.js +13 -3
  156. package/dist/core/__tests__/revive-capacity.test.js +26 -4
  157. package/dist/core/__tests__/revive-parked-fresh.test.js +31 -8
  158. package/dist/core/__tests__/seam/broker-attach-stream.test.js +1 -1
  159. package/dist/core/__tests__/seam/broker-cap-freeze.test.js +4 -3
  160. package/dist/core/__tests__/seam/broker-crash-teardown.test.js +11 -14
  161. package/dist/core/__tests__/seam/broker-provider-retry.test.js +85 -71
  162. package/dist/core/__tests__/seam/dormancy-release.test.js +33 -19
  163. package/dist/core/__tests__/seam/held-deferred-human-prompt.test.js +7 -5
  164. package/dist/core/__tests__/seam/inbox-reference-guidance.test.js +20 -6
  165. package/dist/core/__tests__/seam/node-outcome-delivery.test.js +27 -3
  166. package/dist/core/__tests__/spawn-worktree-id-conflict.test.js +2 -1
  167. package/dist/core/__tests__/stop-guard.test.js +2 -1
  168. package/dist/core/__tests__/subscription-pool-credential-guard.test.js +4 -3
  169. package/dist/core/__tests__/warm-claim-preference-snapshot.test.js +18 -4
  170. package/dist/core/__tests__/yield-ensures-daemon.test.js +2 -1
  171. package/dist/core/bootstrap.js +2 -0
  172. package/dist/core/broker-client/__tests__/transport-socket.test.js +51 -6
  173. package/dist/core/broker-client/transport-socket.d.ts +1 -0
  174. package/dist/core/broker-client/transport-socket.js +13 -5
  175. package/dist/core/canvas/__tests__/attention.test.js +29 -35
  176. package/dist/core/canvas/__tests__/history-transcript.test.js +6 -6
  177. package/dist/core/canvas/__tests__/render-remote.test.js +25 -9
  178. package/dist/core/canvas/attention.d.ts +2 -5
  179. package/dist/core/canvas/attention.js +15 -64
  180. package/dist/core/canvas/boot.d.ts +6 -7
  181. package/dist/core/canvas/boot.js +5 -9
  182. package/dist/core/canvas/canvas.d.ts +13 -109
  183. package/dist/core/canvas/canvas.js +140 -401
  184. package/dist/core/canvas/crons.d.ts +2 -0
  185. package/dist/core/canvas/crons.js +16 -15
  186. package/dist/core/canvas/daemon-owner.js +10 -0
  187. package/dist/core/canvas/db.d.ts +2 -2
  188. package/dist/core/canvas/db.js +2 -18
  189. package/dist/core/canvas/deliveries.d.ts +104 -0
  190. package/dist/core/canvas/deliveries.js +354 -0
  191. package/dist/core/canvas/executions.d.ts +29 -0
  192. package/dist/core/canvas/executions.js +68 -0
  193. package/dist/core/canvas/history.js +35 -35
  194. package/dist/core/canvas/index.d.ts +3 -1
  195. package/dist/core/canvas/index.js +3 -1
  196. package/dist/core/canvas/migrations.js +20 -12
  197. package/dist/core/canvas/nav-model.js +1 -3
  198. package/dist/core/canvas/nav-render.d.ts +4 -4
  199. package/dist/core/canvas/nav-render.js +11 -21
  200. package/dist/core/canvas/node-sql-migration.d.ts +3 -0
  201. package/dist/core/canvas/node-sql-migration.js +261 -0
  202. package/dist/core/canvas/paths.d.ts +2 -16
  203. package/dist/core/canvas/paths.js +2 -31
  204. package/dist/core/canvas/recovery.d.ts +76 -0
  205. package/dist/core/canvas/recovery.js +588 -0
  206. package/dist/core/canvas/remote-canvas-source.js +4 -0
  207. package/dist/core/canvas/render-source.d.ts +16 -27
  208. package/dist/core/canvas/render-source.js +16 -45
  209. package/dist/core/canvas/sessions.d.ts +33 -0
  210. package/dist/core/canvas/sessions.js +78 -0
  211. package/dist/core/canvas/types.d.ts +33 -33
  212. package/dist/core/canvas/types.js +2 -5
  213. package/dist/core/canvas/waits.d.ts +18 -0
  214. package/dist/core/canvas/waits.js +70 -0
  215. package/dist/core/canvas/worktrees.d.ts +40 -0
  216. package/dist/core/canvas/worktrees.js +93 -0
  217. package/dist/core/command.js +11 -0
  218. package/dist/core/config.d.ts +17 -12
  219. package/dist/core/config.js +106 -155
  220. package/dist/core/feed/__tests__/inbox-migrate.test.js +27 -31
  221. package/dist/core/feed/feed.d.ts +0 -6
  222. package/dist/core/feed/feed.js +68 -56
  223. package/dist/core/feed/inbox.d.ts +7 -81
  224. package/dist/core/feed/inbox.js +46 -378
  225. package/dist/core/feed/messages.d.ts +58 -0
  226. package/dist/core/feed/messages.js +217 -0
  227. package/dist/core/fs-utils.d.ts +4 -0
  228. package/dist/core/fs-utils.js +21 -1
  229. package/dist/core/human/answer.d.ts +1 -1
  230. package/dist/core/human/answer.js +1 -1
  231. package/dist/core/human/claim.d.ts +1 -1
  232. package/dist/core/human/claim.js +2 -4
  233. package/dist/core/human/component-docs.js +1 -1
  234. package/dist/core/human/feedback-companion.js +3 -2
  235. package/dist/core/human/feedback.d.ts +5 -8
  236. package/dist/core/human/feedback.js +57 -85
  237. package/dist/core/human/page-authoring.d.ts +30 -0
  238. package/dist/core/human/page-authoring.js +19 -0
  239. package/dist/core/human/requests.d.ts +136 -0
  240. package/dist/core/human/requests.js +515 -0
  241. package/dist/core/human/root.d.ts +0 -7
  242. package/dist/core/human/root.js +0 -17
  243. package/dist/core/human/scan.d.ts +2 -7
  244. package/dist/core/human/scan.js +48 -132
  245. package/dist/core/human/summary.d.ts +1 -1
  246. package/dist/core/human/summary.js +1 -1
  247. package/dist/core/human/tickets.d.ts +23 -83
  248. package/dist/core/human/tickets.js +92 -243
  249. package/dist/core/human/types.d.ts +5 -1
  250. package/dist/core/installed-plugins.js +8 -3
  251. package/dist/core/keybindings/__tests__/resolve.test.js +19 -17
  252. package/dist/core/locked-file.d.ts +6 -3
  253. package/dist/core/locked-file.js +36 -9
  254. package/dist/core/memory/extensions.js +2 -0
  255. package/dist/core/preview-registry.js +0 -1
  256. package/dist/core/profiles/__tests__/env-store.test.js +2 -0
  257. package/dist/core/profiles/default-binding.d.ts +0 -4
  258. package/dist/core/profiles/default-binding.js +12 -58
  259. package/dist/core/profiles/env-store.js +8 -3
  260. package/dist/core/profiles/manifest.d.ts +2 -37
  261. package/dist/core/profiles/manifest.js +35 -161
  262. package/dist/core/profiles/select.js +3 -0
  263. package/dist/core/review/__tests__/capture-origin.test.js +13 -2
  264. package/dist/core/review/__tests__/comments.test.js +28 -10
  265. package/dist/core/review/__tests__/remap.test.js +28 -10
  266. package/dist/core/review/__tests__/stage-identity.test.js +17 -7
  267. package/dist/core/review/birth.d.ts +1 -1
  268. package/dist/core/review/birth.js +34 -5
  269. package/dist/core/review/comments.js +1 -1
  270. package/dist/core/review/document.js +1 -1
  271. package/dist/core/review/project.d.ts +5 -1
  272. package/dist/core/review/project.js +14 -36
  273. package/dist/core/review/realize.d.ts +3 -6
  274. package/dist/core/review/realize.js +51 -168
  275. package/dist/core/review/remap.js +1 -1
  276. package/dist/core/review/stage.d.ts +3 -2
  277. package/dist/core/review/stage.js +2 -3
  278. package/dist/core/review/store.d.ts +3 -21
  279. package/dist/core/review/store.js +140 -186
  280. package/dist/core/review/types.d.ts +0 -1
  281. package/dist/core/runtime/__tests__/install-id-cache-scoping.test.js +9 -5
  282. package/dist/core/runtime/__tests__/spawn-env.test.js +8 -9
  283. package/dist/core/runtime/broker/auth-reload.js +9 -10
  284. package/dist/core/runtime/broker/daemon-ops.d.ts +25 -8
  285. package/dist/core/runtime/broker/daemon-ops.js +42 -9
  286. package/dist/core/runtime/broker/extension-abort.d.ts +3 -0
  287. package/dist/core/runtime/broker/extension-abort.js +11 -0
  288. package/dist/core/runtime/broker/fault-retry.d.ts +15 -6
  289. package/dist/core/runtime/broker/fault-retry.js +142 -95
  290. package/dist/core/runtime/broker/inbox.d.ts +4 -32
  291. package/dist/core/runtime/broker/inbox.js +4 -92
  292. package/dist/core/runtime/broker/rebind.d.ts +1 -0
  293. package/dist/core/runtime/broker/rebind.js +21 -12
  294. package/dist/core/runtime/broker-persona-guidance.d.ts +1 -1
  295. package/dist/core/runtime/broker-persona-guidance.js +2 -13
  296. package/dist/core/runtime/broker.js +28 -22
  297. package/dist/core/runtime/close.d.ts +3 -9
  298. package/dist/core/runtime/close.js +16 -27
  299. package/dist/core/runtime/fault.d.ts +3 -93
  300. package/dist/core/runtime/fault.js +9 -419
  301. package/dist/core/runtime/kickoff.d.ts +3 -6
  302. package/dist/core/runtime/kickoff.js +12 -18
  303. package/dist/core/runtime/launch.js +1 -1
  304. package/dist/core/runtime/lifecycle.js +40 -7
  305. package/dist/core/runtime/placement.js +2 -2
  306. package/dist/core/runtime/recycle.js +8 -2
  307. package/dist/core/runtime/reset.js +22 -6
  308. package/dist/core/runtime/revive.js +226 -218
  309. package/dist/core/runtime/spawn.js +14 -3
  310. package/dist/core/scoped-state/db.d.ts +18 -0
  311. package/dist/core/scoped-state/db.js +135 -0
  312. package/dist/core/scoped-state/migrate.d.ts +8 -0
  313. package/dist/core/scoped-state/migrate.js +181 -0
  314. package/dist/core/scoped-state/paths.d.ts +9 -0
  315. package/dist/core/scoped-state/paths.js +27 -0
  316. package/dist/core/scoped-state/profiles.d.ts +12 -0
  317. package/dist/core/scoped-state/profiles.js +62 -0
  318. package/dist/core/scoped-state/providers.d.ts +16 -0
  319. package/dist/core/scoped-state/providers.js +8 -0
  320. package/dist/core/scoped-state/schema.d.ts +3 -0
  321. package/dist/core/scoped-state/schema.js +26 -0
  322. package/dist/core/scoped-state/settings.d.ts +28 -0
  323. package/dist/core/scoped-state/settings.js +82 -0
  324. package/dist/core/subscription-state.d.ts +29 -48
  325. package/dist/core/subscription-state.js +176 -712
  326. package/dist/core/worktree-close.js +4 -4
  327. package/dist/core/worktree-mutation-async.js +2 -2
  328. package/dist/core/worktree-sweep.js +11 -16
  329. package/dist/core/worktree.js +6 -12
  330. package/dist/daemon/__tests__/autostart-storm.test.js +1 -39
  331. package/dist/daemon/__tests__/helpers/source-daemon.d.ts +2 -2
  332. package/dist/daemon/__tests__/helpers/source-daemon.js +7 -6
  333. package/dist/daemon/__tests__/integration/migration-startup.test.js +59 -26
  334. package/dist/daemon/__tests__/node-deadline-lane.test.js +2 -1
  335. package/dist/daemon/__tests__/node-outcome-birth-invariants.test.js +39 -15
  336. package/dist/daemon/__tests__/node-outcome-delivery.test.js +39 -10
  337. package/dist/daemon/__tests__/reconciler-signature.test.js +2 -2
  338. package/dist/daemon/__tests__/subtree-filter-freshness.test.js +2 -2
  339. package/dist/daemon/api/__tests__/broker-settle-park.test.js +17 -12
  340. package/dist/daemon/api/__tests__/canvas-snapshot-fields.test.js +27 -5
  341. package/dist/daemon/api/__tests__/model-config.test.js +8 -8
  342. package/dist/daemon/api/__tests__/node-create-description.test.js +22 -5
  343. package/dist/daemon/api/__tests__/node-model-validation.test.js +21 -1
  344. package/dist/daemon/api/__tests__/nodes-activity-query.test.js +10 -12
  345. package/dist/daemon/api/__tests__/profile-launch-gates.test.js +4 -1
  346. package/dist/daemon/api/__tests__/profile-metadata-route.test.js +4 -1
  347. package/dist/daemon/api/__tests__/reopen-delivery.test.js +26 -8
  348. package/dist/daemon/api/__tests__/seam/api-server.test.js +24 -32
  349. package/dist/daemon/api/__tests__/seam/b10-attach-modelauth.test.js +4 -1
  350. package/dist/daemon/api/__tests__/seam/leaf-api-parity.test.js +5 -4
  351. package/dist/daemon/api/__tests__/seam/profile-delete.test.js +27 -41
  352. package/dist/daemon/api/__tests__/submit-result.test.js +3 -2
  353. package/dist/daemon/api/bridge.js +1 -1
  354. package/dist/daemon/api/handlers/bash-jobs.js +6 -7
  355. package/dist/daemon/api/handlers/broker-ops.js +47 -84
  356. package/dist/daemon/api/handlers/broker-recovery.d.ts +4 -0
  357. package/dist/daemon/api/handlers/broker-recovery.js +251 -0
  358. package/dist/daemon/api/handlers/canvas.js +2 -44
  359. package/dist/daemon/api/handlers/daemon.js +41 -0
  360. package/dist/daemon/api/handlers/feedback-comments.js +2 -2
  361. package/dist/daemon/api/handlers/health.js +10 -5
  362. package/dist/daemon/api/handlers/human-requests.js +168 -188
  363. package/dist/daemon/api/handlers/human.js +3 -151
  364. package/dist/daemon/api/handlers/inbox-page.d.ts +4 -0
  365. package/dist/daemon/api/handlers/inbox-page.js +89 -0
  366. package/dist/daemon/api/handlers/inbox.js +21 -120
  367. package/dist/daemon/api/handlers/messages.d.ts +1 -0
  368. package/dist/daemon/api/handlers/messages.js +73 -15
  369. package/dist/daemon/api/handlers/node-outcomes.js +58 -13
  370. package/dist/daemon/api/handlers/nodes.js +7 -13
  371. package/dist/daemon/api/handlers/reviews.js +4 -29
  372. package/dist/daemon/api/map.d.ts +25 -3
  373. package/dist/daemon/api/map.js +84 -14
  374. package/dist/daemon/api/server.js +68 -9
  375. package/dist/daemon/control.d.ts +18 -0
  376. package/dist/daemon/cron/disposition.d.ts +2 -0
  377. package/dist/daemon/cron/disposition.js +8 -5
  378. package/dist/daemon/cron/settle.js +37 -13
  379. package/dist/daemon/cron/sinks.d.ts +18 -1
  380. package/dist/daemon/cron/sinks.js +47 -93
  381. package/dist/daemon/crtrd-cli.js +4 -19
  382. package/dist/daemon/crtrd.d.ts +2 -0
  383. package/dist/daemon/crtrd.js +206 -81
  384. package/dist/daemon/fleet.js +5 -6
  385. package/dist/daemon/human/finish.d.ts +12 -24
  386. package/dist/daemon/human/finish.js +88 -285
  387. package/dist/daemon/human/settle.d.ts +40 -0
  388. package/dist/daemon/human/settle.js +89 -0
  389. package/dist/daemon/human/sweep.d.ts +20 -5
  390. package/dist/daemon/human/sweep.js +56 -60
  391. package/dist/daemon/manage.d.ts +21 -16
  392. package/dist/daemon/manage.js +85 -51
  393. package/dist/daemon/messaging/node-message.d.ts +1 -1
  394. package/dist/daemon/messaging/node-message.js +9 -12
  395. package/dist/daemon/park-activity.js +3 -3
  396. package/dist/daemon/reconcilers/bash-deadline.js +6 -7
  397. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  398. package/dist/daemon/reconcilers/broker-supervision.js +41 -19
  399. package/dist/daemon/reconcilers/controller-death.js +6 -18
  400. package/dist/daemon/reconcilers/delivery-lane.d.ts +9 -0
  401. package/dist/daemon/reconcilers/delivery-lane.js +130 -0
  402. package/dist/daemon/reconcilers/live-obligation.js +3 -3
  403. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  404. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -1
  405. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +10 -12
  406. package/dist/daemon/reconcilers/node-lifecycle/tick.js +5 -5
  407. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  408. package/dist/daemon/reconcilers/pending-review-submit.js +3 -3
  409. package/dist/daemon/reconcilers/storage-maintenance.d.ts +2 -8
  410. package/dist/daemon/reconcilers/storage-maintenance.js +13 -43
  411. package/dist/daemon/review/companion.js +5 -11
  412. package/dist/daemon/review/deliver.d.ts +1 -5
  413. package/dist/daemon/review/deliver.js +3 -52
  414. package/dist/daemon/review/finish.d.ts +2 -27
  415. package/dist/daemon/review/finish.js +79 -263
  416. package/dist/daemon/review/sweep.d.ts +3 -10
  417. package/dist/daemon/review/sweep.js +13 -131
  418. package/dist/daemon/startup-policy.d.ts +0 -5
  419. package/dist/daemon/startup-policy.js +0 -5
  420. package/dist/index.d.ts +2 -1
  421. package/dist/index.js +1 -1
  422. package/dist/migrations/__tests__/activation-concurrency.test.js +3 -2
  423. package/dist/migrations/__tests__/activation.test.js +9 -6
  424. package/dist/migrations/activation.d.ts +3 -2
  425. package/dist/migrations/activation.js +2 -4
  426. package/dist/migrations/corpus.d.ts +2 -5
  427. package/dist/migrations/corpus.js +9 -20
  428. package/dist/migrations/runner.d.ts +3 -1
  429. package/dist/migrations/runner.js +6 -2
  430. package/dist/pi-extensions/__tests__/canvas-context-intro.test.js +21 -89
  431. package/dist/pi-extensions/__tests__/canvas-goal-capture-envelope.test.js +4 -2
  432. package/dist/pi-extensions/__tests__/canvas-stophook-agentend.test.js +51 -33
  433. package/dist/pi-extensions/__tests__/canvas-stophook-context-nudge.test.js +16 -2
  434. package/dist/pi-extensions/__tests__/pre-command-gate.test.js +13 -1
  435. package/dist/pi-extensions/canvas-inbox-watcher.js +98 -244
  436. package/dist/pi-extensions/canvas-passive-context.d.ts +4 -8
  437. package/dist/pi-extensions/canvas-passive-context.js +85 -37
  438. package/dist/pi-extensions/canvas-stophook.js +47 -31
  439. package/dist/shared/env.d.ts +1 -0
  440. package/dist/shared/env.js +3 -0
  441. package/package.json +1 -1
  442. package/runtime.lock.json +5 -5
  443. package/dist/clients/attach/__tests__/page-block.test.js +0 -54
  444. package/dist/clients/inbox/review-visibility.d.ts +0 -5
  445. package/dist/clients/inbox/review-visibility.js +0 -19
  446. package/dist/commands/canvas-rebuild-index.d.ts +0 -2
  447. package/dist/commands/canvas-rebuild-index.js +0 -46
  448. package/dist/core/__tests__/human-cancel-guard.test.js +0 -110
  449. package/dist/core/__tests__/human-deliver.test.js +0 -256
  450. package/dist/core/__tests__/human-node-not-supervised.test.d.ts +0 -1
  451. package/dist/core/__tests__/human-node-not-supervised.test.js +0 -89
  452. package/dist/core/__tests__/integration/human-deliver-e2e.test.d.ts +0 -1
  453. package/dist/core/__tests__/integration/human-deliver-e2e.test.js +0 -131
  454. package/dist/core/__tests__/phase4-review-store.test.d.ts +0 -1
  455. package/dist/core/__tests__/phase4-review-store.test.js +0 -144
  456. package/dist/core/__tests__/watchdog-abort-arms-retry.test.d.ts +0 -1
  457. package/dist/core/__tests__/watchdog-abort-arms-retry.test.js +0 -110
  458. package/dist/core/canvas/human-deliveries.d.ts +0 -39
  459. package/dist/core/canvas/human-deliveries.js +0 -75
  460. package/dist/core/canvas/node-outcome-deliveries.d.ts +0 -64
  461. package/dist/core/canvas/node-outcome-deliveries.js +0 -159
  462. package/dist/core/feed/passive.d.ts +0 -3
  463. package/dist/core/feed/passive.js +0 -53
  464. package/dist/core/human/__tests__/inbox-cancel-worker.d.ts +0 -1
  465. package/dist/core/human/__tests__/inbox-cancel-worker.js +0 -7
  466. package/dist/core/human/__tests__/inbox-claim-worker.d.ts +0 -1
  467. package/dist/core/human/__tests__/inbox-claim-worker.js +0 -17
  468. package/dist/core/human/__tests__/inbox-stale-claim-worker.d.ts +0 -1
  469. package/dist/core/human/__tests__/inbox-stale-claim-worker.js +0 -8
  470. package/dist/core/human/__tests__/integration/inbox-core.test.d.ts +0 -1
  471. package/dist/core/human/__tests__/integration/inbox-core.test.js +0 -145
  472. package/dist/core/human/__tests__/page-tickets.test.d.ts +0 -1
  473. package/dist/core/human/__tests__/page-tickets.test.js +0 -161
  474. package/dist/core/review/ticket-filter.d.ts +0 -17
  475. package/dist/core/review/ticket-filter.js +0 -21
  476. package/dist/core/runtime/broker/passive.d.ts +0 -17
  477. package/dist/core/runtime/broker/passive.js +0 -44
  478. package/dist/core/runtime/busy.d.ts +0 -46
  479. package/dist/core/runtime/busy.js +0 -150
  480. package/dist/daemon/__tests__/startup-block-marker.test.d.ts +0 -1
  481. package/dist/daemon/__tests__/startup-block-marker.test.js +0 -86
  482. package/dist/daemon/api/__tests__/review-terminal-conflict.test.d.ts +0 -1
  483. package/dist/daemon/api/__tests__/review-terminal-conflict.test.js +0 -98
  484. package/dist/daemon/human/deliver-action.d.ts +0 -3
  485. package/dist/daemon/human/deliver-action.js +0 -9
  486. package/dist/daemon/node-outcome/deliver-outcome.d.ts +0 -3
  487. package/dist/daemon/node-outcome/deliver-outcome.js +0 -9
  488. package/dist/daemon/reconcilers/human-delivery-lane.d.ts +0 -10
  489. package/dist/daemon/reconcilers/human-delivery-lane.js +0 -41
  490. package/dist/daemon/reconcilers/node-outcome-delivery-lane.d.ts +0 -10
  491. package/dist/daemon/reconcilers/node-outcome-delivery-lane.js +0 -41
  492. package/dist/daemon/startup-block-marker.d.ts +0 -25
  493. package/dist/daemon/startup-block-marker.js +0 -99
  494. /package/dist/{clients/attach/__tests__/page-block.test.d.ts → api/dto/mail.js} +0 -0
  495. /package/dist/{commands/sys/__tests__/migrate.test.d.ts → api/dto/recovery.js} +0 -0
  496. /package/dist/{core/__tests__/human-cancel-guard.test.d.ts → commands/__tests__/integration/migrate.test.d.ts} +0 -0
  497. /package/dist/core/__tests__/{human-deliver.test.d.ts → integration/fresh-home-commands.test.d.ts} +0 -0
@@ -2,8 +2,10 @@
2
2
  import { setTimeout as sleep } from 'node:timers/promises';
3
3
  import { ApiError } from '../../../api/errors.js';
4
4
  import { getNode } from '../../../core/canvas/canvas.js';
5
- import { armOutcomeDelivery, disarmOutcomeDelivery, readOutcomeDelivery, } from '../../../core/canvas/node-outcome-deliveries.js';
5
+ import { armExternalActionDelivery, activateArmedExternalActionDelivery, readExternalActionDelivery } from '../../../core/canvas/deliveries.js';
6
+ import { withCanvasWrite } from '../../../core/canvas/db.js';
6
7
  import { OUTCOME_PAYLOAD_MAX_BYTES } from '../../../core/canvas/types.js';
8
+ import { composeNodeOutcomeDocument } from '../../../core/runtime/outcome-document.js';
7
9
  import { HUMAN_ACTION_NAME_PATTERN } from '../../../core/human/action-binding.js';
8
10
  import { resolveHumanAction } from '../../../core/human-actions.js';
9
11
  import { toNodeOutcomeDTO, toOutcomeDeliveryDTO } from '../map.js';
@@ -82,6 +84,53 @@ function parseRegistration(body) {
82
84
  }
83
85
  return body['payload'] === undefined ? { action } : { action, payload: body['payload'] };
84
86
  }
87
+ function outcomeKey(nodeId) { return `node-outcome:${nodeId}`; }
88
+ function outcomeView(row) {
89
+ const adapter = row.adapter;
90
+ if (adapter?.adapter !== 'subprocess' || !Array.isArray(adapter.argv) || !adapter.argv.every((arg) => typeof arg === 'string') || typeof adapter.cwd !== 'string')
91
+ throw new Error(`outcome delivery ${row.deliveryId} has an invalid subprocess adapter`);
92
+ return { nodeId: row.idempotencyKey?.slice('node-outcome:'.length) ?? '', state: row.state === 'handed_off' ? 'running' : row.state === 'acknowledged' ? 'accepted' : row.state, attempt: row.attempts, actionName: row.destinationId, argv: adapter.argv, cwd: adapter.cwd, configOrigin: typeof adapter.config_origin === 'string' ? adapter.config_origin : '', payload: adapter.payload ?? null, document: null, nextAttemptAt: row.nextAttemptAt ?? 0, claimedAt: row.claimedAt, claimOwner: row.claimOwner, acceptedAt: row.acknowledgedAt, permanentFailedAt: row.failedAt, lastFailure: row.lastFailure, createdAt: row.createdAt, updatedAt: row.updatedAt };
93
+ }
94
+ function nodeAtOutcome(node) {
95
+ const reason = node.outcome_reason;
96
+ let status;
97
+ let intent;
98
+ if (node.outcome_kind === 'result' || reason === 'finished' || reason === 'declined') {
99
+ status = 'done';
100
+ intent = 'done';
101
+ }
102
+ else if (reason === 'parked') {
103
+ status = 'done';
104
+ intent = 'parked';
105
+ }
106
+ else if (reason === 'closed' || reason === 'retired' || reason === 'stranded' || reason === 'deadline_exceeded') {
107
+ status = 'canceled';
108
+ intent = null;
109
+ }
110
+ else {
111
+ status = 'dead';
112
+ intent = null;
113
+ }
114
+ return { ...node, status, intent, terminal_reason: reason };
115
+ }
116
+ function armOutcomeExternalAction(node, target, payload) {
117
+ return withCanvasWrite((db) => {
118
+ const existing = readExternalActionDelivery(outcomeKey(node.node_id));
119
+ if (existing !== null && existing.state !== 'armed')
120
+ return null;
121
+ armExternalActionDelivery(db, { destinationId: target.action, adapter: { adapter: 'subprocess', argv: target.argv, cwd: target.cwd, config_origin: target.configOrigin, payload: payload ?? null }, idempotencyKey: outcomeKey(node.node_id) });
122
+ if (node.outcome_at !== null) {
123
+ if (node.outcome_kind === null || node.outcome_reason === null)
124
+ throw new Error(`outcome latch is incomplete for node ${node.node_id}`);
125
+ const document = JSON.stringify(composeNodeOutcomeDocument({ node: nodeAtOutcome(node), outcome: { kind: node.outcome_kind, reason: node.outcome_reason, at: node.outcome_at, revision: node.outcome_revision, detailJson: node.outcome_detail_json ?? null }, action: { name: target.action, payload: payload ?? null }, finalReport: node.final_report }));
126
+ activateArmedExternalActionDelivery(db, { idempotencyKey: outcomeKey(node.node_id), label: node.node_id, bodyJson: document, supersede: false });
127
+ }
128
+ const delivery = readExternalActionDelivery(outcomeKey(node.node_id));
129
+ if (delivery === null)
130
+ throw new Error(`outcome delivery was not registered for ${node.node_id}`);
131
+ return outcomeView(delivery);
132
+ });
133
+ }
85
134
  function resolveAction(action, cwd) {
86
135
  const resolution = resolveHumanAction(action, cwd);
87
136
  if (!('kind' in resolution))
@@ -97,14 +146,7 @@ function handlePutDelivery(ctx) {
97
146
  const node = requireNode(id);
98
147
  const request = parseRegistration(ctx.body);
99
148
  const target = resolveAction(request.action, node.cwd);
100
- const delivery = armOutcomeDelivery({
101
- nodeId: node.node_id,
102
- actionName: request.action,
103
- argv: target.argv,
104
- cwd: target.cwd,
105
- configOrigin: target.configOrigin,
106
- ...(request.payload === undefined ? {} : { payload: request.payload }),
107
- });
149
+ const delivery = armOutcomeExternalAction(node, { action: request.action, ...target }, request.payload);
108
150
  if (delivery === null) {
109
151
  throw new ApiError(409, 'outcome_delivery_settled', 'outcome delivery has already started or settled');
110
152
  }
@@ -113,19 +155,22 @@ function handlePutDelivery(ctx) {
113
155
  /** GET /v1/nodes/:id/outcome-delivery — inspect the one durable registration. */
114
156
  function handleGetDelivery(ctx) {
115
157
  const id = ctx.params['id'] ?? '';
116
- const delivery = readOutcomeDelivery(id);
158
+ const delivery = readExternalActionDelivery(outcomeKey(id));
117
159
  if (delivery === null)
118
160
  throw new ApiError(404, 'outcome_delivery_not_found', `no outcome delivery for node ${id}`);
119
- return { status: 200, body: toOutcomeDeliveryDTO(delivery) };
161
+ return { status: 200, body: toOutcomeDeliveryDTO(outcomeView(delivery)) };
120
162
  }
121
163
  /** DELETE /v1/nodes/:id/outcome-delivery — disarm only before delivery begins. */
122
164
  function handleDeleteDelivery(ctx) {
123
165
  const id = ctx.params['id'] ?? '';
124
- const current = readOutcomeDelivery(id);
166
+ const current = readExternalActionDelivery(outcomeKey(id));
125
167
  if (current !== null && current.state !== 'armed') {
126
168
  throw new ApiError(409, 'outcome_delivery_settled', 'outcome delivery has already started or settled');
127
169
  }
128
- disarmOutcomeDelivery(id);
170
+ if (current !== null)
171
+ withCanvasWrite((db) => {
172
+ db.prepare("DELETE FROM deliveries WHERE delivery_id = ? AND state = 'armed'").run(current.deliveryId);
173
+ });
129
174
  return { status: 204 };
130
175
  }
131
176
  export const nodeOutcomeRoutes = [
@@ -16,6 +16,8 @@ import { nowIso } from '../../../core/fs-utils.js';
16
16
  import { assertLaunchModelRegistered, forkNode, spawnChildPrepared } from '../../../core/runtime/spawn.js';
17
17
  import { childrenOf, getNode, listNodes, subscribersOf, subscriptionsOf, setMessageWait, updateNode } from '../../../core/canvas/canvas.js';
18
18
  import { subtreeIds } from '../../../core/canvas/nav-model.js';
19
+ import { withCanvasWrite } from '../../../core/canvas/db.js';
20
+ import { unbindSession } from '../../../core/canvas/sessions.js';
19
21
  import { ticketCountsForNodes } from '../../../core/canvas/attention.js';
20
22
  import { contextDir, reportsDir } from '../../../core/canvas/paths.js';
21
23
  import { nodeArtifacts } from '../../../core/canvas/history.js';
@@ -32,8 +34,6 @@ import { renameWindow } from '../../../core/runtime/placement.js';
32
34
  import { buildLaunchSpecAsync, isProviderPinnedModelToken, normalizeModel, readMergedLaunchConfigAsync } from '../../../core/runtime/launch.js';
33
35
  import { modelRequestFromConfig } from '../../../core/model-routes.js';
34
36
  import { BrokerUnreachableError } from '../../../core/runtime/broker-request.js';
35
- import { readFault } from '../../../core/runtime/fault.js';
36
- import { activeFaultForDisplay } from '../../../core/canvas/render-source.js';
37
37
  import { isBrokerLive, persistDormantModel, setModelLive } from '../../../core/runtime/model-swap.js';
38
38
  import { boundFleet } from '../../../core/runtime/fleet.js';
39
39
  import { writeOutputSchema } from '../../../core/runtime/structured-output.js';
@@ -72,16 +72,7 @@ function edgesFor(id) {
72
72
  /** Re-read a node fresh and project its detail DTO (post-action response). */
73
73
  function detailOf(id) {
74
74
  const meta = requireMeta(id);
75
- const fault = activeFaultForDisplay(meta, readFault(id));
76
- return {
77
- ...toNodeDetailDTO(meta, edgesFor(id)),
78
- fault: fault === null ? null : {
79
- link: fault.link,
80
- kind: fault.kind,
81
- retry: { disposition: fault.retry.disposition },
82
- since: fault.since,
83
- },
84
- };
75
+ return toNodeDetailDTO(meta, edgesFor(id));
85
76
  }
86
77
  /** Count context + report files under a node (the context-roster `files`). */
87
78
  function countFiles(id) {
@@ -836,7 +827,10 @@ export async function handleConfig(ctx, deps = {}) {
836
827
  next: 'Create the replacement directory or send an existing absolute directory.',
837
828
  });
838
829
  }
839
- updateNode(id, { cwd: resolved, pi_session_id: null, pi_session_file: null });
830
+ withCanvasWrite(() => {
831
+ updateNode(id, { cwd: resolved });
832
+ unbindSession(id);
833
+ });
840
834
  return { status: 200, body: detailOf(id) };
841
835
  }
842
836
  let meta = requireMeta(id);
@@ -1,12 +1,9 @@
1
1
  // Canonical daemon-owned review lifecycle routes. Handlers validate the full
2
2
  // wire request, delegate lifecycle work to review services, and project only
3
3
  // committed daemon state.
4
- import { isSafeNodeId, reviewResultPath } from '../../../core/canvas/paths.js';
5
- import { responsePath } from '../../../core/human/convention.js';
6
- import { ticketDir } from '../../../core/human/root.js';
4
+ import { isSafeNodeId } from '../../../core/canvas/paths.js';
7
5
  import { createReview } from '../../../core/review/birth.js';
8
- import { readAnchorBase, getReviewByBridge, listReviews, requireVisibleReview } from '../../../core/review/store.js';
9
- import { ReviewOperationError } from '../../../core/review/types.js';
6
+ import { readAnchorBase, listReviews, requireVisibleReview } from '../../../core/review/store.js';
10
7
  import { cancelReview, submitReviewApproval } from '../../review/finish.js';
11
8
  import { toFeedbackResultDTO, toReviewDTO } from '../map.js';
12
9
  import { invalidRequest as rejectRequest, objectBody, optionalString, requireParam, requiredString, } from './validate.js';
@@ -19,20 +16,9 @@ function invalidRequest(violations) {
19
16
  function requireReviewId(ctx, violations) {
20
17
  return requireParam(ctx, 'review_id', 'must be a safe review id', isSafeNodeId, violations);
21
18
  }
22
- function requireBridgeNodeId(ctx, violations) {
23
- return requireParam(ctx, 'bridge_node_id', 'must be a safe node id', isSafeNodeId, violations);
24
- }
25
- function approvedResultPath(review) {
26
- if (review.origin_kind === 'inline')
27
- return reviewResultPath(review.review_id);
28
- if (review.bridge_node_id === null)
29
- throw new Error(`approved ticket review lacks its bridge node: ${review.review_id}`);
30
- return responsePath(ticketDir(review.bridge_node_id));
31
- }
32
19
  function toReviewResponseDTO(review) {
33
- return review.state === 'approved'
34
- ? toReviewDTO(review, { result_path: approvedResultPath(review) })
35
- : toReviewDTO(review);
20
+ const dto = toReviewDTO(review, review.state === 'approved' ? { result_path: `${review.review_dir}/result.json` } : {});
21
+ return { ...dto, review_dir: review.review_dir };
36
22
  }
37
23
  function parseCreate(ctx) {
38
24
  const violations = [];
@@ -158,16 +144,6 @@ function handleRead(ctx) {
158
144
  invalidRequest(violations);
159
145
  return { status: 200, body: toReviewResponseDTO(requireVisibleReview(reviewId)) };
160
146
  }
161
- function handleByBridge(ctx) {
162
- const violations = [];
163
- const bridgeNodeId = requireBridgeNodeId(ctx, violations);
164
- if (violations.length > 0 || bridgeNodeId === undefined)
165
- invalidRequest(violations);
166
- const review = getReviewByBridge(bridgeNodeId);
167
- if (review !== null)
168
- return { status: 200, body: toReviewResponseDTO(review) };
169
- throw new ReviewOperationError('unknown_review', 'review was not found', { received: bridgeNodeId });
170
- }
171
147
  async function handleSubmit(ctx) {
172
148
  const violations = [];
173
149
  const reviewId = requireReviewId(ctx, violations);
@@ -217,7 +193,6 @@ function handleDocument(ctx) {
217
193
  export const reviewRoutes = [
218
194
  { method: 'POST', pattern: '/v1/human/reviews', handler: handleCreate },
219
195
  { method: 'GET', pattern: '/v1/human/reviews', handler: handleList },
220
- { method: 'GET', pattern: '/v1/human/reviews/by-bridge/:bridge_node_id', handler: handleByBridge },
221
196
  { method: 'GET', pattern: '/v1/human/reviews/:review_id', handler: handleRead },
222
197
  { method: 'POST', pattern: '/v1/human/reviews/:review_id/submit', handler: handleSubmit },
223
198
  { method: 'POST', pattern: '/v1/human/reviews/:review_id/cancel', handler: handleCancel },
@@ -1,5 +1,4 @@
1
1
  import type { ManagedWorktree, NodeMeta, NodeRow, NodeRuntime, SubscriptionRef } from '../../core/canvas/types.js';
2
- import type { OutcomeDeliveryRecord } from '../../core/canvas/node-outcome-deliveries.js';
3
2
  import type { ReviewComment, ReviewCommentEvent, ReviewErrorCode, ReviewRecord, ReviewResult } from '../../core/review/types.js';
4
3
  import { type Cron, type CronRunRecord } from '../../core/canvas/crons.js';
5
4
  import type { ProfileEntry } from '../../core/profiles/manifest.js';
@@ -7,11 +6,34 @@ import type { ReviveResult } from '../../core/runtime/revive.js';
7
6
  import type { CloseNodeResult } from '../../core/runtime/close.js';
8
7
  import { type PushResult } from '../../core/feed/feed.js';
9
8
  import type { PageFeedback, PageFeedbackComment } from '../../core/human/feedback.js';
10
- import type { CloseResultDTO, CronDTO, CronRunDTO, ErrorBody, NodeEdgesDTO, NodeOutcomeDTO, NodePathsDTO, NodeStatusDTO, OutcomeDeliveryDTO, NodeSummaryDTO, NodeDetailDTO, NodeWorktreeDTO, ProfileDTO, ReviewCommentDTO, ReviewCommentEventDTO, ReviewDTO, FeedbackResultDTO, PageFeedbackCommentDTO, PageFeedbackDTO, PushReportResultDTO, ReviveResultDTO, SubscriptionDTO } from '../../api/index.js';
9
+ import type { OnDiskMigrationRunResult } from '../../migrations/runner.js';
10
+ import type { CloseResultDTO, CronDTO, CronRunDTO, ErrorBody, NodeEdgesDTO, NodeOutcomeDTO, NodePathsDTO, NodeStatusDTO, OutcomeDeliveryDTO, NodeSummaryDTO, NodeDetailDTO, NodeWorktreeDTO, ProfileDTO, ReviewCommentDTO, ReviewCommentEventDTO, ReviewDTO, FeedbackResultDTO, PageFeedbackCommentDTO, PageFeedbackDTO, PushReportResultDTO, ReviveResultDTO, MigrateStateDTO, SubscriptionDTO } from '../../api/index.js';
11
+ export declare function toMigrateStateDTO(result: OnDiskMigrationRunResult, options: {
12
+ resumed: boolean;
13
+ resumeError?: string;
14
+ }): MigrateStateDTO;
11
15
  /** Project a latched outcome, or null while this node remains unsettled. */
12
16
  export declare function toNodeOutcomeDTO(node: Pick<NodeMeta, 'node_id' | 'final_report'> & NodeRuntime): NodeOutcomeDTO | null;
17
+ /** The outcome-delivery fields exposed by the API. The delivery store supplies this projection directly. */
18
+ export interface OutcomeDeliveryDTOInput {
19
+ nodeId: string;
20
+ state: 'armed' | 'pending' | 'running' | 'accepted' | 'permanent_failed';
21
+ actionName: string;
22
+ attempt: number;
23
+ nextAttemptAt: number;
24
+ acceptedAt: number | null;
25
+ permanentFailedAt: number | null;
26
+ lastFailure: {
27
+ kind: 'exit' | 'signal' | 'timeout' | 'spawn_error';
28
+ exitCode?: number;
29
+ signal?: string;
30
+ message?: string;
31
+ } | null;
32
+ createdAt: number;
33
+ updatedAt: number;
34
+ }
13
35
  /** Project a durable delivery row without exposing its execution coordinates or stderr tail. */
14
- export declare function toOutcomeDeliveryDTO(row: OutcomeDeliveryRecord): OutcomeDeliveryDTO;
36
+ export declare function toOutcomeDeliveryDTO(row: OutcomeDeliveryDTOInput): OutcomeDeliveryDTO;
15
37
  /** Project the queryable row (what `listNodes` yields) into a summary DTO. */
16
38
  export declare function toNodeSummaryDTO(row: NodeRow): NodeSummaryDTO;
17
39
  /** The subscription/child edges a detail projection needs. The handler gathers
@@ -10,11 +10,12 @@
10
10
  // reasonable projections; this module is what makes them concrete, so any DTO
11
11
  // field that projection proves wrong is corrected here at the source.
12
12
  import { existsSync, readFileSync } from 'node:fs';
13
+ import { join } from 'node:path';
13
14
  import { outputResultPath } from '../../core/runtime/structured-output.js';
14
15
  import { ReviewOperationError as ReviewOperationErrorClass } from '../../core/review/types.js';
15
16
  import { cronSinkDisplay } from '../../core/canvas/crons.js';
16
17
  import { isProfilePaused, sanitizeProfileMetadata } from '../../core/profiles/manifest.js';
17
- import { contextDir, inboxPath, nodeDir, nodeMetaPath, reportsDir, reviewResultPath, transcriptPath, viewSocketPath, } from '../../core/canvas/paths.js';
18
+ import { contextDir, nodeDir, nodeMetaPath, reportsDir, transcriptPath, viewSocketPath, } from '../../core/canvas/paths.js';
18
19
  import { FinalizationError } from '../../core/feed/feed.js';
19
20
  import { NodeIdConflictError } from '../../core/runtime/nodes.js';
20
21
  import { readContextTokens } from '../../core/canvas/telemetry.js';
@@ -22,8 +23,82 @@ import { CrtrError } from '../../core/errors.js';
22
23
  import { WorktreeError } from '../../core/worktree.js';
23
24
  import { ApiError } from '../../api/errors.js';
24
25
  import { ExitCode } from '../../types.js';
25
- import { responsePath } from '../../core/human/convention.js';
26
- import { ticketDir } from '../../core/human/root.js';
26
+ export function toMigrateStateDTO(result, options) {
27
+ const { discovery, snapshots } = result;
28
+ return {
29
+ profiles: result.profiles,
30
+ stores: discovery.stores.length,
31
+ changed: result.changed,
32
+ applied: result.applied,
33
+ skipped: result.skipped,
34
+ blockers: result.blockers.map((blocker) => ({
35
+ kind: blocker.kind,
36
+ message: blocker.message,
37
+ ...(blocker.storeRoot === undefined ? {} : { store: blocker.storeRoot }),
38
+ ...(blocker.targetId === undefined ? {} : { target: blocker.targetId }),
39
+ ...(blocker.path === undefined ? {} : { path: blocker.path }),
40
+ ...(blocker.name === undefined ? {} : { name: blocker.name }),
41
+ ...(blocker.paths === undefined ? {} : { paths: blocker.paths }),
42
+ })),
43
+ discovery_roots: discovery.roots.map((row) => ({
44
+ reason: row.reason,
45
+ root: row.root,
46
+ boundary: row.boundary,
47
+ ...(row.detail === undefined ? {} : { detail: row.detail }),
48
+ })),
49
+ discovered_stores: discovery.stores.map((store) => ({
50
+ store: store.key,
51
+ scope: store.descriptor.scope,
52
+ namespace: store.descriptor.namespace,
53
+ mount_status: store.descriptor.mountStatus,
54
+ writable: store.writable,
55
+ reasons: [...new Set(store.discovery.map((row) => row.reason))],
56
+ targets: store.targets,
57
+ docs: snapshots.get(store.key)?.docs.length ?? 0,
58
+ })),
59
+ discovered_targets: discovery.targets.map((target) => ({
60
+ id: target.id,
61
+ kind: target.kind,
62
+ origin: target.origin,
63
+ cwd: target.target.cwd,
64
+ profile_id: target.target.profileId,
65
+ node_id: target.target.nodeId,
66
+ stores: target.storeKeys,
67
+ })),
68
+ repository_namespaces: result.repositories.map((row) => ({
69
+ repository_root: row.repositoryRoot,
70
+ repository_key: row.repositoryKey,
71
+ declaration_path: row.declarationPath,
72
+ namespace: row.namespace,
73
+ source: row.source,
74
+ action: row.action,
75
+ })),
76
+ store_prefixes: result.storePrefixes.map((row) => ({
77
+ store_root: row.storeRoot,
78
+ owner_dir: row.ownerDir,
79
+ repository_root: row.repositoryRoot,
80
+ owner_relative_path: row.ownerRelativePath,
81
+ old_prefix: row.oldPrefix,
82
+ old_rule: row.oldRule,
83
+ effective_prefix: row.effectivePrefix,
84
+ nested_declaration_action: row.nestedDeclarationAction,
85
+ front_door_action: row.frontDoorAction,
86
+ })),
87
+ renames: result.renames.map((row) => ({ store_root: row.storeRoot, path: row.path, from: row.from, to: row.to })),
88
+ references: result.references.map((row) => ({ store_root: row.storeRoot, path: row.path, kind: row.kind, from: row.from, to: row.to })),
89
+ dryRun: result.dryRun,
90
+ blocked: result.blocked,
91
+ corpus_phase: result.corpusPhase,
92
+ wrote: {
93
+ profile_manifests: result.wrote.profileManifests,
94
+ documents: result.wrote.documents,
95
+ corpus_consumers: result.wrote.corpusConsumers,
96
+ corpus_identities: result.wrote.corpusIdentities,
97
+ },
98
+ resumed: options.resumed,
99
+ ...(options.resumeError === undefined ? {} : { resume_error: options.resumeError }),
100
+ };
101
+ }
27
102
  // Node projections
28
103
  /** Read the optional machine result without letting a missing or malformed sidecar obscure the durable outcome row. */
29
104
  function readStructuredResult(nodeId) {
@@ -122,6 +197,8 @@ export function toNodeSummaryDTO(row) {
122
197
  finalized_at: row.finalized_at ?? null,
123
198
  deadline_at: row.deadline_at ?? null,
124
199
  outcome: toNodeOutcomeDTO(row),
200
+ fault: row.fault && row.fault.link !== 'broker↔crtrd' ? { ...row.fault, link: row.fault.link } : null,
201
+ streaming: row.streaming ?? false,
125
202
  };
126
203
  }
127
204
  /** Project a node's spine + subscription edges (absorbs `managers`/`paths`). */
@@ -142,7 +219,6 @@ export function toNodePathsDTO(nodeId) {
142
219
  context_dir: contextDir(nodeId),
143
220
  reports_dir: reportsDir(nodeId),
144
221
  meta_path: nodeMetaPath(nodeId),
145
- inbox_path: inboxPath(nodeId),
146
222
  transcript_path: transcriptPath(nodeId),
147
223
  view_socket: viewSocketPath(nodeId),
148
224
  };
@@ -197,6 +273,8 @@ export function toNodeDetailDTO(meta, edges) {
197
273
  finalized_at: meta.finalized_at ?? null,
198
274
  deadline_at: meta.deadline_at ?? null,
199
275
  outcome: toNodeOutcomeDTO(meta),
276
+ fault: meta.fault && meta.fault.link !== 'broker↔crtrd' ? { ...meta.fault, link: meta.fault.link } : null,
277
+ streaming: meta.streaming ?? false,
200
278
  creator: meta.creator ?? null,
201
279
  edges: toNodeEdgesDTO(meta, edges),
202
280
  paths: toNodePathsDTO(meta.node_id),
@@ -363,7 +441,7 @@ export function toReviewDTO(row, extras = {}) {
363
441
  review_id: row.review_id,
364
442
  origin_kind: row.origin_kind,
365
443
  origin_node_id: row.origin_node_id,
366
- bridge_node_id: row.bridge_node_id,
444
+ review_dir: row.review_dir,
367
445
  companion_node_id: row.companion_node_id,
368
446
  file: row.file,
369
447
  state: row.state,
@@ -601,15 +679,7 @@ function reviewErrorDetails(err) {
601
679
  function terminalConflictReviewDTO(review) {
602
680
  if (review.state !== 'approved')
603
681
  return toReviewDTO(review);
604
- const result_path = review.origin_kind === 'inline'
605
- ? reviewResultPath(review.review_id)
606
- : responsePath(ticketDir(requireBridgeNodeId(review)));
607
- return toReviewDTO(review, { result_path });
608
- }
609
- function requireBridgeNodeId(review) {
610
- if (review.bridge_node_id === null)
611
- throw new Error(`approved ticket review lacks its bridge node: ${review.review_id}`);
612
- return review.bridge_node_id;
682
+ return toReviewDTO(review, { result_path: join(review.review_dir, 'result.json') });
613
683
  }
614
684
  function statusForExitCode(exitCode) {
615
685
  switch (exitCode) {
@@ -24,21 +24,22 @@ import { emitEvent } from '../../core/events/emit.js';
24
24
  import { envCrtrdTcp, envCrtrdToken } from '../../shared/env.js';
25
25
  import { Router } from './router.js';
26
26
  import { handleAttachUpgrade } from './bridge.js';
27
+ import { boundDaemonControl } from '../control.js';
27
28
  import { attachRoutes } from './handlers/attach.js';
28
29
  import { bashJobRoutes } from './handlers/bash-jobs.js';
29
30
  import { brokerOperationRoutes } from './handlers/broker-ops.js';
31
+ import { brokerRecoveryRoutes, nodeFaultRoutes } from './handlers/broker-recovery.js';
30
32
  import { canvasRoutes } from './handlers/canvas.js';
31
33
  import { chatInventoryRoutes } from './handlers/chat-inventory.js';
32
34
  import { daemonRoutes } from './handlers/daemon.js';
33
35
  import { fileRoutes } from './handlers/files.js';
34
36
  import { focusRoutes } from './handlers/focus.js';
35
37
  import { healthRoutes } from './handlers/health.js';
36
- import { humanRoutes } from './handlers/human.js';
37
38
  import { humanRequestRoutes } from './handlers/human-requests.js';
38
39
  import { inboxRoutes } from './handlers/inbox.js';
39
40
  import { feedbackCommentRoutes } from './handlers/feedback-comments.js';
40
41
  import { memoryRoutes } from './handlers/memory.js';
41
- import { messageRoutes } from './handlers/messages.js';
42
+ import { brokerMailRoutes, messageRoutes } from './handlers/messages.js';
42
43
  import { modelAuthRoutes } from './handlers/modelauth.js';
43
44
  import { modelConfigRoutes } from './handlers/model-config.js';
44
45
  import { nodeRoutes } from './handlers/nodes.js';
@@ -62,7 +63,10 @@ function buildRouter() {
62
63
  .registerAll(nodeOutcomeRoutes)
63
64
  .registerAll(bashJobRoutes)
64
65
  .registerAll(brokerOperationRoutes)
66
+ .registerAll(brokerRecoveryRoutes)
67
+ .registerAll(nodeFaultRoutes)
65
68
  .registerAll(worktreeRoutes)
69
+ .registerAll(brokerMailRoutes)
66
70
  .registerAll(messageRoutes)
67
71
  .registerAll(reportRoutes)
68
72
  .registerAll(attachRoutes)
@@ -75,7 +79,6 @@ function buildRouter() {
75
79
  .registerAll(profileRoutes)
76
80
  .registerAll(modelAuthRoutes)
77
81
  .registerAll(modelConfigRoutes)
78
- .registerAll(humanRoutes)
79
82
  .registerAll(reviewRoutes)
80
83
  .registerAll(reviewCommentRoutes)
81
84
  .registerAll(inboxRoutes)
@@ -135,6 +138,20 @@ function writeUnauthorized(res) {
135
138
  res.writeHead(401, { 'content-type': 'application/json; charset=utf-8' });
136
139
  res.end(payload);
137
140
  }
141
+ function writeStartupBlocked(res, message) {
142
+ res.writeHead(503, { 'content-type': 'application/json; charset=utf-8' });
143
+ res.end(JSON.stringify({ error: { code: 'startup_blocked', message } }));
144
+ }
145
+ function destroyUpgradeStartupBlocked(socket, message) {
146
+ const payload = JSON.stringify({ error: { code: 'startup_blocked', message } });
147
+ const response = `HTTP/1.1 503 Service Unavailable\r\ncontent-type: application/json; charset=utf-8\r\ncontent-length: ${Buffer.byteLength(payload)}\r\nconnection: close\r\n\r\n${payload}`;
148
+ try {
149
+ socket.end(response);
150
+ }
151
+ catch {
152
+ socket.destroy();
153
+ }
154
+ }
138
155
  /** Reject an unauthorized TCP WS-upgrade attempt: this is a raw pre-upgrade
139
156
  * socket (no `ServerResponse`), so the 401 is written as a literal HTTP
140
157
  * response — mirroring `bridge.ts`'s `refuseUpgrade` (`end()`, not
@@ -180,13 +197,25 @@ function closeServer(server) {
180
197
  * servers route into identical state. */
181
198
  export function createApiServer(opts = {}) {
182
199
  const router = buildRouter();
200
+ const brokerLaunchRoutes = new Router()
201
+ .registerAll(brokerOperationRoutes)
202
+ .registerAll(brokerRecoveryRoutes)
203
+ .registerAll(brokerMailRoutes);
204
+ const startupBlockFor = (method, pathname) => {
205
+ const block = boundDaemonControl()?.startupBlock() ?? null;
206
+ if (block === null)
207
+ return null;
208
+ const admitted = (method === 'GET' && (pathname === '/healthz' || pathname === '/v1/status'))
209
+ || (method === 'POST' && (pathname === '/v1/daemon/migrate' || pathname === '/v1/daemon/admit'))
210
+ || (block.phase === 'recovering' && brokerLaunchRoutes.match(method, pathname) !== null);
211
+ return admitted ? null : block;
212
+ };
183
213
  const sockPath = apiSocketPath();
184
- // Shared request handler. The router's `handle` is total: it never throws and
185
- // turns every failure (no route, bad body, handler throw) into a JSON
186
- // ErrorBody. The `void` + `.catch` is belt-and-suspenders against an
187
- // unexpected rejection.
214
+ // Shared request handler. It owns the request boundary, including URL
215
+ // parsing before the router can take over, so malformed wire input cannot
216
+ // escape Node's request listener and terminate the daemon.
188
217
  const onRequest = (req, res) => {
189
- void router.handle(req, res).catch((err) => {
218
+ const internalFailure = (err) => {
190
219
  emitEvent({
191
220
  event: 'api.request.failed',
192
221
  level: 'error',
@@ -201,7 +230,32 @@ export function createApiServer(opts = {}) {
201
230
  catch {
202
231
  /* response already gone */
203
232
  }
204
- });
233
+ };
234
+ let url;
235
+ try {
236
+ url = new URL(req.url ?? '/', 'http://127.0.0.1');
237
+ }
238
+ catch {
239
+ try {
240
+ res.writeHead(400, { 'content-type': 'application/json; charset=utf-8' });
241
+ res.end(JSON.stringify({ error: { code: 'invalid_request', message: 'request URL is invalid' } }));
242
+ }
243
+ catch {
244
+ /* response already gone */
245
+ }
246
+ return;
247
+ }
248
+ try {
249
+ const block = startupBlockFor((req.method ?? 'GET').toUpperCase(), url.pathname);
250
+ if (block !== null) {
251
+ writeStartupBlocked(res, block.message);
252
+ return;
253
+ }
254
+ void router.handle(req, res).catch(internalFailure);
255
+ }
256
+ catch (err) {
257
+ internalFailure(err);
258
+ }
205
259
  };
206
260
  // Shared upgrade handler: only `GET /v1/nodes/:id/attach` is served; every
207
261
  // other upgrade path destroys the socket, and an unhandled error destroys the
@@ -214,6 +268,11 @@ export function createApiServer(opts = {}) {
214
268
  });
215
269
  try {
216
270
  const url = new URL(req.url ?? '/', 'http://127.0.0.1');
271
+ const block = startupBlockFor((req.method ?? 'GET').toUpperCase(), url.pathname);
272
+ if (block !== null) {
273
+ destroyUpgradeStartupBlocked(socket, block.message);
274
+ return;
275
+ }
217
276
  const nodeId = attachNodeId(req.method ?? 'GET', url.pathname);
218
277
  if (nodeId === null) {
219
278
  // Not an attach upgrade — no other upgrade path is served.
@@ -1,3 +1,4 @@
1
+ import type { DaemonAdmitDTO, StartupPhaseDTO } from '../api/dto/health.js';
1
2
  /** What crtrd exposes to handlers that act on the daemon process itself. */
2
3
  export interface DaemonControl {
3
4
  /** This daemon's epoch id. */
@@ -14,6 +15,23 @@ export interface DaemonControl {
14
15
  };
15
16
  /** Register daemon-owned post-response work for shutdown draining. */
16
17
  registerDetached(work: Promise<void>): void;
18
+ /** Null only after normal startup completed. */
19
+ startupBlock(): {
20
+ phase: Exclude<StartupPhaseDTO, 'ready'>;
21
+ message: string;
22
+ blockerPaths: readonly string[];
23
+ } | null;
24
+ /** Admit normal work after the daemon has prepared its storage. */
25
+ admitStartup(): Promise<DaemonAdmitDTO>;
26
+ /** Re-run daemon-owned corpus migration and resume normal startup when repaired. */
27
+ repairMigrations(req: {
28
+ dryRun: boolean;
29
+ dirs: readonly string[];
30
+ }): Promise<{
31
+ result: import('../migrations/runner.js').OnDiskMigrationRunResult;
32
+ resumed: boolean;
33
+ resumeError?: string;
34
+ }>;
17
35
  }
18
36
  /** Bind this process's control surface. Called once, by `runDaemon`. */
19
37
  export declare function bindDaemonControl(control: DaemonControl): void;
@@ -1,4 +1,5 @@
1
1
  import { type Cron } from '../../core/canvas/crons.js';
2
+ import { type CronSinkResolution } from './sinks.js';
2
3
  export interface RunSettleContext {
3
4
  runId: string;
4
5
  startedAtIso: string;
@@ -15,5 +16,6 @@ export interface Disposition {
15
16
  delivered: string;
16
17
  /** A paused row is retained so `cron resume` can re-arm it. */
17
18
  paused: boolean;
19
+ obligation?: CronSinkResolution;
18
20
  }
19
21
  export declare function disposeSettledRun(c: Cron, ctx: RunSettleContext, outOfBand: boolean, selfCanceled?: boolean): Promise<Disposition>;
@@ -1,6 +1,6 @@
1
1
  import { getCron, setCronLastOutputHash } from '../../core/canvas/crons.js';
2
2
  import { escalateFailure, failureSummary } from './escalation.js';
3
- import { deliverToSink } from './sinks.js';
3
+ import { resolveCronSink } from './sinks.js';
4
4
  export async function disposeSettledRun(c, ctx, outOfBand, selfCanceled = false) {
5
5
  const prefix = outOfBand ? 'out-of-band: ' : '';
6
6
  // A self-cancel still delivers its already-produced output; an external cancellation does not.
@@ -31,17 +31,20 @@ export async function disposeSettledRun(c, ctx, outOfBand, selfCanceled = false)
31
31
  case 'on-change':
32
32
  if (!changed)
33
33
  return { delivered: `${prefix}unchanged — not delivered (on-change)`, paused: false };
34
- return deliverOrEscalate(effective, ctx, outOfBand, prefix);
34
+ return resolveOrEscalate(effective, ctx, outOfBand, prefix);
35
35
  case 'always':
36
- return deliverOrEscalate(effective, ctx, outOfBand, prefix);
36
+ return resolveOrEscalate(effective, ctx, outOfBand, prefix);
37
37
  }
38
38
  }
39
- async function deliverOrEscalate(c, ctx, outOfBand, prefix) {
39
+ async function resolveOrEscalate(c, ctx, outOfBand, prefix) {
40
40
  if (ctx.stdoutHead.trim() === '') {
41
41
  return { delivered: `${prefix}empty stdout — nothing delivered`, paused: false };
42
42
  }
43
43
  try {
44
- return { delivered: `${prefix}${await deliverToSink(c, ctx.stdoutHead)}`, paused: false };
44
+ const obligation = resolveCronSink(c, ctx.runId, ctx.stdoutHead);
45
+ return obligation.kind === 'none'
46
+ ? { delivered: `${prefix}${obligation.delivered}`, paused: false }
47
+ : { delivered: '', paused: false, obligation };
45
48
  }
46
49
  catch (err) {
47
50
  const why = `delivery failed: ${err.message}`;