@north-light/cli 0.3.530 → 0.3.531

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 (495) hide show
  1. package/dist/clients/attach/session/connection.js +1 -1
  2. package/dist/clients/attach/session/reconnect.js +1 -1
  3. package/dist/clients/attach/viewer.js +3 -3
  4. package/dist/core/async-array.d.ts +7 -0
  5. package/dist/core/async-array.js +1 -0
  6. package/dist/core/audit.d.ts +1 -1
  7. package/dist/core/audit.js +2 -2
  8. package/dist/core/canvas/attention.d.ts +4 -4
  9. package/dist/core/canvas/attention.js +1 -1
  10. package/dist/core/canvas/boot.d.ts +4 -4
  11. package/dist/core/canvas/boot.js +1 -1
  12. package/dist/core/canvas/canvas.d.ts +59 -59
  13. package/dist/core/canvas/canvas.js +19 -19
  14. package/dist/core/canvas/context-strip.js +2 -2
  15. package/dist/core/canvas/crons.d.ts +27 -27
  16. package/dist/core/canvas/crons.js +11 -11
  17. package/dist/core/canvas/daemon-actions.d.ts +10 -10
  18. package/dist/core/canvas/daemon-actions.js +8 -8
  19. package/dist/core/canvas/daemon-owner.d.ts +3 -3
  20. package/dist/core/canvas/daemon-owner.js +2 -2
  21. package/dist/core/canvas/db.d.ts +19 -30
  22. package/dist/core/canvas/db.js +3 -2
  23. package/dist/core/canvas/deliveries.d.ts +16 -16
  24. package/dist/core/canvas/deliveries.js +24 -24
  25. package/dist/core/canvas/executions.d.ts +8 -8
  26. package/dist/core/canvas/executions.js +1 -1
  27. package/dist/core/canvas/focuses.d.ts +8 -8
  28. package/dist/core/canvas/focuses.js +1 -1
  29. package/dist/core/canvas/history.d.ts +3 -3
  30. package/dist/core/canvas/history.js +9 -9
  31. package/dist/core/canvas/install-id.d.ts +1 -1
  32. package/dist/core/canvas/install-id.js +1 -1
  33. package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +1 -1
  34. package/dist/core/canvas/managed-worktree-sweep-candidates.js +2 -2
  35. package/dist/core/canvas/memory-reads.d.ts +6 -6
  36. package/dist/core/canvas/memory-reads.js +1 -1
  37. package/dist/core/canvas/nav-model.d.ts +13 -13
  38. package/dist/core/canvas/nav-model.js +1 -1
  39. package/dist/core/canvas/node-agent-paths.d.ts +6 -6
  40. package/dist/core/canvas/node-agent-paths.js +1 -1
  41. package/dist/core/canvas/node-tokens.d.ts +7 -7
  42. package/dist/core/canvas/node-tokens.js +3 -3
  43. package/dist/core/canvas/outcome-actions.d.ts +5 -5
  44. package/dist/core/canvas/outcome-actions.js +3 -3
  45. package/dist/core/canvas/recovery.d.ts +26 -26
  46. package/dist/core/canvas/recovery.js +2 -2
  47. package/dist/core/canvas/render-source.d.ts +1 -1
  48. package/dist/core/canvas/render-source.js +1 -1
  49. package/dist/core/canvas/sessions.d.ts +10 -10
  50. package/dist/core/canvas/sessions.js +4 -4
  51. package/dist/core/canvas/source.js +1 -1
  52. package/dist/core/canvas/structured-requests.d.ts +15 -15
  53. package/dist/core/canvas/structured-requests.js +5 -5
  54. package/dist/core/canvas/tree.d.ts +9 -9
  55. package/dist/core/canvas/tree.js +5 -5
  56. package/dist/core/canvas/waits.d.ts +13 -13
  57. package/dist/core/canvas/waits.js +6 -6
  58. package/dist/core/canvas/worktrees.d.ts +15 -15
  59. package/dist/core/canvas/worktrees.js +1 -1
  60. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  61. package/dist/core/conversation-store/file-store.d.ts +7 -7
  62. package/dist/core/conversation-store/file-store.js +9 -9
  63. package/dist/core/conversation-store/index.d.ts +16 -14
  64. package/dist/core/conversation-store/index.js +1 -1
  65. package/dist/core/conversation-store/listener.js +5 -5
  66. package/dist/core/conversation-store/patch.d.ts +3 -1
  67. package/dist/core/conversation-store/patch.js +1 -1
  68. package/dist/core/feed/feed.js +3 -3
  69. package/dist/core/feed/inbox.d.ts +2 -2
  70. package/dist/core/feed/inbox.js +1 -1
  71. package/dist/core/feed/messages.d.ts +11 -12
  72. package/dist/core/feed/messages.js +5 -5
  73. package/dist/core/feed/reports.d.ts +4 -4
  74. package/dist/core/feed/reports.js +2 -2
  75. package/dist/core/grants/cover.d.ts +1 -1
  76. package/dist/core/grants/cover.js +1 -1
  77. package/dist/core/grants/local.d.ts +1 -1
  78. package/dist/core/grants/local.js +1 -1
  79. package/dist/core/grants/mirror.d.ts +19 -19
  80. package/dist/core/grants/mirror.js +2 -2
  81. package/dist/core/grants/on-sync.d.ts +1 -1
  82. package/dist/core/grants/on-sync.js +1 -1
  83. package/dist/core/grants/remove.js +1 -1
  84. package/dist/core/grants/sync.js +1 -1
  85. package/dist/core/graph/access.d.ts +17 -17
  86. package/dist/core/graph/access.js +3 -3
  87. package/dist/core/graph/custom.d.ts +16 -16
  88. package/dist/core/graph/custom.js +9 -9
  89. package/dist/core/graph/deletion.d.ts +3 -7
  90. package/dist/core/graph/deletion.js +4 -4
  91. package/dist/core/graph/documents.d.ts +24 -27
  92. package/dist/core/graph/documents.js +7 -7
  93. package/dist/core/graph/edges.d.ts +13 -13
  94. package/dist/core/graph/edges.js +1 -1
  95. package/dist/core/graph/events.d.ts +7 -9
  96. package/dist/core/graph/events.js +8 -8
  97. package/dist/core/graph/exposures.d.ts +6 -6
  98. package/dist/core/graph/exposures.js +4 -4
  99. package/dist/core/graph/jobs.d.ts +6 -8
  100. package/dist/core/graph/jobs.js +2 -2
  101. package/dist/core/graph/kinds/action.js +1 -1
  102. package/dist/core/graph/kinds/custom.js +2 -2
  103. package/dist/core/graph/kinds/document.d.ts +1 -0
  104. package/dist/core/graph/kinds/document.js +4 -4
  105. package/dist/core/graph/kinds/dto.d.ts +2 -2
  106. package/dist/core/graph/kinds/dto.js +1 -1
  107. package/dist/core/graph/kinds/job.js +2 -2
  108. package/dist/core/graph/kinds/kind.d.ts +6 -8
  109. package/dist/core/graph/kinds/kind.js +1 -1
  110. package/dist/core/graph/kinds/node.js +5 -5
  111. package/dist/core/graph/kinds/owner.js +2 -2
  112. package/dist/core/graph/kinds/registry.d.ts +6 -9
  113. package/dist/core/graph/kinds/registry.js +1 -1
  114. package/dist/core/graph/names.d.ts +6 -6
  115. package/dist/core/graph/names.js +3 -3
  116. package/dist/core/graph/object-waits.d.ts +4 -7
  117. package/dist/core/graph/object-waits.js +1 -1
  118. package/dist/core/graph/objects.d.ts +14 -14
  119. package/dist/core/graph/objects.js +9 -9
  120. package/dist/core/graph/package-docs.d.ts +2 -7
  121. package/dist/core/graph/package-docs.js +5 -5
  122. package/dist/core/graph/package-kinds.d.ts +2 -5
  123. package/dist/core/graph/package-kinds.js +1 -1
  124. package/dist/core/graph/package-reconcile.d.ts +2 -5
  125. package/dist/core/graph/package-reconcile.js +1 -1
  126. package/dist/core/graph/reader.d.ts +18 -18
  127. package/dist/core/graph/reader.js +3 -3
  128. package/dist/core/graph/receivers.d.ts +4 -4
  129. package/dist/core/graph/receivers.js +5 -5
  130. package/dist/core/graph/repo-sync/exchange.d.ts +3 -7
  131. package/dist/core/graph/repo-sync/exchange.js +2 -2
  132. package/dist/core/graph/repo-sync/repos.d.ts +7 -5
  133. package/dist/core/graph/repo-sync/repos.js +3 -3
  134. package/dist/core/graph/repo-sync/sync.d.ts +3 -6
  135. package/dist/core/graph/repo-sync/sync.js +2 -2
  136. package/dist/core/graph/rules.d.ts +5 -5
  137. package/dist/core/graph/rules.js +3 -3
  138. package/dist/core/graph/spaces/app.js +1 -1
  139. package/dist/core/graph/spaces/index.d.ts +4 -5
  140. package/dist/core/graph/spaces/index.js +1 -1
  141. package/dist/core/graph/spaces/own-memory.d.ts +4 -4
  142. package/dist/core/graph/spaces/own-memory.js +1 -1
  143. package/dist/core/graph/spaces/person.js +3 -3
  144. package/dist/core/graph/spaces/repo.d.ts +1 -1
  145. package/dist/core/graph/spaces/repo.js +1 -1
  146. package/dist/core/graph/watches.d.ts +15 -15
  147. package/dist/core/graph/watches.js +10 -10
  148. package/dist/core/human/feedback-companion.d.ts +2 -2
  149. package/dist/core/human/feedback-companion.js +1 -1
  150. package/dist/core/human/feedback.d.ts +3 -3
  151. package/dist/core/human/feedback.js +1 -1
  152. package/dist/core/human/requests.d.ts +34 -33
  153. package/dist/core/human/requests.js +20 -20
  154. package/dist/core/human/scan.d.ts +2 -2
  155. package/dist/core/human/scan.js +1 -1
  156. package/dist/core/human/tickets.d.ts +9 -9
  157. package/dist/core/human/tickets.js +1 -1
  158. package/dist/core/llm/app-rungs.d.ts +1 -1
  159. package/dist/core/llm/app-rungs.js +1 -1
  160. package/dist/core/llm/run.js +1 -1
  161. package/dist/core/peer/directory.d.ts +1 -1
  162. package/dist/core/peer/directory.js +1 -1
  163. package/dist/core/peer/envelope.d.ts +3 -3
  164. package/dist/core/peer/envelope.js +1 -1
  165. package/dist/core/peer/home.d.ts +7 -7
  166. package/dist/core/peer/home.js +2 -2
  167. package/dist/core/peer/ingest.d.ts +6 -6
  168. package/dist/core/peer/ingest.js +1 -1
  169. package/dist/core/peer/outbox-store.d.ts +14 -14
  170. package/dist/core/peer/outbox-store.js +5 -5
  171. package/dist/core/peer/receiver.d.ts +2 -2
  172. package/dist/core/peer/receiver.js +1 -1
  173. package/dist/core/peer/stubs.d.ts +10 -10
  174. package/dist/core/peer/stubs.js +1 -1
  175. package/dist/core/providers/approval.d.ts +2 -2
  176. package/dist/core/providers/approval.js +2 -2
  177. package/dist/core/providers/audit.d.ts +3 -3
  178. package/dist/core/providers/audit.js +2 -2
  179. package/dist/core/providers/bundles.js +2 -2
  180. package/dist/core/providers/call.d.ts +2 -2
  181. package/dist/core/providers/call.js +1 -1
  182. package/dist/core/providers/files.d.ts +1 -1
  183. package/dist/core/providers/files.js +1 -1
  184. package/dist/core/providers/mint.js +1 -1
  185. package/dist/core/providers/receipts.d.ts +1 -1
  186. package/dist/core/providers/receipts.js +2 -2
  187. package/dist/core/review/birth.js +1 -1
  188. package/dist/core/review/comments.d.ts +19 -19
  189. package/dist/core/review/comments.js +5 -5
  190. package/dist/core/review/companion.d.ts +1 -1
  191. package/dist/core/review/companion.js +1 -1
  192. package/dist/core/review/document.d.ts +3 -3
  193. package/dist/core/review/document.js +2 -2
  194. package/dist/core/review/fork.js +2 -2
  195. package/dist/core/review/realize.js +1 -1
  196. package/dist/core/review/remap.d.ts +2 -2
  197. package/dist/core/review/remap.js +4 -4
  198. package/dist/core/review/stage.d.ts +1 -1
  199. package/dist/core/review/stage.js +1 -1
  200. package/dist/core/review/store.d.ts +21 -21
  201. package/dist/core/review/store.js +1 -1
  202. package/dist/core/runs/activity.d.ts +1 -1
  203. package/dist/core/runs/activity.js +5 -5
  204. package/dist/core/runs/confinement.d.ts +7 -7
  205. package/dist/core/runs/confinement.js +2 -2
  206. package/dist/core/runs/events.d.ts +12 -12
  207. package/dist/core/runs/events.js +4 -4
  208. package/dist/core/runs/operations.d.ts +11 -11
  209. package/dist/core/runs/operations.js +5 -5
  210. package/dist/core/runs/questions.d.ts +10 -10
  211. package/dist/core/runs/questions.js +3 -3
  212. package/dist/core/runtime/auth-reload.js +1 -1
  213. package/dist/core/runtime/bearings.d.ts +5 -5
  214. package/dist/core/runtime/bearings.js +6 -6
  215. package/dist/core/runtime/broker-inventory.js +1 -1
  216. package/dist/core/runtime/broker-request.js +1 -1
  217. package/dist/core/runtime/broker.js +1 -1
  218. package/dist/core/runtime/close.d.ts +3 -3
  219. package/dist/core/runtime/close.js +1 -1
  220. package/dist/core/runtime/deliver-live.js +1 -1
  221. package/dist/core/runtime/fleet.d.ts +2 -2
  222. package/dist/core/runtime/host.d.ts +3 -3
  223. package/dist/core/runtime/host.js +3 -3
  224. package/dist/core/runtime/kickoff.d.ts +12 -12
  225. package/dist/core/runtime/kickoff.js +17 -17
  226. package/dist/core/runtime/launch-target.d.ts +1 -1
  227. package/dist/core/runtime/launch-target.js +1 -1
  228. package/dist/core/runtime/ledger.d.ts +3 -3
  229. package/dist/core/runtime/ledger.js +3 -3
  230. package/dist/core/runtime/lifecycle.d.ts +1 -1
  231. package/dist/core/runtime/lifecycle.js +2 -2
  232. package/dist/core/runtime/memory-admission.js +1 -1
  233. package/dist/core/runtime/model-swap.d.ts +2 -2
  234. package/dist/core/runtime/model-swap.js +1 -1
  235. package/dist/core/runtime/node-read.d.ts +1 -1
  236. package/dist/core/runtime/node-read.js +2 -2
  237. package/dist/core/runtime/nodes.d.ts +6 -6
  238. package/dist/core/runtime/nodes.js +1 -1
  239. package/dist/core/runtime/outcome-document.d.ts +1 -1
  240. package/dist/core/runtime/outcome-document.js +1 -1
  241. package/dist/core/runtime/persona.d.ts +3 -3
  242. package/dist/core/runtime/persona.js +2 -2
  243. package/dist/core/runtime/placement.d.ts +11 -11
  244. package/dist/core/runtime/placement.js +1 -1
  245. package/dist/core/runtime/promote.d.ts +3 -3
  246. package/dist/core/runtime/promote.js +1 -1
  247. package/dist/core/runtime/recycle.js +1 -1
  248. package/dist/core/runtime/reopen.d.ts +5 -5
  249. package/dist/core/runtime/reopen.js +1 -1
  250. package/dist/core/runtime/reset.d.ts +4 -4
  251. package/dist/core/runtime/reset.js +1 -1
  252. package/dist/core/runtime/revive-all.d.ts +2 -2
  253. package/dist/core/runtime/revive-all.js +1 -1
  254. package/dist/core/runtime/revive.d.ts +4 -4
  255. package/dist/core/runtime/revive.js +2 -2
  256. package/dist/core/runtime/roadmap.d.ts +6 -6
  257. package/dist/core/runtime/roadmap.js +5 -5
  258. package/dist/core/runtime/session-branch.d.ts +1 -1
  259. package/dist/core/runtime/session-branch.js +1 -1
  260. package/dist/core/runtime/session-list-cache.js +1 -1
  261. package/dist/core/runtime/situational-live.js +1 -1
  262. package/dist/core/runtime/spawn.d.ts +2 -2
  263. package/dist/core/runtime/spawn.js +2 -2
  264. package/dist/core/runtime/stop-guard.d.ts +2 -2
  265. package/dist/core/runtime/stop-guard.js +3 -3
  266. package/dist/core/runtime/warm-pool.d.ts +2 -2
  267. package/dist/core/runtime/warm-pool.js +1 -1
  268. package/dist/core/spaces/mounts.d.ts +2 -2
  269. package/dist/core/spaces/mounts.js +1 -1
  270. package/dist/core/spaces/permissions.d.ts +1 -1
  271. package/dist/core/spaces/permissions.js +1 -1
  272. package/dist/core/spaces/process.d.ts +1 -1
  273. package/dist/core/spaces/process.js +1 -1
  274. package/dist/core/spaces/space.js +1 -1
  275. package/dist/core/spaces/stop.d.ts +3 -3
  276. package/dist/core/spaces/stop.js +2 -2
  277. package/dist/core/spaces/users.d.ts +6 -6
  278. package/dist/core/spaces/users.js +1 -1
  279. package/dist/core/storage/attachments.d.ts +2 -2
  280. package/dist/core/storage/attachments.js +1 -1
  281. package/dist/core/storage/shares.d.ts +2 -2
  282. package/dist/core/storage/shares.js +1 -1
  283. package/dist/core/storage/tables.d.ts +21 -21
  284. package/dist/core/storage/tables.js +3 -3
  285. package/dist/core/substrate/delivery/corpus.d.ts +5 -8
  286. package/dist/core/substrate/delivery/corpus.js +3 -3
  287. package/dist/core/substrate/delivery/deliver.d.ts +10 -15
  288. package/dist/core/substrate/delivery/deliver.js +3 -3
  289. package/dist/core/substrate/delivery/plan.d.ts +2 -12
  290. package/dist/core/substrate/delivery/plan.js +3 -3
  291. package/dist/core/substrate/delivery/render-boot.d.ts +4 -4
  292. package/dist/core/substrate/delivery/render-boot.js +18 -18
  293. package/dist/core/substrate/delivery/render-event.d.ts +7 -14
  294. package/dist/core/substrate/delivery/render-event.js +4 -4
  295. package/dist/core/substrate/subject.d.ts +2 -2
  296. package/dist/core/substrate/subject.js +1 -1
  297. package/dist/core/usage/ledger.d.ts +6 -6
  298. package/dist/core/usage/ledger.js +4 -4
  299. package/dist/core/worktree-close.js +4 -4
  300. package/dist/core/worktree-mutation-async.js +7 -7
  301. package/dist/core/worktree-quarantine.js +1 -1
  302. package/dist/core/worktree-sweep.d.ts +1 -1
  303. package/dist/core/worktree-sweep.js +6 -6
  304. package/dist/core/worktree.d.ts +5 -5
  305. package/dist/core/worktree.js +13 -13
  306. package/dist/daemon/analytics/compute.d.ts +2 -2
  307. package/dist/daemon/analytics/compute.js +1 -1
  308. package/dist/daemon/api/app-listener.d.ts +4 -4
  309. package/dist/daemon/api/app-listener.js +13 -13
  310. package/dist/daemon/api/bridge.js +5 -5
  311. package/dist/daemon/api/document-listener.js +6 -6
  312. package/dist/daemon/api/handlers/analytics.js +1 -1
  313. package/dist/daemon/api/handlers/attach.js +1 -1
  314. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  315. package/dist/daemon/api/handlers/bash.js +1 -1
  316. package/dist/daemon/api/handlers/broker-ops.d.ts +1 -1
  317. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  318. package/dist/daemon/api/handlers/broker-recovery.d.ts +1 -1
  319. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  320. package/dist/daemon/api/handlers/broker-signals.d.ts +2 -2
  321. package/dist/daemon/api/handlers/broker-signals.js +2 -2
  322. package/dist/daemon/api/handlers/canvas.d.ts +1 -1
  323. package/dist/daemon/api/handlers/canvas.js +4 -4
  324. package/dist/daemon/api/handlers/chat-inventory.js +1 -1
  325. package/dist/daemon/api/handlers/crons.js +1 -1
  326. package/dist/daemon/api/handlers/custom-objects.d.ts +4 -4
  327. package/dist/daemon/api/handlers/custom-objects.js +3 -3
  328. package/dist/daemon/api/handlers/delivery-retry.js +1 -1
  329. package/dist/daemon/api/handlers/delivery.js +1 -1
  330. package/dist/daemon/api/handlers/docs.d.ts +4 -4
  331. package/dist/daemon/api/handlers/docs.js +1 -1
  332. package/dist/daemon/api/handlers/feedback-comments.js +3 -3
  333. package/dist/daemon/api/handlers/files.js +1 -1
  334. package/dist/daemon/api/handlers/focus.js +1 -1
  335. package/dist/daemon/api/handlers/health.js +3 -3
  336. package/dist/daemon/api/handlers/hook-exec.js +1 -1
  337. package/dist/daemon/api/handlers/human-requests.js +1 -1
  338. package/dist/daemon/api/handlers/inbox-page.d.ts +1 -1
  339. package/dist/daemon/api/handlers/inbox-page.js +1 -1
  340. package/dist/daemon/api/handlers/inbox.d.ts +1 -1
  341. package/dist/daemon/api/handlers/inbox.js +1 -1
  342. package/dist/daemon/api/handlers/llm.d.ts +1 -1
  343. package/dist/daemon/api/handlers/llm.js +3 -3
  344. package/dist/daemon/api/handlers/memory-reads.js +1 -1
  345. package/dist/daemon/api/handlers/memory.d.ts +5 -5
  346. package/dist/daemon/api/handlers/memory.js +5 -5
  347. package/dist/daemon/api/handlers/messages.js +2 -2
  348. package/dist/daemon/api/handlers/node-events.d.ts +2 -2
  349. package/dist/daemon/api/handlers/node-events.js +3 -3
  350. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  351. package/dist/daemon/api/handlers/node-records.js +2 -2
  352. package/dist/daemon/api/handlers/nodes.d.ts +1 -1
  353. package/dist/daemon/api/handlers/nodes.js +1 -1
  354. package/dist/daemon/api/handlers/objects.js +3 -3
  355. package/dist/daemon/api/handlers/package-docs.js +1 -1
  356. package/dist/daemon/api/handlers/plugin-app-token.d.ts +1 -1
  357. package/dist/daemon/api/handlers/plugin-app-token.js +1 -1
  358. package/dist/daemon/api/handlers/profiles.d.ts +3 -3
  359. package/dist/daemon/api/handlers/profiles.js +1 -1
  360. package/dist/daemon/api/handlers/providers.d.ts +1 -1
  361. package/dist/daemon/api/handlers/providers.js +1 -1
  362. package/dist/daemon/api/handlers/questions.js +1 -1
  363. package/dist/daemon/api/handlers/reports.d.ts +1 -1
  364. package/dist/daemon/api/handlers/reports.js +5 -5
  365. package/dist/daemon/api/handlers/review-comments.js +1 -1
  366. package/dist/daemon/api/handlers/reviews.js +1 -1
  367. package/dist/daemon/api/handlers/runs.js +1 -1
  368. package/dist/daemon/api/handlers/structured-requests.js +1 -1
  369. package/dist/daemon/api/handlers/subscriptions.js +1 -1
  370. package/dist/daemon/api/handlers/transfer.js +1 -1
  371. package/dist/daemon/api/map.d.ts +3 -3
  372. package/dist/daemon/api/map.js +1 -1
  373. package/dist/daemon/api/principal.d.ts +1 -1
  374. package/dist/daemon/api/principal.js +1 -1
  375. package/dist/daemon/api/reader.d.ts +5 -5
  376. package/dist/daemon/api/reader.js +1 -1
  377. package/dist/daemon/api/router.d.ts +5 -5
  378. package/dist/daemon/api/router.js +1 -1
  379. package/dist/daemon/api/server.js +1 -1
  380. package/dist/daemon/broker-signals/bus.d.ts +1 -1
  381. package/dist/daemon/broker-signals/bus.js +1 -1
  382. package/dist/daemon/companion-retire.js +1 -1
  383. package/dist/daemon/cron/armed-context.d.ts +2 -2
  384. package/dist/daemon/cron/armed-context.js +1 -1
  385. package/dist/daemon/cron/authority.d.ts +2 -2
  386. package/dist/daemon/cron/authority.js +1 -1
  387. package/dist/daemon/cron/disposition.js +1 -1
  388. package/dist/daemon/cron/ended.d.ts +1 -1
  389. package/dist/daemon/cron/ended.js +2 -2
  390. package/dist/daemon/cron/escalation.js +3 -3
  391. package/dist/daemon/cron/folders.d.ts +1 -1
  392. package/dist/daemon/cron/folders.js +1 -1
  393. package/dist/daemon/cron/held.d.ts +1 -1
  394. package/dist/daemon/cron/held.js +1 -1
  395. package/dist/daemon/cron/lease-recovery.d.ts +1 -1
  396. package/dist/daemon/cron/lease-recovery.js +1 -1
  397. package/dist/daemon/cron/passes.d.ts +2 -2
  398. package/dist/daemon/cron/passes.js +1 -1
  399. package/dist/daemon/cron/run-socket.d.ts +1 -1
  400. package/dist/daemon/cron/run-socket.js +1 -1
  401. package/dist/daemon/cron/settle.js +1 -1
  402. package/dist/daemon/cron/sinks.d.ts +1 -1
  403. package/dist/daemon/cron/sinks.js +2 -2
  404. package/dist/daemon/cron-run.d.ts +12 -3
  405. package/dist/daemon/cron-run.js +2 -2
  406. package/dist/daemon/crtrd.js +6 -6
  407. package/dist/daemon/delivery/run-delivery.js +1 -1
  408. package/dist/daemon/due-sources.d.ts +3 -3
  409. package/dist/daemon/due-sources.js +1 -1
  410. package/dist/daemon/due.d.ts +3 -3
  411. package/dist/daemon/due.js +7 -7
  412. package/dist/daemon/fleet.d.ts +2 -2
  413. package/dist/daemon/fleet.js +11 -11
  414. package/dist/daemon/human/finish.js +3 -3
  415. package/dist/daemon/human/settle.d.ts +1 -1
  416. package/dist/daemon/human/settle.js +1 -1
  417. package/dist/daemon/human/sweep.js +1 -1
  418. package/dist/daemon/joined-owner.d.ts +2 -2
  419. package/dist/daemon/joined-owner.js +1 -1
  420. package/dist/daemon/messaging/node-message.js +1 -1
  421. package/dist/daemon/park-activity.d.ts +2 -2
  422. package/dist/daemon/park-activity.js +1 -1
  423. package/dist/daemon/peer/authority.js +1 -1
  424. package/dist/daemon/peer/forward.d.ts +6 -6
  425. package/dist/daemon/peer/forward.js +1 -1
  426. package/dist/daemon/peer/handlers.js +1 -1
  427. package/dist/daemon/peer/ingress.d.ts +4 -4
  428. package/dist/daemon/peer/ingress.js +1 -1
  429. package/dist/daemon/peer/outbox.d.ts +2 -2
  430. package/dist/daemon/peer/outbox.js +1 -1
  431. package/dist/daemon/peer/relay-service.js +1 -1
  432. package/dist/daemon/plugin-objects/read-leaf.d.ts +2 -2
  433. package/dist/daemon/plugin-objects/read-leaf.js +2 -2
  434. package/dist/daemon/profile-delete.js +1 -1
  435. package/dist/daemon/readiness.d.ts +2 -2
  436. package/dist/daemon/readiness.js +1 -1
  437. package/dist/daemon/reconcilers/action-lane.d.ts +1 -1
  438. package/dist/daemon/reconcilers/action-lane.js +1 -1
  439. package/dist/daemon/reconcilers/bash-deadline.js +2 -2
  440. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  441. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  442. package/dist/daemon/reconcilers/controller-death.d.ts +1 -1
  443. package/dist/daemon/reconcilers/controller-death.js +1 -1
  444. package/dist/daemon/reconcilers/cron-lane.d.ts +1 -1
  445. package/dist/daemon/reconcilers/cron-lane.js +1 -1
  446. package/dist/daemon/reconcilers/delivery-lane.d.ts +1 -1
  447. package/dist/daemon/reconcilers/delivery-lane.js +2 -2
  448. package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +3 -3
  449. package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
  450. package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +2 -2
  451. package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
  452. package/dist/daemon/reconcilers/live-obligation.d.ts +6 -6
  453. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  454. package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
  455. package/dist/daemon/reconcilers/node-deadline.d.ts +1 -1
  456. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  457. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  458. package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.d.ts +3 -3
  459. package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.js +1 -1
  460. package/dist/daemon/reconcilers/node-lifecycle/terminating.js +1 -1
  461. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  462. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.d.ts +1 -1
  463. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  464. package/dist/daemon/reconcilers/pending-review-submit.d.ts +1 -1
  465. package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
  466. package/dist/daemon/reconcilers/storage-due-work.js +1 -1
  467. package/dist/daemon/reconcilers/storage-maintenance.d.ts +1 -1
  468. package/dist/daemon/reconcilers/storage-maintenance.js +2 -2
  469. package/dist/daemon/reconcilers/structured-request-lane.d.ts +1 -1
  470. package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
  471. package/dist/daemon/review/comment-notify.js +2 -2
  472. package/dist/daemon/review/companion.d.ts +3 -3
  473. package/dist/daemon/review/companion.js +1 -1
  474. package/dist/daemon/review/finish.js +1 -1
  475. package/dist/daemon/review/sweep.js +1 -1
  476. package/dist/daemon/run-notices.d.ts +4 -4
  477. package/dist/daemon/run-notices.js +1 -1
  478. package/dist/daemon/runs/append-section.d.ts +2 -2
  479. package/dist/daemon/runs/append-section.js +2 -2
  480. package/dist/daemon/runs/observer.d.ts +2 -2
  481. package/dist/daemon/runs/observer.js +2 -2
  482. package/dist/daemon/structured-requests/boot.d.ts +1 -1
  483. package/dist/daemon/structured-requests/boot.js +1 -1
  484. package/dist/daemon/structured-requests/effects.js +1 -1
  485. package/dist/daemon/structured-requests/sidecar.d.ts +1 -1
  486. package/dist/daemon/structured-requests/sidecar.js +1 -1
  487. package/dist/migrations/004-canvas-documents/apply.d.ts +3 -3
  488. package/dist/migrations/004-canvas-documents/apply.js +1 -1
  489. package/dist/migrations/004-canvas-documents/index.d.ts +2 -2
  490. package/dist/migrations/004-canvas-documents/index.js +2 -2
  491. package/dist/migrations/activation.js +2 -2
  492. package/docs/public-api.md +11 -0
  493. package/package.json +3 -2
  494. package/packages/crouter-identity/package.json +1 -1
  495. package/runtime.lock.json +12 -12
@@ -1,5 +1,5 @@
1
1
  /** Register every due source and busy-only declaration. Idempotent. */
2
- export declare function installDueSources(): void;
2
+ export declare function installDueSources(): Promise<void>;
3
3
  /** How long a node with no engine yet, or an engine that has not opened its first
4
4
  * turn, counts as work the daemon is about to do. Past it the node is idle or
5
5
  * stranded, not starting: a resident revived with no prompt sits at an idle
@@ -9,6 +9,6 @@ export interface DueReport {
9
9
  busy: boolean;
10
10
  next_due_at: string | null;
11
11
  }
12
- export declare function dueReport(now?: number): DueReport;
12
+ export declare function dueReport(now?: number): Promise<DueReport>;
13
13
  /** For tests and diagnostics: the lanes covered. */
14
- export declare function coveredLanes(): string[];
14
+ export declare function coveredLanes(): Promise<string[]>;
@@ -1,11 +1,11 @@
1
- var T=Object.defineProperty;var r=(n,e)=>T(n,"name",{value:e,configurable:!0});import{prepared as f}from"../core/sqlite-statements.js";import{openDb as E}from"../core/canvas/db.js";import{isPidPresent as x}from"../core/canvas/pid.js";import{isProfilePaused as p}from"../core/profiles/manifest.js";import{hasUnseenWakeMail as L}from"../core/canvas/deliveries.js";import{listPendingProviderRetries as I}from"../core/canvas/recovery.js";import{listSubmitRequestedRequests as O}from"../core/human/requests.js";import{storageConfig as A}from"../core/storage/client.js";import{emitEvent as M}from"../core/events/emit.js";import{wantsExecution as N}from"./reconcilers/node-lifecycle/wants-execution.js";import{dueAtMs as b}from"./reconcilers/fault-retry-backstop.js";import{UNUSED_UPLOAD_TTL_MS as h}from"./reconcilers/storage-due-work.js";import{busyOnlyLanes as g,collectDue as w,declareBusyOnly as l,dueSourceLanes as U,registerDueSource as o}from"./due-sources.js";const _=r((n,...e)=>f(E(),n).all(...e),"rows"),a=r(n=>f(E(),n).get(),"first"),s=r(n=>{if(n==null)return null;const e=Date.parse(n);return Number.isFinite(e)?e:null},"iso"),c=r(n=>{let e=null;for(const t of n)t!==null&&(e===null||t<e)&&(e=t);return e},"earliest"),m="node_id NOT IN (SELECT node_id FROM warm_pool)";let S=!1;function D(){if(S)return;S=!0,l("brokerSupervision","acts only on live broker processes, which already make busy true"),l("controllerDeath","acts only on live controller processes"),l("pollRunObservers","follows live pids only"),l("bashDeadline","acts only on running bash jobs, which already make busy true"),l("storageMaintenance","retention and placement housekeeping: never time-critical, and it must not wake or hold a sleeping runtime"),o("nodeLifecycle",{nextDue:r(()=>c(_(`SELECT node_id, status, intent, profile_id, respawn_not_before FROM node_rows
2
- WHERE status IN ('active', 'idle') AND kind != 'human' AND ${m}
3
- AND pi_pid IS NULL AND respawn_not_before IS NOT NULL`).filter(e=>!p(e.profile_id)&&N({node_id:e.node_id,status:e.status,intent:e.intent})).map(e=>s(e.respawn_not_before))),"nextDue")}),o("nodeDeadline",{nextDue:r(()=>c(_(`SELECT deadline_at, profile_id FROM node_rows
4
- WHERE deadline_at IS NOT NULL AND outcome_at IS NULL AND status IN ('active', 'idle') AND kind != 'human'`).filter(e=>!p(e.profile_id)).map(e=>s(e.deadline_at))),"nextDue")}),o("structuredRequests",{nextDue:r(e=>a("SELECT 1 FROM structured_requests WHERE state != 'pending' AND effects_done_at IS NULL LIMIT 1")!==void 0?e:a("SELECT MIN(deadline_at) AS at FROM structured_requests WHERE state = 'pending' AND deadline_at IS NOT NULL")?.at??null,"nextDue")}),o("cronLane",{nextDue:r(()=>{const e=_(`SELECT fire_at, profile FROM crons
1
+ var D=Object.defineProperty;var a=(n,e)=>D(n,"name",{value:e,configurable:!0});import{openDb as f}from"../core/canvas/db.js";import{isPidPresent as R}from"../core/canvas/pid.js";import{isProfilePaused as p}from"../core/profiles/manifest.js";import{hasUnseenWakeMail as E}from"../core/canvas/deliveries.js";import{listPendingProviderRetries as T}from"../core/canvas/recovery.js";import{listSubmitRequestedRequests as x}from"../core/human/requests.js";import{storageConfig as I}from"../core/storage/client.js";import{emitEvent as A}from"../core/events/emit.js";import{wantsExecution as L}from"./reconcilers/node-lifecycle/wants-execution.js";import{dueAtMs as O}from"./reconcilers/fault-retry-backstop.js";import{UNUSED_UPLOAD_TTL_MS as y}from"./reconcilers/storage-due-work.js";import{busyOnlyLanes as M,collectDue as b,declareBusyOnly as l,dueSourceLanes as g,registerDueSource as r}from"./due-sources.js";import{filterAsync as h}from"../core/async-array.js";const c=a(async(n,...e)=>await(await f()).prepare(n).all(...e),"rows"),s=a(async n=>await(await f()).prepare(n).get(),"first"),o=a(n=>{if(n==null)return null;const e=Date.parse(n);return Number.isFinite(e)?e:null},"iso"),_=a(n=>{let e=null;for(const t of n)t!==null&&(e===null||t<e)&&(e=t);return e},"earliest"),N="node_id NOT IN (SELECT node_id FROM warm_pool)";let m=!1;async function S(){if(m)return;m=!0,l("brokerSupervision","acts only on live broker processes, which already make busy true"),l("controllerDeath","acts only on live controller processes"),l("pollRunObservers","follows live pids only"),l("bashDeadline","acts only on running bash jobs, which already make busy true"),l("storageMaintenance","retention and placement housekeeping: never time-critical, and it must not wake or hold a sleeping runtime"),r("nodeLifecycle",{nextDue:a(async()=>_((await h(await c(`SELECT node_id, status, intent, profile_id, respawn_not_before FROM node_rows
2
+ WHERE status IN ('active', 'idle') AND kind != 'human' AND ${N}
3
+ AND pi_pid IS NULL AND respawn_not_before IS NOT NULL`),async e=>!p(e.profile_id)&&await L({node_id:e.node_id,status:e.status,intent:e.intent}))).map(e=>o(e.respawn_not_before))),"nextDue")}),r("nodeDeadline",{nextDue:a(async()=>_((await c(`SELECT deadline_at, profile_id FROM node_rows
4
+ WHERE deadline_at IS NOT NULL AND outcome_at IS NULL AND status IN ('active', 'idle') AND kind != 'human'`)).filter(e=>!p(e.profile_id)).map(e=>o(e.deadline_at))),"nextDue")}),r("structuredRequests",{nextDue:a(async e=>await s("SELECT 1 FROM structured_requests WHERE state != 'pending' AND effects_done_at IS NULL LIMIT 1")!==void 0?e:(await s("SELECT MIN(deadline_at) AS at FROM structured_requests WHERE state = 'pending' AND deadline_at IS NOT NULL"))?.at??null,"nextDue")}),r("cronLane",{nextDue:a(async()=>{const e=(await c(`SELECT fire_at, profile FROM crons
5
5
  WHERE state = 'active' AND run_state = 'idle'
6
- AND NOT (held = 1 AND recur IS NULL AND expires_at IS NULL)`).filter(i=>!p(i.profile)).map(i=>s(i.fire_at)),t=_("SELECT expires_at FROM crons WHERE expires_at IS NOT NULL AND run_state = 'idle'").map(i=>s(i.expires_at));return c([...e,...t])},"nextDue")});const n=r(e=>()=>a(`SELECT MIN(next_attempt_at) AS at FROM ${e} WHERE state = 'pending' AND canceled_at IS NULL AND next_attempt_at IS NOT NULL`)?.at??null,"attempts");o("deliveryLane",{nextDue:n("deliveries")}),o("actionLane",{nextDue:n("daemon_actions")}),o("pendingReviewSubmit",{nextDue:r(e=>O().length>0?e:null,"nextDue")}),o("storageDueWork",{nextDue:r(e=>{if(A()===null)return null;if(a("SELECT 1 FROM uploads WHERE delete_pending_since IS NOT NULL LIMIT 1")!==void 0||a("SELECT 1 FROM shares WHERE status = 'off' AND object_deleted_at IS NULL LIMIT 1")!==void 0)return e;const t=a("SELECT MIN(expires_at) AS at FROM shares WHERE status = 'on' AND expires_at IS NOT NULL")?.at,i=a(`SELECT MIN(created_at) AS at FROM uploads u WHERE delete_pending_since IS NULL
7
- AND NOT EXISTS (SELECT 1 FROM upload_uses x WHERE x.upload_id = u.upload_id)`)?.at,u=s(i);return c([s(t),u===null?null:u+h])},"nextDue")}),o("faultRetryBackstop",{nextDue:r(()=>c(I().map(e=>b(e))),"nextDue")})}r(D,"installDueSources");const R=12e4;function v(n){const e=_(`SELECT n.node_id, n.status, n.intent, n.profile_id, n.pi_pid, n.frozen_at, n.respawn_not_before, n.created, n.launched_at,
6
+ AND NOT (held = 1 AND recur IS NULL AND expires_at IS NULL)`)).filter(i=>!p(i.profile)).map(i=>o(i.fire_at)),t=(await c("SELECT expires_at FROM crons WHERE expires_at IS NOT NULL AND run_state = 'idle'")).map(i=>o(i.expires_at));return _([...e,...t])},"nextDue")});const n=a(async e=>async()=>(await s(`SELECT MIN(next_attempt_at) AS at FROM ${e} WHERE state = 'pending' AND canceled_at IS NULL AND next_attempt_at IS NOT NULL`))?.at??null,"attempts");r("deliveryLane",{nextDue:await n("deliveries")}),r("actionLane",{nextDue:await n("daemon_actions")}),r("pendingReviewSubmit",{nextDue:a(async e=>(await x()).length>0?e:null,"nextDue")}),r("storageDueWork",{nextDue:a(async e=>{if(I()===null)return null;if(await s("SELECT 1 FROM uploads WHERE delete_pending_since IS NOT NULL LIMIT 1")!==void 0||await s("SELECT 1 FROM shares WHERE status = 'off' AND object_deleted_at IS NULL LIMIT 1")!==void 0)return e;const t=(await s("SELECT MIN(expires_at) AS at FROM shares WHERE status = 'on' AND expires_at IS NOT NULL"))?.at,i=(await s(`SELECT MIN(created_at) AS at FROM uploads u WHERE delete_pending_since IS NULL
7
+ AND NOT EXISTS (SELECT 1 FROM upload_uses x WHERE x.upload_id = u.upload_id)`))?.at,u=o(i);return _([o(t),u===null?null:u+y])},"nextDue")}),r("faultRetryBackstop",{nextDue:a(async()=>_((await T()).map(e=>O(e))),"nextDue")})}a(S,"installDueSources");const w=12e4;async function U(n){const e=await c(`SELECT n.node_id, n.status, n.intent, n.profile_id, n.pi_pid, n.frozen_at, n.respawn_not_before, n.created, n.launched_at,
8
8
  n.turn_open_at, n.turn_closed_at,
9
9
  (SELECT x.started_at FROM executions x WHERE x.node_id = n.node_id AND x.state != 'exited') AS exec_started_at
10
10
  FROM node_rows n
11
- WHERE n.status IN ('active', 'idle') AND n.kind != 'human' AND n.${m}`);for(const t of e){if(p(t.profile_id)||!N({node_id:t.node_id,status:t.status,intent:t.intent}))continue;if(t.pi_pid!==null&&x(t.pi_pid)){if(t.turn_open_at!==null&&t.turn_closed_at===null)return!0;const d=s(t.exec_started_at);if(t.turn_open_at===null&&d!==null&&n-d<R||L(t.node_id))return!0;continue}if(t.respawn_not_before!==null)continue;if(t.pi_pid!==null||t.frozen_at!==null||t.status==="active")return!0;const u=Math.max(...[t.created,t.launched_at,t.exec_started_at].map(d=>s(d)??0));if(u>0&&n-u<R||t.status==="idle"&&L(t.node_id))return!0}return!1}r(v,"nodesOweWork");function X(n=Date.now()){D();const{dueNow:e,nextDueMs:t}=w(n,(u,d)=>{M({level:"warn",event:"daemon.due.source_failed",error:d,fields:{lane:u}})});return{busy:e||v(n)||a("SELECT 1 FROM crons WHERE run_state = 'running' LIMIT 1")!==void 0||a("SELECT 1 FROM jobs j JOIN objects o ON o.rowid = j.object WHERE j.status = 'running' AND o.deleted_at IS NULL LIMIT 1")!==void 0,next_due_at:t===null?null:new Date(t).toISOString()}}r(X,"dueReport");function K(){return D(),[...U(),...g()]}r(K,"coveredLanes");export{R as START_GRACE_MS,K as coveredLanes,X as dueReport,D as installDueSources};
11
+ WHERE n.status IN ('active', 'idle') AND n.kind != 'human' AND n.${N}`);for(const t of e){if(p(t.profile_id)||!await L({node_id:t.node_id,status:t.status,intent:t.intent}))continue;if(t.pi_pid!==null&&R(t.pi_pid)){if(t.turn_open_at!==null&&t.turn_closed_at===null)return!0;const d=o(t.exec_started_at);if(t.turn_open_at===null&&d!==null&&n-d<w||await E(t.node_id))return!0;continue}if(t.respawn_not_before!==null)continue;if(t.pi_pid!==null||t.frozen_at!==null||t.status==="active")return!0;const u=Math.max(...[t.created,t.launched_at,t.exec_started_at].map(d=>o(d)??0));if(u>0&&n-u<w||t.status==="idle"&&await E(t.node_id))return!0}return!1}a(U,"nodesOweWork");async function X(n=Date.now()){await S();const{dueNow:e,nextDueMs:t}=await b(n,(u,d)=>{A({level:"warn",event:"daemon.due.source_failed",error:d,fields:{lane:u}})});return{busy:e||await U(n)||await s("SELECT 1 FROM crons WHERE run_state = 'running' LIMIT 1")!==void 0||await s("SELECT 1 FROM jobs j JOIN objects o ON o.rowid = j.object WHERE j.status = 'running' AND o.deleted_at IS NULL LIMIT 1")!==void 0,next_due_at:t===null?null:new Date(t).toISOString()}}a(X,"dueReport");async function K(){return await S(),[...g(),...M()]}a(K,"coveredLanes");export{w as START_GRACE_MS,K as coveredLanes,X as dueReport,S as installDueSources};
@@ -66,8 +66,8 @@ export declare class DaemonFleet implements FleetRegistry {
66
66
  interruptForProfilePause(nodeId: string, pid?: number | undefined): void;
67
67
  hasProfilePauseInterruption(nodeId: string): boolean;
68
68
  forget(nodeId: string): void;
69
- onChildExit(nodeId: string, status: FleetExitStatus, executionId?: string): void;
70
- deliverExit(nodeId: string, status: FleetExitStatus): void;
69
+ onChildExit(nodeId: string, status: FleetExitStatus, executionId?: string): Promise<void>;
70
+ deliverExit(nodeId: string, status: FleetExitStatus): Promise<void>;
71
71
  /** The node-lifecycle tick's enactment entry. */
72
72
  applyDeadRowPolicy(nodeId: string): Promise<void>;
73
73
  /** A revive refusal before its launch try/catch leaves the row active but
@@ -1,21 +1,21 @@
1
- var g=Object.defineProperty;var l=(s,e)=>g(s,"name",{value:e,configurable:!0});import{getNode as v,getRow as k}from"../core/canvas/index.js";import{revokeExitedNodeToken as $}from"../core/canvas/node-tokens.js";import{isProfilePaused as T}from"../core/profiles/manifest.js";import{fullName as p}from"../core/canvas/labels.js";import{isSafeNodeId as o}from"../core/canvas/paths.js";import{hasIdleReleaseIntent as R,transition as _}from"../core/runtime/lifecycle.js";import{publishNotice as E}from"../core/runtime/close.js";import{readFault as P,readInterruptedTurn as N,readTransportPoisonVerdict as x}from"../core/canvas/recovery.js";import{hasPendingWake as C}from"./reconcilers/live-obligation.js";import{clearRespawnPolicy as h,deferRespawnWhileOffline as F,MAX_RESPAWN_ATTEMPTS as M,OFFLINE_RESPAWN_RETRY_MS as S,recordRespawnPolicy as O,respawnBackoffMs as z}from"./reconcilers/node-lifecycle/respawn-policy.js";import{probeOnline as A}from"../core/runtime/connectivity.js";import{reviveNode as B}from"../core/runtime/revive.js";import{pushUrgent as m}from"../core/feed/feed.js";import{emitEvent as c}from"../core/events/emit.js";import{brokerThresholdsForDaemon as D}from"../core/runtime/fleet.js";import{isRecoveryHeld as L}from"../core/runtime/recovery-hold.js";function w(s,e){const r=P(s.node_id),t=r===null?"":`The broker reported a ${r.kind} fault on ${r.link} (${r.op}) before it exited: ${r.message}
1
+ var g=Object.defineProperty;var l=(i,e)=>g(i,"name",{value:e,configurable:!0});import{getNode as w,getRow as k}from"../core/canvas/index.js";import{revokeExitedNodeToken as $}from"../core/canvas/node-tokens.js";import{isProfilePaused as T}from"../core/profiles/manifest.js";import{fullName as p}from"../core/canvas/labels.js";import{isSafeNodeId as o}from"../core/canvas/paths.js";import{hasIdleReleaseIntent as R,transition as v}from"../core/runtime/lifecycle.js";import{publishNotice as E}from"../core/runtime/close.js";import{readFault as P,readInterruptedTurn as N,readTransportPoisonVerdict as x}from"../core/canvas/recovery.js";import{hasPendingWake as C}from"./reconcilers/live-obligation.js";import{clearRespawnPolicy as h,deferRespawnWhileOffline as F,MAX_RESPAWN_ATTEMPTS as M,OFFLINE_RESPAWN_RETRY_MS as S,recordRespawnPolicy as O,respawnBackoffMs as z}from"./reconcilers/node-lifecycle/respawn-policy.js";import{probeOnline as A}from"../core/runtime/connectivity.js";import{reviveNode as B}from"../core/runtime/revive.js";import{pushUrgent as m}from"../core/feed/feed.js";import{emitEvent as c}from"../core/events/emit.js";import{brokerThresholdsForDaemon as D}from"../core/runtime/fleet.js";import{isRecoveryHeld as L}from"../core/runtime/recovery-hold.js";async function _(i,e){const t=await P(i.node_id),r=t===null?"":`The broker reported a ${t.kind} fault on ${t.link} (${t.op}) before it exited: ${t.message}
2
2
 
3
- `,i=e===void 0?"The daemon did not observe an exit status.":`The observed exit status was code ${e.code??"null"}, signal ${e.signal??"null"}.`;return`\u26A0 Spawn failed \u2014 \`${s.name}\` (${s.kind}) never started.
3
+ `,s=e===void 0?"The daemon did not observe an exit status.":`The observed exit status was code ${e.code??"null"}, signal ${e.signal??"null"}.`;return`\u26A0 Spawn failed \u2014 \`${i.name}\` (${i.kind}) never started.
4
4
 
5
- Its pi vehicle exited before the session came up (no pi_session_id was ever recorded), so the node produced no output. ${i}
5
+ Its pi vehicle exited before the session came up (no pi_session_id was ever recorded), so the node produced no output. ${s}
6
6
 
7
- `+t+`Inspect canonical event diagnostics with \`crtr sys logs --node ${s.node_id}\`.
7
+ `+r+`Inspect canonical event diagnostics with \`crtr sys logs --node ${i.node_id}\`.
8
8
 
9
- If the work still needs doing, re-spawn it.`}l(w,"bootFailureBody");async function y(s,e){await m(s.node_id,w(s,e),{from:s.node_id})}l(y,"surfaceBootFailure");function b(s){return`\u26A0 Out of memory \u2014 \`${s.name}\` (${s.kind}) was killed because its app's processes together passed the app's memory limit.
9
+ If the work still needs doing, re-spawn it.`}l(_,"bootFailureBody");async function y(i,e){await m(i.node_id,await _(i,e),{from:i.node_id})}l(y,"surfaceBootFailure");function b(i){return`\u26A0 Out of memory \u2014 \`${i.name}\` (${i.kind}) was killed because its app's processes together passed the app's memory limit.
10
10
 
11
- Every process of the run was stopped. The daemon does not restart it, because it would reach the same limit. Reduce what the run holds in memory, or ask the person to raise the app's limit (\`crtr sys limits set --app ${s.grantee??"app:terminal"} --memory <size>\`), then revive the node.`}l(b,"outOfMemoryBody");async function W(s){const e=x(s.node_id),r=e===null?"":`
11
+ Every process of the run was stopped. The daemon does not restart it, because it would reach the same limit. Reduce what the run holds in memory, or ask the person to raise the app's limit (\`crtr sys limits set --app ${i.grantee??"app:terminal"} --memory <size>\`), then revive the node.`}l(b,"outOfMemoryBody");async function W(i){const e=await x(i.node_id),t=e===null?"":`
12
12
 
13
- Provider rotation observed ${e.consecutivePasses} consecutive route-queue passes with no HTTP response (tried ${e.routes.join(", ")}). Check network and provider transport before reviving.`,t=`\u26A0 Crash loop \u2014 \`${s.name}\` (${s.kind}) kept dying without settling a turn.
13
+ Provider rotation observed ${e.consecutivePasses} consecutive route-queue passes with no HTTP response (tried ${e.routes.join(", ")}). Check network and provider transport before reviving.`,r=`\u26A0 Crash loop \u2014 \`${i.name}\` (${i.kind}) kept dying without settling a turn.
14
14
 
15
- Its session started successfully, but six consecutive relaunches made no progress, so the daemon stopped retrying.`+r+`
15
+ Its session started successfully, but six consecutive relaunches made no progress, so the daemon stopped retrying.`+t+`
16
16
 
17
- Fix the crash cause, then revive the node if the work still needs doing.`;await m(s.node_id,t,{from:s.node_id})}l(W,"surfaceCrashLoop");async function q(s,e){const r=e instanceof Error?e.message:String(e),t=`\u26A0 Recovery failed \u2014 \`${s.name}\` (${s.kind}) could not be relaunched.
17
+ Fix the crash cause, then revive the node if the work still needs doing.`;await m(i.node_id,r,{from:i.node_id})}l(W,"surfaceCrashLoop");async function q(i,e){const t=e instanceof Error?e.message:String(e),r=`\u26A0 Recovery failed \u2014 \`${i.name}\` (${i.kind}) could not be relaunched.
18
18
 
19
- The daemon refused this recovery before starting a broker: ${r}
19
+ The daemon refused this recovery before starting a broker: ${t}
20
20
 
21
- The node is now dead. Fix the recorded launch configuration, then revive it if the work still needs doing.`;await m(s.node_id,t,{from:s.node_id})}l(q,"surfaceRecoveryFailure");function G(s){return s?.cycle_pending!==!0}l(G,"retryResumeMode");function H(s,e,r=!0){return s===null||s.status==="done"||s.status==="canceled"||s.status==="dead"?"forget":s.intent==="refresh"?"respawn-fresh":R(s)?"dormant":s.lifecycle==="resident"&&!e&&!r&&s.pi_session_id!=null?"release-idle":s.pi_session_id!=null?G(s)?"respawn-resume":"respawn-cycle":e||s.fork_from!=null?"respawn-fresh":"boot-failure"}l(H,"classifyDeadNode");const Y=3e4;class le{static{l(this,"DaemonFleet")}#n;#o;#s;#l;#e=new Map;#r=new Set;#a=new Set;#t=new Map;#c=Number.NEGATIVE_INFINITY;constructor(e){this.#n=e.epoch,this.#o=e.enqueue,this.#s=e.now??Date.now,this.#l=e.probeOnline??(()=>A())}epoch(){return this.#n}register(e,r){if(this.#e.has(e))throw new Error(`fleet: ${e} already has a live broker entry \u2014 refusing a second launch (programming error)`);if(r.pid===null)throw new Error(`fleet: refusing to register ${e} with no pid`);this.#r.delete(e),this.#t.delete(e),this.#e.set(e,{pid:r.pid,handle:r})}has(e){return this.#e.has(e)}isClaimed(e){return this.#e.has(e)||this.#r.has(e)}get(e){return this.#e.get(e)}size(){return this.#e.size}occupancy(){return this.#e.size+this.#r.size}reserveSlot(e){if(this.#r.has(e)||this.#e.has(e))return!0;const{automaticReviveCap:r}=D();if(this.occupancy()<r)return this.#r.add(e),!0;const t=this.#s();return t-this.#c>=Y&&(this.#c=t,c({level:"warn",event:"broker.capacity.revive_deferred",fields:{live_count:this.occupancy(),hard_cap:r}})),!1}releaseReservation(e){this.#r.delete(e)}entries(){return this.#e.entries()}interruptForProfilePause(e,r=this.#e.get(e)?.pid){if(r!==void 0){this.#a.add(e);try{process.kill(r,"SIGTERM")}catch{}}}hasProfilePauseInterruption(e){return this.#a.has(e)}forget(e){this.#e.delete(e),this.#r.delete(e),this.#t.delete(e)}onChildExit(e,r,t){t&&$(t),this.#e.delete(e),this.#o(()=>{const i=v(e),a=i?.launched_at==null?Number.NaN:Date.parse(i.launched_at),n=Number.isFinite(a)?Math.max(0,this.#s()-a):null,d=i?.respawn_failures??0;i?.status==="done"||i?.status==="canceled"||i?.status==="dead"?this.#t.delete(e):this.#t.set(e,r),this.#u(e,r,n,d)})}deliverExit(e,r){this.onChildExit(e,r)}async applyDeadRowPolicy(e){const r=this.#t.get(e);try{await this.#f(e,r)}finally{this.#t.get(e)===r&&this.#t.delete(e)}}async terminalizeIfStillNonTerminal(e,r,t,i,a){const n=v(e);return n===null||n.status==="done"||n.status==="canceled"||n.status==="dead"?!1:(await this.#i(e,n,{event:r,reason:i,detail:a,wake:`Child crashed \u2014 ${p(n)} (${e}) could not be relaunched and is now dead. It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,surface:l(()=>q(n,t),"surface")}),!0)}dispose(){}#u(e,r,t,i){c({level:"info",event:"broker.exit.observed",...o(e)?{node_id:e}:{},fields:{...o(e)?{}:{affected_node_id:e},code:r.code,signal:r.signal,uptime_ms:t,consecutive_failures:i}})}async#f(e,r){return this.#h(e,r)}async#h(e,r){const t=v(e);if(t!==null&&T(t.profile_id))return h(e),"forget";if(this.#a.delete(e))return h(e),"forget";if(L(e))return"dormant";const i=N(e)?.interrupted===!0;if(r?.oomKilled===!0&&t!==null&&t.status!=="done"&&t.status!=="canceled"&&t.status!=="dead")return h(e),await this.#i(e,t,{event:"broker.out_of_memory",reason:"out_of_memory",detail:{schema:"crtr.node-outcome-detail/v1",message:b(t)},wake:`Child out of memory \u2014 ${p(t)} (${e}) used more memory than its app is allowed and is now dead. It is not restarted automatically. Revive it with \`crtr node lifecycle revive ${e}\` once the work needs less memory or the cap is raised (\`crtr sys limits set\`).`,surface:l(async()=>{await m(e,b(t),{from:e})},"surface")}),"forget";const a=H(t,i,C(e));switch(a){case"forget":h(e);break;case"dormant":h(e);break;case"release-idle":h(e),_(e,"release"),c({level:"info",event:"broker.recovery.released",...o(e)?{node_id:e}:{},fields:{...o(e)?{}:{affected_node_id:e}}});break;case"boot-failure":await this.#i(e,t,{event:"broker.boot.failed",reason:"boot_failed",detail:{schema:"crtr.node-outcome-detail/v1",message:w(t,r)},wake:`Child crashed \u2014 ${p(t)} (${e}) exited before its session ever came up and is now dead. It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,surface:l(()=>y(t,r),"surface")});break;case"respawn-fresh":case"respawn-cycle":case"respawn-resume":await this.#d(e,t,a,i);break}return a}async#d(e,r,t,i){const a=k(e);if(a===null)return;const n=a.respawn_failures??0;if(!await this.#l()){F(e,n,this.#s()),c({level:"info",event:"broker.respawn.offline_deferred",...o(e)?{node_id:e}:{},fields:{...o(e)?{}:{affected_node_id:e},action:t,retry_in_ms:S,consecutive_failures:n}});return}const d=a.respawn_not_before==null,f=d?O(a,this.#s()):{failures:n,notBefore:a.respawn_not_before,exhausted:n>=M};if(f.exhausted){const u=`Child crashed \u2014 ${p(r)} (${e}) kept dying without settling a turn (${f.failures} consecutive launches) and is now dead. It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`;await this.#i(e,r,{event:"broker.respawn.exhausted",reason:"crash_looped",detail:{schema:"crtr.node-outcome-detail/v1",message:u,respawn_failures:f.failures},wake:u,...r.pi_session_id!=null?{surface:l(()=>W(r),"surface")}:{}});return}if(d&&f.notBefore!==null){c({level:"info",event:"broker.respawn.deferred",...o(e)?{node_id:e}:{},fields:{...o(e)?{}:{affected_node_id:e},action:t,backoff_ms:z(f.failures),consecutive_failures:f.failures}});return}c({level:"info",event:"broker.respawn.started",...o(e)?{node_id:e}:{},fields:{...o(e)?{}:{affected_node_id:e},action:t,consecutive_failures:f.failures}});try{await B(e,{capacity:"freeze",resume:t==="respawn-resume",wakeReason:t==="respawn-resume"&&i?"runtime-restart-abort":void 0,recovery:!0})}catch(u){c({level:"error",event:"broker.respawn.failed",...o(e)?{node_id:e}:{},error:u,fields:{...o(e)?{}:{affected_node_id:e},action:t}}),await this.terminalizeIfStillNonTerminal(e,"broker.respawn.refused",u,"launch_failed",{schema:"crtr.node-outcome-detail/v1",message:u instanceof Error?u.message:String(u)})}}async#i(e,r,t){c({level:"error",event:t.event,...o(e)?{node_id:e}:{fields:{affected_node_id:e}}}),_(e,"crash",{reason:t.reason,outcome:{detail:t.detail}});try{await(t.surface??(()=>y(r)))()}catch(i){c({level:"error",event:"broker.boot_failure_surface.failed",...o(e)?{node_id:e}:{fields:{affected_node_id:e}},error:i})}E(e,"notice.crash",t.wake,{reason:"child-crashed",child:e})}}export{le as DaemonFleet,H as classifyDeadNode,G as retryResumeMode,y as surfaceBootFailure};
21
+ The node is now dead. Fix the recorded launch configuration, then revive it if the work still needs doing.`;await m(i.node_id,r,{from:i.node_id})}l(q,"surfaceRecoveryFailure");function G(i){return i?.cycle_pending!==!0}l(G,"retryResumeMode");function H(i,e,t=!0){return i===null||i.status==="done"||i.status==="canceled"||i.status==="dead"?"forget":i.intent==="refresh"?"respawn-fresh":R(i)?"dormant":i.lifecycle==="resident"&&!e&&!t&&i.pi_session_id!=null?"release-idle":i.pi_session_id!=null?G(i)?"respawn-resume":"respawn-cycle":e||i.fork_from!=null?"respawn-fresh":"boot-failure"}l(H,"classifyDeadNode");const Y=3e4;class le{static{l(this,"DaemonFleet")}#n;#o;#i;#l;#e=new Map;#t=new Set;#a=new Set;#r=new Map;#c=Number.NEGATIVE_INFINITY;constructor(e){this.#n=e.epoch,this.#o=e.enqueue,this.#i=e.now??Date.now,this.#l=e.probeOnline??(()=>A())}epoch(){return this.#n}register(e,t){if(this.#e.has(e))throw new Error(`fleet: ${e} already has a live broker entry \u2014 refusing a second launch (programming error)`);if(t.pid===null)throw new Error(`fleet: refusing to register ${e} with no pid`);this.#t.delete(e),this.#r.delete(e),this.#e.set(e,{pid:t.pid,handle:t})}has(e){return this.#e.has(e)}isClaimed(e){return this.#e.has(e)||this.#t.has(e)}get(e){return this.#e.get(e)}size(){return this.#e.size}occupancy(){return this.#e.size+this.#t.size}reserveSlot(e){if(this.#t.has(e)||this.#e.has(e))return!0;const{automaticReviveCap:t}=D();if(this.occupancy()<t)return this.#t.add(e),!0;const r=this.#i();return r-this.#c>=Y&&(this.#c=r,c({level:"warn",event:"broker.capacity.revive_deferred",fields:{live_count:this.occupancy(),hard_cap:t}})),!1}releaseReservation(e){this.#t.delete(e)}entries(){return this.#e.entries()}interruptForProfilePause(e,t=this.#e.get(e)?.pid){if(t!==void 0){this.#a.add(e);try{process.kill(t,"SIGTERM")}catch{}}}hasProfilePauseInterruption(e){return this.#a.has(e)}forget(e){this.#e.delete(e),this.#t.delete(e),this.#r.delete(e)}async onChildExit(e,t,r){r&&await $(r),this.#e.delete(e),this.#o(async()=>{const s=await w(e),a=s?.launched_at==null?Number.NaN:Date.parse(s.launched_at),n=Number.isFinite(a)?Math.max(0,this.#i()-a):null,d=s?.respawn_failures??0;s?.status==="done"||s?.status==="canceled"||s?.status==="dead"?this.#r.delete(e):this.#r.set(e,t),this.#u(e,t,n,d)})}async deliverExit(e,t){await this.onChildExit(e,t)}async applyDeadRowPolicy(e){const t=this.#r.get(e);try{await this.#f(e,t)}finally{this.#r.get(e)===t&&this.#r.delete(e)}}async terminalizeIfStillNonTerminal(e,t,r,s,a){const n=await w(e);return n===null||n.status==="done"||n.status==="canceled"||n.status==="dead"?!1:(await this.#s(e,n,{event:t,reason:s,detail:a,wake:`Child crashed \u2014 ${p(n)} (${e}) could not be relaunched and is now dead. It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,surface:l(()=>q(n,r),"surface")}),!0)}dispose(){}#u(e,t,r,s){c({level:"info",event:"broker.exit.observed",...o(e)?{node_id:e}:{},fields:{...o(e)?{}:{affected_node_id:e},code:t.code,signal:t.signal,uptime_ms:r,consecutive_failures:s}})}async#f(e,t){return this.#h(e,t)}async#h(e,t){const r=await w(e);if(r!==null&&T(r.profile_id))return await h(e),"forget";if(this.#a.delete(e))return await h(e),"forget";if(L(e))return"dormant";const s=(await N(e))?.interrupted===!0;if(t?.oomKilled===!0&&r!==null&&r.status!=="done"&&r.status!=="canceled"&&r.status!=="dead")return await h(e),await this.#s(e,r,{event:"broker.out_of_memory",reason:"out_of_memory",detail:{schema:"crtr.node-outcome-detail/v1",message:b(r)},wake:`Child out of memory \u2014 ${p(r)} (${e}) used more memory than its app is allowed and is now dead. It is not restarted automatically. Revive it with \`crtr node lifecycle revive ${e}\` once the work needs less memory or the cap is raised (\`crtr sys limits set\`).`,surface:l(async()=>{await m(e,b(r),{from:e})},"surface")}),"forget";const a=H(r,s,await C(e));switch(a){case"forget":await h(e);break;case"dormant":await h(e);break;case"release-idle":await h(e),await v(e,"release"),c({level:"info",event:"broker.recovery.released",...o(e)?{node_id:e}:{},fields:{...o(e)?{}:{affected_node_id:e}}});break;case"boot-failure":await this.#s(e,r,{event:"broker.boot.failed",reason:"boot_failed",detail:{schema:"crtr.node-outcome-detail/v1",message:await _(r,t)},wake:`Child crashed \u2014 ${p(r)} (${e}) exited before its session ever came up and is now dead. It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,surface:l(()=>y(r,t),"surface")});break;case"respawn-fresh":case"respawn-cycle":case"respawn-resume":await this.#d(e,r,a,s);break}return a}async#d(e,t,r,s){const a=await k(e);if(a===null)return;const n=a.respawn_failures??0;if(!await this.#l()){await F(e,n,this.#i()),c({level:"info",event:"broker.respawn.offline_deferred",...o(e)?{node_id:e}:{},fields:{...o(e)?{}:{affected_node_id:e},action:r,retry_in_ms:S,consecutive_failures:n}});return}const d=a.respawn_not_before==null,f=d?await O(a,this.#i()):{failures:n,notBefore:a.respawn_not_before,exhausted:n>=M};if(f.exhausted){const u=`Child crashed \u2014 ${p(t)} (${e}) kept dying without settling a turn (${f.failures} consecutive launches) and is now dead. It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`;await this.#s(e,t,{event:"broker.respawn.exhausted",reason:"crash_looped",detail:{schema:"crtr.node-outcome-detail/v1",message:u,respawn_failures:f.failures},wake:u,...t.pi_session_id!=null?{surface:l(()=>W(t),"surface")}:{}});return}if(d&&f.notBefore!==null){c({level:"info",event:"broker.respawn.deferred",...o(e)?{node_id:e}:{},fields:{...o(e)?{}:{affected_node_id:e},action:r,backoff_ms:z(f.failures),consecutive_failures:f.failures}});return}c({level:"info",event:"broker.respawn.started",...o(e)?{node_id:e}:{},fields:{...o(e)?{}:{affected_node_id:e},action:r,consecutive_failures:f.failures}});try{await B(e,{capacity:"freeze",resume:r==="respawn-resume",wakeReason:r==="respawn-resume"&&s?"runtime-restart-abort":void 0,recovery:!0})}catch(u){c({level:"error",event:"broker.respawn.failed",...o(e)?{node_id:e}:{},error:u,fields:{...o(e)?{}:{affected_node_id:e},action:r}}),await this.terminalizeIfStillNonTerminal(e,"broker.respawn.refused",u,"launch_failed",{schema:"crtr.node-outcome-detail/v1",message:u instanceof Error?u.message:String(u)})}}async#s(e,t,r){c({level:"error",event:r.event,...o(e)?{node_id:e}:{fields:{affected_node_id:e}}}),await v(e,"crash",{reason:r.reason,outcome:{detail:r.detail}});try{await(r.surface??(()=>y(t)))()}catch(s){c({level:"error",event:"broker.boot_failure_surface.failed",...o(e)?{node_id:e}:{fields:{affected_node_id:e}},error:s})}await E(e,"notice.crash",r.wake,{reason:"child-crashed",child:e})}}export{le as DaemonFleet,H as classifyDeadNode,G as retryResumeMode,y as surfaceBootFailure};
@@ -1,5 +1,5 @@
1
- var _=Object.defineProperty;var r=(t,e)=>_(t,"name",{value:e,configurable:!0});import{getRequest as y,getRequestByInboxTicket as b,presentationDir as q}from"../../core/human/requests.js";import{buildPageSummary as v}from"../../core/human/summary.js";import{validateFinalPageResponses as $}from"../../core/human/tickets.js";import{composeHumanCompletion as j}from"../../core/human/completion.js";import{describePageAnswer as k}from"../../core/human/answer.js";import{renderAnswerText as S}from"../../core/human/answer-text.js";import{readPageFeedback as T}from"../../core/human/feedback.js";import{pageDocumentSha256 as A}from"../../core/human/feedback-companion.js";import{pagePath as N}from"../../core/human/convention.js";import{retireCompanion as f}from"../companion-retire.js";import{settleHumanRequest as h}from"./settle.js";function d(t){const e=y(t)??b(t);if(e===null||e.kind!=="page")throw new Error(`unknown page request: ${t}`);return e}r(d,"requestForTicket");function c(t){try{const e=JSON.parse(t.specification_json);if(typeof e!="object"||e===null)throw new Error("not an object");return e}catch(e){throw new Error(`corrupt page specification: ${t.request_id}`,{cause:e})}}r(c,"manifest");function u(t,e){if(t.action_json!==null)try{const n=JSON.parse(t.action_json);if(n.schema!=="crtr.human-action-binding/v1"||!Array.isArray(n.argv)||typeof n.cwd!="string")throw new Error("invalid binding");return{adapter:{adapter:"subprocess",argv:n.argv,cwd:n.cwd,node_id:t.requester_node_id,...n.app?{app:n.app}:{}},bodyJson:j({requestId:t.request_id,result:e,binding:n,source:c(t).source??{}})}}catch(n){throw new Error(`corrupt frozen completion action: ${t.request_id}`,{cause:n})}}r(u,"completionAction");function O(t,e=80){const n=t.split(`
2
- `)[0]??"";return n.length>e?`${n.slice(0,e-1)}\u2026`:n}r(O,"firstLine");function x(t){try{return c(t).title}catch{return}}r(x,"pageTitle");function w(t){let e;try{const n=T(t.request_dir);if(n.companionNodeId===void 0)return"";e=[],n.firstCommentedSha256!==void 0&&A(t.request_dir)!==n.firstCommentedSha256&&e.push(`The page changed during feedback: the person commented on it and its companion conversation (node ${n.companionNodeId}) revised it in place. Reread the final page at ${N(q(t),c(t).dialect)} before interpreting this outcome.`);const o=n.comments.filter(i=>i.status==="open");if(o.length>0){const i=o.map(s=>[...s.quote.split(`
1
+ var _=Object.defineProperty;var r=(t,e)=>_(t,"name",{value:e,configurable:!0});import{getRequest as y,getRequestByInboxTicket as b,presentationDir as q}from"../../core/human/requests.js";import{buildPageSummary as v}from"../../core/human/summary.js";import{validateFinalPageResponses as $}from"../../core/human/tickets.js";import{composeHumanCompletion as j}from"../../core/human/completion.js";import{describePageAnswer as k}from"../../core/human/answer.js";import{renderAnswerText as S}from"../../core/human/answer-text.js";import{readPageFeedback as T}from"../../core/human/feedback.js";import{pageDocumentSha256 as A}from"../../core/human/feedback-companion.js";import{pagePath as N}from"../../core/human/convention.js";import{retireCompanion as f}from"../companion-retire.js";import{settleHumanRequest as w}from"./settle.js";async function d(t){const e=await y(t)??await b(t);if(e===null||e.kind!=="page")throw new Error(`unknown page request: ${t}`);return e}r(d,"requestForTicket");function c(t){try{const e=JSON.parse(t.specification_json);if(typeof e!="object"||e===null)throw new Error("not an object");return e}catch(e){throw new Error(`corrupt page specification: ${t.request_id}`,{cause:e})}}r(c,"manifest");function u(t,e){if(t.action_json!==null)try{const n=JSON.parse(t.action_json);if(n.schema!=="crtr.human-action-binding/v1"||!Array.isArray(n.argv)||typeof n.cwd!="string")throw new Error("invalid binding");return{adapter:{adapter:"subprocess",argv:n.argv,cwd:n.cwd,node_id:t.requester_node_id,...n.app?{app:n.app}:{}},bodyJson:j({requestId:t.request_id,result:e,binding:n,source:c(t).source??{}})}}catch(n){throw new Error(`corrupt frozen completion action: ${t.request_id}`,{cause:n})}}r(u,"completionAction");function O(t,e=80){const n=t.split(`
2
+ `)[0]??"";return n.length>e?`${n.slice(0,e-1)}\u2026`:n}r(O,"firstLine");function x(t){try{return c(t).title}catch{return}}r(x,"pageTitle");async function h(t){let e;try{const n=await T(t.request_dir);if(n.companionNodeId===void 0)return"";e=[],n.firstCommentedSha256!==void 0&&await A(t.request_dir)!==n.firstCommentedSha256&&e.push(`The page changed during feedback: the person commented on it and its companion conversation (node ${n.companionNodeId}) revised it in place. Reread the final page at ${N(q(t),c(t).dialect)} before interpreting this outcome.`);const o=n.comments.filter(i=>i.status==="open");if(o.length>0){const i=o.map(s=>[...s.quote.split(`
3
3
  `).map(a=>`> ${a}`),s.note].join(`
4
4
  `));e.push([`Feedback left unresolved at settlement \u2014 the companion conversation (node ${n.companionNodeId}) had not dealt with these items:`,...i].join(`
5
5
 
@@ -7,4 +7,4 @@ var _=Object.defineProperty;var r=(t,e)=>_(t,"name",{value:e,configurable:!0});i
7
7
 
8
8
  ${e.join(`
9
9
 
10
- `)}`}r(w,"feedbackAddendum");function E(t,e){const n=k(c(t),e.responses,{completedAt:e.completedAt});return S(n)+w(t)}r(E,"answerBody");function J(t,e,n){const o=x(t),i=o===void 0?`the human interaction ${t.request_id}`:`\u201C${o}\u201D`,s=n!==void 0&&n!==""?n:"no reason was given";return(e?`The user dismissed ${i} without answering \u2014 a deliberate \u201Cno, I'm not answering this.\u201D Treat it as a rejection: no response will arrive, no partial answer exists, and the same ask must not be raised again.`:`${o===void 0?`The human interaction ${t.request_id}`:`The page \u201C${o}\u201D`} was canceled \u2014 ${s}. No response will arrive, and any partial answers the user had entered were discarded unsent.`)+w(t)}r(J,"cancelBody");function g(t,e,n,o){if(t.requester_node_id!==null)return{label:O(n),disposition:e,body_json:{body:n,result:o}}}r(g,"notification");function l(t){return t.companion_node_id===null?void 0:{retire:r(async(e,n)=>{await f(e,n)},"retire")}}r(l,"retire");async function Q(t,e,n={}){return(await P(t,e,n)).result}r(Q,"resolvePageTicket");async function P(t,e,n={}){const o=d(t),i=c(o),s=$(i,e),a={schema:"crtr.page-response/v1",kind:"page",responses:s,summary:v(i,s),completedAt:n.completedAt??new Date().toISOString(),...n.actor===void 0?{}:{actor:n.actor}},m=await h({request_id:o.request_id,outcome:"answered",result_json:JSON.stringify(a),notification:r(p=>g(p,"human-answer",E(p,a),a),"notification"),...u(o,a)===void 0?{}:{completion_action:u(o,a)},...l(o)===void 0?{}:{post_commit:l(o)}});if(m.outcome==="already_settled"){if(m.request.result_json===null)throw new Error(`settled page request lacks a result: ${o.request_id}`);return{outcome:"already_settled",result:JSON.parse(m.request.result_json)}}return{outcome:"settled",result:a}}r(P,"answerPageTicket");async function U(t,e){const n=d(t),i={schema:"humanloop.cancel/v1",kind:"canceled",canceledAt:new Date().toISOString(),...e.reason===void 0?{}:{reason:e.reason},...e.actor===void 0?{}:{actor:e.actor},...e.disposition===void 0?{}:{disposition:e.disposition}},s=await h({request_id:n.request_id,outcome:e.disposition==="dismissed"?"dismissed":"canceled",result_json:JSON.stringify(i),notification:r(a=>g(a,"human-canceled",J(a,e.disposition==="dismissed",e.reason),i),"notification"),...u(n,i)===void 0?{}:{completion_action:u(n,i)},...l(n)===void 0?{}:{post_commit:l(n)}});if(s.outcome==="already_settled"){if(s.request.result_json===null)throw new Error(`settled page request lacks a result: ${n.request_id}`);return{outcome:"already_settled",result:JSON.parse(s.request.result_json)}}return{outcome:"settled",result:i}}r(U,"cancelHumanTicket");async function V(t){return d(t).state==="settled"}r(V,"deliverTerminalResult");async function W(t,e){const n=d(t);n.companion_node_id!==null&&await f(n.companion_node_id,e)}r(W,"settleFeedbackCompanion");export{P as answerPageTicket,U as cancelHumanTicket,V as deliverTerminalResult,Q as resolvePageTicket,W as settleFeedbackCompanion};
10
+ `)}`}r(h,"feedbackAddendum");async function E(t,e){const n=k(c(t),e.responses,{completedAt:e.completedAt});return S(n)+await h(t)}r(E,"answerBody");async function J(t,e,n){const o=x(t),i=o===void 0?`the human interaction ${t.request_id}`:`\u201C${o}\u201D`,s=n!==void 0&&n!==""?n:"no reason was given";return(e?`The user dismissed ${i} without answering \u2014 a deliberate \u201Cno, I'm not answering this.\u201D Treat it as a rejection: no response will arrive, no partial answer exists, and the same ask must not be raised again.`:`${o===void 0?`The human interaction ${t.request_id}`:`The page \u201C${o}\u201D`} was canceled \u2014 ${s}. No response will arrive, and any partial answers the user had entered were discarded unsent.`)+await h(t)}r(J,"cancelBody");function g(t,e,n,o){if(t.requester_node_id!==null)return{label:O(n),disposition:e,body_json:{body:n,result:o}}}r(g,"notification");function l(t){return t.companion_node_id===null?void 0:{retire:r(async(e,n)=>{await f(e,n)},"retire")}}r(l,"retire");async function Q(t,e,n={}){return(await P(t,e,n)).result}r(Q,"resolvePageTicket");async function P(t,e,n={}){const o=await d(t),i=c(o),s=$(i,e),a={schema:"crtr.page-response/v1",kind:"page",responses:s,summary:v(i,s),completedAt:n.completedAt??new Date().toISOString(),...n.actor===void 0?{}:{actor:n.actor}},m=await w({request_id:o.request_id,outcome:"answered",result_json:JSON.stringify(a),notification:r(async p=>g(p,"human-answer",await E(p,a),a),"notification"),...u(o,a)===void 0?{}:{completion_action:u(o,a)},...l(o)===void 0?{}:{post_commit:l(o)}});if(m.outcome==="already_settled"){if(m.request.result_json===null)throw new Error(`settled page request lacks a result: ${o.request_id}`);return{outcome:"already_settled",result:JSON.parse(m.request.result_json)}}return{outcome:"settled",result:a}}r(P,"answerPageTicket");async function U(t,e){const n=await d(t),i={schema:"humanloop.cancel/v1",kind:"canceled",canceledAt:new Date().toISOString(),...e.reason===void 0?{}:{reason:e.reason},...e.actor===void 0?{}:{actor:e.actor},...e.disposition===void 0?{}:{disposition:e.disposition}},s=await w({request_id:n.request_id,outcome:e.disposition==="dismissed"?"dismissed":"canceled",result_json:JSON.stringify(i),notification:r(async a=>g(a,"human-canceled",await J(a,e.disposition==="dismissed",e.reason),i),"notification"),...u(n,i)===void 0?{}:{completion_action:u(n,i)},...l(n)===void 0?{}:{post_commit:l(n)}});if(s.outcome==="already_settled"){if(s.request.result_json===null)throw new Error(`settled page request lacks a result: ${n.request_id}`);return{outcome:"already_settled",result:JSON.parse(s.request.result_json)}}return{outcome:"settled",result:i}}r(U,"cancelHumanTicket");async function V(t){return(await d(t)).state==="settled"}r(V,"deliverTerminalResult");async function W(t,e){const n=await d(t);n.companion_node_id!==null&&await f(n.companion_node_id,e)}r(W,"settleFeedbackCompanion");export{P as answerPageTicket,U as cancelHumanTicket,V as deliverTerminalResult,Q as resolvePageTicket,W as settleFeedbackCompanion};
@@ -14,7 +14,7 @@ export interface SettleHumanRequestInput {
14
14
  outcome: HumanRequestOutcome;
15
15
  result_json: string;
16
16
  settled_at?: string;
17
- notification?: SettlementNotification | ((request: HumanRequestRecord) => SettlementNotification | undefined);
17
+ notification?: SettlementNotification | ((request: HumanRequestRecord) => Promise<SettlementNotification | undefined> | SettlementNotification | undefined);
18
18
  completion_action?: {
19
19
  adapter: DaemonActionAdapter;
20
20
  bodyJson: unknown;
@@ -1 +1 @@
1
- var u=Object.defineProperty;var d=(e,o)=>u(e,"name",{value:o,configurable:!0});import{withCanvasWrite as m}from"../../core/canvas/db.js";import{enqueueDaemonAction as f}from"../../core/canvas/daemon-actions.js";import{cancelDelivery as p,enqueueNodeMail as w}from"../../core/feed/messages.js";import{getRequest as l,markCompanionRetired as y,markProjected as q,markProjectionError as v,setSettlementDeliveryMarksLocked as j,settleRequestLocked as h}from"../../core/human/requests.js";import{appendQuestionAnswered as k}from"../../core/runs/questions.js";import{notifyProviderApproval as b}from"../../core/providers/approval.js";async function x(e){const o=m(i=>{const _=e.settled_at??new Date().toISOString(),t=h(i,{request_id:e.request_id,outcome:e.outcome,result_json:e.result_json,settled_at:_});if(t===null){const c=l(e.request_id);if(c===null)throw new Error(`human request disappeared while settling: ${e.request_id}`);return{outcome:"already_settled",request:c}}const n=typeof e.notification=="function"?e.notification(t):e.notification;if(t.requester_node_id!==null&&n===void 0)throw new Error(`request ${t.request_id} needs a requester notification`);if(t.action_json!==null&&t.kind==="page"&&e.completion_action===void 0)throw new Error(`request ${t.request_id} needs its frozen completion action`);if(t.kind==="review"&&t.projected_at===null&&e.post_commit?.project===void 0)throw new Error(`review ${t.request_id} needs a projection effect`);if(t.companion_node_id!==null&&t.companion_retired_at===null&&e.post_commit?.retire===void 0)throw new Error(`request ${t.request_id} needs a companion retirement effect`);let a=null,s=null;if(t.requester_node_id!==null){if(n===void 0)throw new Error(`request ${t.request_id} needs a requester notification`);a=w(t.requester_node_id,{kind:"completed",label:n.label,senderName:"crtrd",...n.body_ref===void 0?{}:{bodyRef:n.body_ref},...n.body_json===void 0?{}:{bodyJson:n.body_json},disposition:n.disposition,urgency:"normal",wake:1}).deliveryId}t.action_json!==null&&e.completion_action!==void 0&&t.kind==="page"&&(s=f({adapter:e.completion_action.adapter,bodyJson:e.completion_action.bodyJson,idempotencyKey:`human-action:${t.inbox_ticket_id}`})),t.submit_note_delivery_id!==null&&p(t.submit_note_delivery_id),j(i,t.request_id,{settlement_delivery_id:a,action_delivery_id:s});const r=l(t.request_id);if(r===null)throw new Error(`settled human request disappeared: ${t.request_id}`);return k(i,r),{outcome:"settled",request:r}});return o.outcome==="settled"&&(b(o.request.request_id),e.post_commit!==void 0&&await g(o.request,e.post_commit)),o}d(x,"settleHumanRequest");async function g(e,o){if(e.kind==="review"&&e.projected_at===null&&o.project!==void 0)try{await o.project(e),q(e.request_id,new Date().toISOString())}catch(i){v(e.request_id,i instanceof Error?i.message:String(i))}if(e.companion_node_id!==null&&e.companion_retired_at===null&&o.retire!==void 0)try{await o.retire(e.companion_node_id,e.outcome==="canceled"||e.outcome==="dismissed"?"canceled":"approved"),y(e.request_id,new Date().toISOString())}catch{}}d(g,"projectAndRetire");export{g as projectAndRetire,x as settleHumanRequest};
1
+ var u=Object.defineProperty;var d=(e,o)=>u(e,"name",{value:o,configurable:!0});import{withCanvasWrite as m}from"../../core/canvas/db.js";import{enqueueDaemonAction as f}from"../../core/canvas/daemon-actions.js";import{cancelDelivery as w,enqueueNodeMail as p}from"../../core/feed/messages.js";import{getRequest as l,markCompanionRetired as y,markProjected as q,markProjectionError as v,setSettlementDeliveryMarksLocked as j,settleRequestLocked as h}from"../../core/human/requests.js";import{appendQuestionAnswered as k}from"../../core/runs/questions.js";import{notifyProviderApproval as b}from"../../core/providers/approval.js";async function x(e){const o=await m(async n=>{const _=e.settled_at??new Date().toISOString(),t=await h(n,{request_id:e.request_id,outcome:e.outcome,result_json:e.result_json,settled_at:_});if(t===null){const c=await l(e.request_id);if(c===null)throw new Error(`human request disappeared while settling: ${e.request_id}`);return{outcome:"already_settled",request:c}}const i=typeof e.notification=="function"?await e.notification(t):e.notification;if(t.requester_node_id!==null&&i===void 0)throw new Error(`request ${t.request_id} needs a requester notification`);if(t.action_json!==null&&t.kind==="page"&&e.completion_action===void 0)throw new Error(`request ${t.request_id} needs its frozen completion action`);if(t.kind==="review"&&t.projected_at===null&&e.post_commit?.project===void 0)throw new Error(`review ${t.request_id} needs a projection effect`);if(t.companion_node_id!==null&&t.companion_retired_at===null&&e.post_commit?.retire===void 0)throw new Error(`request ${t.request_id} needs a companion retirement effect`);let a=null,s=null;if(t.requester_node_id!==null){if(i===void 0)throw new Error(`request ${t.request_id} needs a requester notification`);a=(await p(t.requester_node_id,{kind:"completed",label:i.label,senderName:"crtrd",...i.body_ref===void 0?{}:{bodyRef:i.body_ref},...i.body_json===void 0?{}:{bodyJson:i.body_json},disposition:i.disposition,urgency:"normal",wake:1})).deliveryId}t.action_json!==null&&e.completion_action!==void 0&&t.kind==="page"&&(s=await f({adapter:e.completion_action.adapter,bodyJson:e.completion_action.bodyJson,idempotencyKey:`human-action:${t.inbox_ticket_id}`})),t.submit_note_delivery_id!==null&&await w(t.submit_note_delivery_id),await j(n,t.request_id,{settlement_delivery_id:a,action_delivery_id:s});const r=await l(t.request_id);if(r===null)throw new Error(`settled human request disappeared: ${t.request_id}`);return await k(n,r),{outcome:"settled",request:r}});return o.outcome==="settled"&&(b(o.request.request_id),e.post_commit!==void 0&&await g(o.request,e.post_commit)),o}d(x,"settleHumanRequest");async function g(e,o){if(e.kind==="review"&&e.projected_at===null&&o.project!==void 0)try{await o.project(e),await q(e.request_id,new Date().toISOString())}catch(n){await v(e.request_id,n instanceof Error?n.message:String(n))}if(e.companion_node_id!==null&&e.companion_retired_at===null&&o.retire!==void 0)try{await o.retire(e.companion_node_id,e.outcome==="canceled"||e.outcome==="dismissed"?"canceled":"approved"),await y(e.request_id,new Date().toISOString())}catch{}}d(g,"projectAndRetire");export{g as projectAndRetire,x as settleHumanRequest};
@@ -1 +1 @@
1
- var m=Object.defineProperty;var n=(e,o)=>m(e,"name",{value:o,configurable:!0});import{existsSync as p,readdirSync as f,rmSync as y}from"node:fs";import{reviewsRoot as c}from"../../core/canvas/paths.js";import{listBindingRequests as w,listRequests as u,listUnprojectedReviews as q,markProjectionError as v}from"../../core/human/requests.js";import{projectAndRetire as d}from"./settle.js";function R(e){return e instanceof Error?e.message:String(e)}n(R,"errorText");async function g(){}n(g,"reconcileUndeliveredTickets");async function k(e){let o=0,s=0,a=0,l=0,i=0;for(const r of w())try{await e.realizeReview(r.request_id),o+=1}catch{i+=1}try{const r=new Set(u({kind:"review"}).map(t=>t.request_id));if(p(c()))for(const t of f(c(),{withFileTypes:!0}))t.isDirectory()&&!r.has(t.name)&&(y(`${c()}/${t.name}`,{recursive:!0,force:!0}),s+=1)}catch{i+=1}for(const r of q())try{await d(r,{project:e.projectReview,retire:e.retireCompanion}),a+=1}catch(t){v(r.request_id,R(t)),i+=1}for(const r of u({state:"settled"}))if(!(r.companion_node_id===null||r.companion_retired_at!==null))try{await d(r,{retire:e.retireCompanion}),l+=1}catch{i+=1}return{realized:o,collected:s,reprojected:a,retired:l,failed:i}}n(k,"sweepHumanRequests");export{g as reconcileUndeliveredTickets,k as sweepHumanRequests};
1
+ var m=Object.defineProperty;var n=(e,o)=>m(e,"name",{value:o,configurable:!0});import{existsSync as p,readdirSync as w,rmSync as f}from"node:fs";import{reviewsRoot as a}from"../../core/canvas/paths.js";import{listBindingRequests as y,listRequests as u,listUnprojectedReviews as q,markProjectionError as v}from"../../core/human/requests.js";import{projectAndRetire as d}from"./settle.js";function R(e){return e instanceof Error?e.message:String(e)}n(R,"errorText");async function g(){}n(g,"reconcileUndeliveredTickets");async function k(e){let o=0,c=0,s=0,l=0,i=0;for(const t of await y())try{await e.realizeReview(t.request_id),o+=1}catch{i+=1}try{const t=new Set((await u({kind:"review"})).map(r=>r.request_id));if(p(a()))for(const r of w(a(),{withFileTypes:!0}))r.isDirectory()&&!t.has(r.name)&&(f(`${a()}/${r.name}`,{recursive:!0,force:!0}),c+=1)}catch{i+=1}for(const t of await q())try{await d(t,{project:e.projectReview,retire:e.retireCompanion}),s+=1}catch(r){await v(t.request_id,R(r)),i+=1}for(const t of await u({state:"settled"}))if(!(t.companion_node_id===null||t.companion_retired_at!==null))try{await d(t,{retire:e.retireCompanion}),l+=1}catch{i+=1}return{realized:o,collected:c,reprojected:s,retired:l,failed:i}}n(k,"sweepHumanRequests");export{g as reconcileUndeliveredTickets,k as sweepHumanRequests};
@@ -1,5 +1,5 @@
1
1
  /** Rows changed, or null when this runtime has not joined a directory or the rewrite already ran for its owner. */
2
- export declare function applyJoinedOwner(): {
2
+ export declare function applyJoinedOwner(): Promise<{
3
3
  owner: string;
4
4
  rows: number;
5
- } | null;
5
+ } | null>;
@@ -1 +1 @@
1
- var m=Object.defineProperty;var o=(r,e)=>m(r,"name",{value:e,configurable:!0});import{withCanvasWrite as p}from"../core/canvas/db.js";import{rewriteLocalNodeIdentity as l}from"../core/canvas/canvas.js";import{rewriteLocalNodeTokenIdentity as c}from"../core/canvas/node-tokens.js";import{joinedOwner as u}from"../core/directory/join.js";import{LOCAL_TERMINAL_GRANT_ID as t}from"../core/grants/local.js";import{dropLocalGrantMirror as E}from"../core/grants/mirror.js";import{rewriteLocalRunEventGrantee as f}from"../core/runs/events.js";import{rewriteLocalIdempotencyGrantee as L}from"../core/runs/operations.js";import{prepared as n}from"../core/sqlite-statements.js";const a="joined_owner_applied";function A(){const r=u();return r===null?null:p(e=>{if(n(e,"SELECT value FROM canvas_meta WHERE key = ?").get(a)?.value===r)return null;const i=l(e,r,t)+c(e,r,t)+E(e)+f(e)+L(e);return n(e,"INSERT INTO canvas_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(a,r),{owner:r,rows:i}})}o(A,"applyJoinedOwner");export{A as applyJoinedOwner};
1
+ var i=Object.defineProperty;var a=(r,e)=>i(r,"name",{value:e,configurable:!0});import{withCanvasWrite as p}from"../core/canvas/db.js";import{rewriteLocalNodeIdentity as l}from"../core/canvas/canvas.js";import{rewriteLocalNodeTokenIdentity as m}from"../core/canvas/node-tokens.js";import{joinedOwner as w}from"../core/directory/join.js";import{LOCAL_TERMINAL_GRANT_ID as t}from"../core/grants/local.js";import{dropLocalGrantMirror as c}from"../core/grants/mirror.js";import{rewriteLocalRunEventGrantee as u}from"../core/runs/events.js";import{rewriteLocalIdempotencyGrantee as E}from"../core/runs/operations.js";const o="joined_owner_applied";async function d(){const r=w();return r===null?null:await p(async e=>{if((await e.prepare("SELECT value FROM canvas_meta WHERE key = ?").get(o))?.value===r)return null;const n=await l(e,r,t)+await m(e,r,t)+await c(e)+await u(e)+await E(e);return await e.prepare("INSERT INTO canvas_meta (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value").run(o,r),{owner:r,rows:n}})}a(d,"applyJoinedOwner");export{d as applyJoinedOwner};
@@ -1 +1 @@
1
- var a=Object.defineProperty;var r=(e,i)=>a(e,"name",{value:i,configurable:!0});import{getNode as l}from"../../core/canvas/canvas.js";import{cancelCronsOnWake as c}from"../../core/canvas/crons.js";import{withFreshTerminalGuard as _}from"../../core/canvas/canvas.js";import{emitEvent as s}from"../../core/events/emit.js";import{enqueueNodeMail as y}from"../../core/feed/messages.js";import{BrokerUnreachableError as p}from"../../core/runtime/broker-request.js";import{deliverLive as v}from"../../core/runtime/interactive-deliver.js";import{isBrokerLive as u}from"../../core/runtime/model-swap.js";import{reviveNode as b}from"../../core/runtime/revive.js";import{hasNoNaturalCycle as h}from"../../core/runtime/revive-all.js";import{ReviewOperationError as k}from"../../core/review/types.js";import{formatCard as w}from"../../shared/generated-context.js";import{isProfilePaused as N}from"../../core/profiles/manifest.js";function d(e,i){throw new k("delivery_unroutable",i==="origin_missing"?"message target was not found":"message target has no natural delivery cycle",{node_id:e,reason:i})}r(d,"deliveryUnroutable");function m(e,i){const n=_(e,h,i);return n.kind==="missing"&&d(e,"origin_missing"),n.kind==="terminal"&&d(e,"no_natural_cycle"),n.result}r(m,"guardRoutable");async function G(e){m(e.node_id,()=>{});let i=l(e.node_id);if(i===null&&d(e.node_id,"origin_missing"),e.mode==="interactive"&&!i.run_id&&!N(i.profile_id)&&u(i))try{return await v(e.node_id,e.runtime===void 0?e.body:w(e.runtime.kind,e.runtime.facts,e.body),{origin:e.from==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:[{...e.from==null?{}:{from:e.from},kind:"message",tier:"normal"}]}}),m(e.node_id,()=>{}),c(e.node_id),{entry_id:null,via:"engine",revived:!1}}catch(o){if(!(o instanceof p))throw o}const n=m(e.node_id,()=>y(e.node_id,{senderNodeId:e.from??null,kind:"message",label:e.label,bodyJson:{...e.data,body:e.body},urgency:e.mode==="quiet"?"deferred":"normal",wake:1}));let f=!1,t;if(n.urgency!=="deferred"&&(i=l(e.node_id),i===null&&d(e.node_id,"origin_missing"),!u(i)))try{const o=await b(e.node_id,{resume:!0,capacity:"freeze"});f=o.launch!==void 0,o.outcome==="frozen"&&(t="capacity_frozen")}catch(o){s({level:"error",event:"message.wake_failed",node_id:e.node_id,error:o,fields:{message_id:n.messageId}})}return{entry_id:n.messageId,via:"inbox",revived:f,...t===void 0?{}:{reason:t}}}r(G,"deliverNodeMessage");export{G as deliverNodeMessage};
1
+ var u=Object.defineProperty;var r=(e,i)=>u(e,"name",{value:i,configurable:!0});import{getNode as f}from"../../core/canvas/canvas.js";import{cancelCronsOnWake as c}from"../../core/canvas/crons.js";import{withFreshTerminalGuard as s}from"../../core/canvas/canvas.js";import{emitEvent as _}from"../../core/events/emit.js";import{enqueueNodeMail as y}from"../../core/feed/messages.js";import{BrokerUnreachableError as p}from"../../core/runtime/broker-request.js";import{deliverLive as v}from"../../core/runtime/interactive-deliver.js";import{isBrokerLive as l}from"../../core/runtime/model-swap.js";import{reviveNode as w}from"../../core/runtime/revive.js";import{hasNoNaturalCycle as b}from"../../core/runtime/revive-all.js";import{ReviewOperationError as h}from"../../core/review/types.js";import{formatCard as k}from"../../shared/generated-context.js";import{isProfilePaused as N}from"../../core/profiles/manifest.js";function t(e,i){throw new h("delivery_unroutable",i==="origin_missing"?"message target was not found":"message target has no natural delivery cycle",{node_id:e,reason:i})}r(t,"deliveryUnroutable");async function a(e,i){const n=await s(e,b,i);return n.kind==="missing"&&t(e,"origin_missing"),n.kind==="terminal"&&t(e,"no_natural_cycle"),n.result}r(a,"guardRoutable");async function G(e){await a(e.node_id,async()=>{});let i=await f(e.node_id);if(i===null&&t(e.node_id,"origin_missing"),e.mode==="interactive"&&!i.run_id&&!N(i.profile_id)&&l(i))try{return await v(e.node_id,e.runtime===void 0?e.body:k(e.runtime.kind,e.runtime.facts,e.body),{origin:e.from==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:[{...e.from==null?{}:{from:e.from},kind:"message",tier:"normal"}]}}),await a(e.node_id,async()=>{}),await c(e.node_id),{entry_id:null,via:"engine",revived:!1}}catch(o){if(!(o instanceof p))throw o}const n=await a(e.node_id,async()=>await y(e.node_id,{senderNodeId:e.from??null,kind:"message",label:e.label,bodyJson:{...e.data,body:e.body},urgency:e.mode==="quiet"?"deferred":"normal",wake:1}));let m=!1,d;if(n.urgency!=="deferred"&&(i=await f(e.node_id),i===null&&t(e.node_id,"origin_missing"),!l(i)))try{const o=await w(e.node_id,{resume:!0,capacity:"freeze"});m=o.launch!==void 0,o.outcome==="frozen"&&(d="capacity_frozen")}catch(o){_({level:"error",event:"message.wake_failed",node_id:e.node_id,error:o,fields:{message_id:n.messageId}})}return{entry_id:n.messageId,via:"inbox",revived:m,...d===void 0?{}:{reason:d}}}r(G,"deliverNodeMessage");export{G as deliverNodeMessage};
@@ -2,8 +2,8 @@ import type { NodeMeta } from '../core/canvas/types.js';
2
2
  import type { PendingPark } from './park-pending.js';
3
3
  /** A main-session write after parking was armed is durable evidence of live
4
4
  * input even when the turn has since settled and the viewer detached. */
5
- export declare function mainSessionActivitySince(sessionFile: string | null | undefined, startedAt: number): boolean;
5
+ export declare function mainSessionActivitySince(sessionFile: string | null | undefined, startedAt: number): Promise<boolean>;
6
6
  /** One verdict shared by normal completion and grace expiry. A broker records
7
7
  * accepted live input against the process-local marker before it drives Pi, so
8
8
  * the verdict cannot race a viewer, live delivery, or durable wake. */
9
- export declare function shouldParkAfterSummary(nodeId: string, node: Pick<NodeMeta, 'lifecycle' | 'pi_session_file'>, pending: PendingPark): boolean;
9
+ export declare function shouldParkAfterSummary(nodeId: string, node: Pick<NodeMeta, 'lifecycle' | 'pi_session_file'>, pending: PendingPark): Promise<boolean>;
@@ -1 +1 @@
1
- var a=Object.defineProperty;var i=(r,t)=>a(r,"name",{value:t,configurable:!0});import{conversationIdFromPath as n,conversationStore as f,ConversationNotFoundError as u}from"../core/conversation-store/index.js";import{emitEvent as m}from"../core/events/emit.js";import{hasWakeMailSince as c}from"../core/canvas/deliveries.js";import{readLiveTurn as s}from"../core/canvas/recovery.js";import{parkEvent as l}from"./reconcilers/live-obligation.js";function v(r,t){if(r==null)return!1;const e=n(r);if(e===null)return!1;try{return f().header(e).mtime>=t}catch(o){return o instanceof u?!1:(m({level:"warn",event:"broker.park.session_activity_scan_failed",error:o}),!0)}}i(v,"mainSessionActivitySince");function d(r,t,e){return!e.activity&&s(r)?.busy!==!0&&!v(t.pi_session_file,e.startedAt)&&!c(r,e.startedAt)&&l(r,t.lifecycle)==="park"}i(d,"shouldParkAfterSummary");export{v as mainSessionActivitySince,d as shouldParkAfterSummary};
1
+ var n=Object.defineProperty;var e=(r,t)=>n(r,"name",{value:t,configurable:!0});import{conversationIdFromPath as o,conversationStore as f,ConversationNotFoundError as c}from"../core/conversation-store/index.js";import{emitEvent as s}from"../core/events/emit.js";import{hasWakeMailSince as u}from"../core/canvas/deliveries.js";import{readLiveTurn as m}from"../core/canvas/recovery.js";import{parkEvent as l}from"./reconcilers/live-obligation.js";async function v(r,t){if(r==null)return!1;const a=o(r);if(a===null)return!1;try{return(await f().header(a)).mtime>=t}catch(i){return i instanceof c?!1:(s({level:"warn",event:"broker.park.session_activity_scan_failed",error:i}),!0)}}e(v,"mainSessionActivitySince");async function _(r,t,a){return!a.activity&&(await m(r))?.busy!==!0&&!await v(t.pi_session_file,a.startedAt)&&!await u(r,a.startedAt)&&await l(r,t.lifecycle)==="park"}e(_,"shouldParkAfterSummary");export{v as mainSessionActivitySince,_ as shouldParkAfterSummary};
@@ -1 +1 @@
1
- var b=Object.defineProperty;var c=(e,n)=>b(e,"name",{value:n,configurable:!0});import{decodeEnvelope as m,EnvelopeError as v}from"../../core/peer/envelope.js";import{coverGrant as w}from"../../core/grants/cover.js";import{grantFor as g}from"../../core/grants/mirror.js";import{RunError as f}from"../../core/runs/operations.js";const r=c((e,n,o)=>({status:e,code:n,message:o}),"refuse"),l="the envelope does not match its token";function G(e){return async(n,o)=>{const t=c(()=>new f(403,"app_not_granted",`${n.sub} holds no active grant for ${o} on this machine`),"notGranted");if(n.grant===void 0){const i=g(n.sub,o);if(i===null)throw t();return i}try{return await w(n.grant,n.rev??1,o,n.sub,e)}catch(i){throw i instanceof f&&i.status===401?t():i}}}c(G,"mirrorGrantLink");async function L(e,n,o){const t=e.chain[0];if(t===void 0||!t.sub.startsWith("runtime:"))return r(401,"unauthorized","not a machine's token");if(t.sub===o.self())return r(401,"unauthorized","a machine does not call itself");if(e.scope!==void 0)return r(401,"unauthorized","a provider token does not authorize on a machine");const i=o.relation(e.sub);if(i===null)return r(403,"forbidden","no relation reaches this machine");let u;if(n!==void 0){try{u=m(n)}catch(a){return r(400,"invalid_request",a instanceof v?a.message:"invalid envelope")}if(u.act.sub!==t.sub||u.sub!==e.sub)return r(401,"unauthorized",l);if(u.act.act!==void 0&&u.act.act.place===null)return r(400,"invalid_request","the envelope names an app with no run place")}const s=u?.act.act,p=e.chain.slice(1).filter(a=>a.sub.startsWith("app:"));if(p.length>1)return r(401,"unauthorized","the token names more than one app");const d=p[0];if(d!==void 0&&(s===void 0||s.sub!==d.sub))return r(401,"unauthorized",l);const h=d??(s===void 0?void 0:{sub:s.sub});if(h!==void 0)try{await o.grantLink(h,e.sub)}catch(a){if(a instanceof f)return r(a.status,a.code,a.message);throw a}return u===void 0?{principal:{class:"machine",via:t.sub,sub:e.sub}}:s!==void 0?{principal:{class:"forwarded",via:t.sub,sub:e.sub,actor:{kind:"app",app:s.sub,node:s.node,node_scopes:s.node_scopes,place:s.place}}}:i!=="owner"?r(403,"forbidden","only the owner acts as the person"):{principal:{class:"forwarded",via:t.sub,sub:e.sub,actor:{kind:"person"}}}}c(L,"peerAuthority");export{G as mirrorGrantLink,L as peerAuthority};
1
+ var b=Object.defineProperty;var c=(e,n)=>b(e,"name",{value:n,configurable:!0});import{decodeEnvelope as m,EnvelopeError as v}from"../../core/peer/envelope.js";import{coverGrant as w}from"../../core/grants/cover.js";import{grantFor as g}from"../../core/grants/mirror.js";import{RunError as f}from"../../core/runs/operations.js";const r=c((e,n,o)=>({status:e,code:n,message:o}),"refuse"),l="the envelope does not match its token";function G(e){return async(n,o)=>{const t=c(()=>new f(403,"app_not_granted",`${n.sub} holds no active grant for ${o} on this machine`),"notGranted");if(n.grant===void 0){const i=await g(n.sub,o);if(i===null)throw t();return i}try{return await w(n.grant,n.rev??1,o,n.sub,e)}catch(i){throw i instanceof f&&i.status===401?t():i}}}c(G,"mirrorGrantLink");async function L(e,n,o){const t=e.chain[0];if(t===void 0||!t.sub.startsWith("runtime:"))return r(401,"unauthorized","not a machine's token");if(t.sub===o.self())return r(401,"unauthorized","a machine does not call itself");if(e.scope!==void 0)return r(401,"unauthorized","a provider token does not authorize on a machine");const i=o.relation(e.sub);if(i===null)return r(403,"forbidden","no relation reaches this machine");let u;if(n!==void 0){try{u=m(n)}catch(a){return r(400,"invalid_request",a instanceof v?a.message:"invalid envelope")}if(u.act.sub!==t.sub||u.sub!==e.sub)return r(401,"unauthorized",l);if(u.act.act!==void 0&&u.act.act.place===null)return r(400,"invalid_request","the envelope names an app with no run place")}const s=u?.act.act,p=e.chain.slice(1).filter(a=>a.sub.startsWith("app:"));if(p.length>1)return r(401,"unauthorized","the token names more than one app");const d=p[0];if(d!==void 0&&(s===void 0||s.sub!==d.sub))return r(401,"unauthorized",l);const h=d??(s===void 0?void 0:{sub:s.sub});if(h!==void 0)try{await o.grantLink(h,e.sub)}catch(a){if(a instanceof f)return r(a.status,a.code,a.message);throw a}return u===void 0?{principal:{class:"machine",via:t.sub,sub:e.sub}}:s!==void 0?{principal:{class:"forwarded",via:t.sub,sub:e.sub,actor:{kind:"app",app:s.sub,node:s.node,node_scopes:s.node_scopes,place:s.place}}}:i!=="owner"?r(403,"forbidden","only the owner acts as the person"):{principal:{class:"forwarded",via:t.sub,sub:e.sub,actor:{kind:"person"}}}}c(L,"peerAuthority");export{G as mirrorGrantLink,L as peerAuthority};
@@ -1,5 +1,5 @@
1
1
  import { ApiError } from '../../api/errors.js';
2
- import type { DatabaseSync } from 'node:sqlite';
2
+ import { type CanvasDb } from '../../core/canvas/db.js';
3
3
  import type { ObjectRow, Privacy } from '../../core/graph/types.js';
4
4
  import { type Envelope, type EnvelopeCaller } from '../../core/peer/envelope.js';
5
5
  import { type PeerRequest } from '../../core/peer/client.js';
@@ -14,7 +14,7 @@ export interface MachineLabel {
14
14
  export interface ForwardDeps extends Omit<HomeDeps, 'call'> {
15
15
  /** Without an envelope the call is the machine's own (`peer.locate`); with one it is made for the caller. */
16
16
  call(machine: string, request: PeerRequest, envelope?: Envelope, signal?: AbortSignal): ReturnType<typeof peerCall>;
17
- envelope(principal: EnvelopeCaller): Envelope;
17
+ envelope(principal: EnvelopeCaller): Promise<Envelope>;
18
18
  label(machine: string): Promise<MachineLabel>;
19
19
  }
20
20
  export declare const defaultForwardDeps: ForwardDeps;
@@ -54,11 +54,11 @@ export declare function envelopeOfForwarded(principal: Extract<RequestPrincipal,
54
54
  export declare function queryWithoutMachine(ctx: RequestContext): Record<string, string>;
55
55
  /** On the home machine: the stub of the node a forwarded app call is made for (created or refreshed from the verified envelope), or null
56
56
  * for a person actor, an unanchored app, or a local caller. */
57
- export declare function callerStub(db: DatabaseSync, ctx: RequestContext): ObjectRow | null;
57
+ export declare function callerStub(db: CanvasDb, ctx: RequestContext): Promise<ObjectRow | null>;
58
58
  /** On the calling machine: the node making a call, when the caller is a node (a broker), else null. */
59
- export declare function callerNode(db: DatabaseSync, ctx: RequestContext): ObjectRow | null;
59
+ export declare function callerNode(db: CanvasDb, ctx: RequestContext): Promise<ObjectRow | null>;
60
60
  /** On the calling machine: the stub of an object the home machine answered for. */
61
- export declare function remoteStub(db: DatabaseSync, id: string, type: string, machine: string, ref?: {
61
+ export declare function remoteStub(db: CanvasDb, id: string, type: string, machine: string, ref?: {
62
62
  kind?: string | null;
63
63
  name?: string;
64
64
  preview?: string;
@@ -69,4 +69,4 @@ export declare function remoteStub(db: DatabaseSync, id: string, type: string, m
69
69
  } | null;
70
70
  kind_decl?: KindDeclaration;
71
71
  privacy?: Privacy;
72
- }): ObjectRow;
72
+ }): Promise<ObjectRow>;
@@ -1 +1 @@
1
- var _=Object.defineProperty;var t=(e,n)=>_(e,"name",{value:n,configurable:!0});import{ApiError as p}from"../../api/errors.js";import{openDb as v}from"../../core/canvas/db.js";import{getById as x,nodeObject as $}from"../../core/graph/objects.js";import{envelopeFor as g}from"../../core/peer/envelope.js";import{isUnreachable as j}from"../../core/peer/client.js";import{machineReach as D}from"../../core/peer/directory.js";import{defaultHomeDeps as O,homeOf as S,relocate as q}from"../../core/peer/home.js";import{ensureStub as k,rehomeStub as A,stubOf as E}from"../../core/peer/stubs.js";import{peerCall as F}from"../../core/peer/client.js";const C={...O,call:t((e,n,o,a)=>F(e,n,{...o===void 0?{}:{envelope:o},...a===void 0?{}:{signal:a}}),"call"),envelope:t(e=>g(e),"envelope"),label:t(async e=>{try{const n=await D(e);return{id:e,name:n?.name??e}}catch{return{id:e,name:e}}},"label")},M={current:C},N=t(e=>e.class==="person"||e.class==="broker"||e.class==="cron","originates"),m=t(e=>{const n=e?.error;return typeof n=="object"&&n!==null&&typeof n.code=="string"?n.code:null},"errorCode");function L(e,n){const o=n?.error;return new p(e,o?.code??"error",o?.message??`the home machine answered ${e}`,o?.details)}t(L,"relayError");function P(e,n){return new p(503,"runtime_unreachable",`No machine of yours answers for ${e} (unreachable: ${n.join(", ")}).`,{id:e,unreachable:n})}t(P,"unknownError");const Q=t((e,n)=>e!==null&&typeof e=="object"&&!Array.isArray(e)?{...e,machine:n}:e,"withMachine");async function T(e,n,o){const a=M.current,r=v(),u=x(r,n),i=u===null?null:E(r,u),w=e.principal;if(!N(w)){if(i!==null)throw new p(404,"not_here",`${n} is not homed on this machine (it is a stub of ${i.home_machine})`,{id:n,home_machine:i.home_machine});return{kind:"local"}}if(u!==null&&i===null)return{kind:"local"};const b={...a,call:t((s,d)=>a.call(s,d),"call")};let l=await S(r,n,{hint:e.query.get("machine"),deps:b});for(let s=0;s<2;s++){if(l.where==="nowhere"||l.where==="here"){if(i!==null)throw new p(404,"not_found",`${n} is no longer on any machine of yours`,{id:n});return{kind:"local"}}if(l.where==="unknown")return{kind:"unknown",unreachable:l.unreachable};const d=l.machine,c=await a.call(d,o,a.envelope(w)),f=await a.label(d);if(j(c))return{kind:"unknown",unreachable:[`${f.name} (${c.unreachable.reason})`]};const y=l.source!=="locate";if(c.status===404&&s===0&&(m(c.body)==="not_here"||y&&m(c.body)==="not_found")){const h=await q(r,n,d,b);if(h.where==="machine"){l=h;continue}if(h.where==="unknown")return{kind:"unknown",unreachable:h.unreachable};if(m(c.body)==="not_found")return{kind:"remote",status:c.status,body:c.body,machine:f};if(i!==null)throw new p(404,"not_found",`${n} is no longer on any machine of yours`,{id:n});return{kind:"local"}}return{kind:"remote",status:c.status,body:c.body,machine:f}}return{kind:"unknown",unreachable:[]}}t(T,"forwardVerb");function W(e){if(e.actor.kind==="person")return{sub:e.sub,act:{sub:e.via}};const{app:n,node:o,node_scopes:a,place:r}=e.actor;return{sub:e.sub,act:{sub:e.via,act:{sub:n,node:o,node_scopes:a,place:r}}}}t(W,"envelopeOfForwarded");function X(e){const n={};for(const[o,a]of e.query)o!=="machine"&&(n[o]=a);return n}t(X,"queryWithoutMachine");function Y(e,n){const o=n.principal;return o.class!=="forwarded"||o.actor.kind!=="app"||o.actor.node===null?null:k(e,o.actor.node,"node",o.via,W(o))}t(Y,"callerStub");function Z(e,n){return n.principal.class==="broker"?$(e,n.principal.node):null}t(Z,"callerNode");function ee(e,n,o,a,r){A(e,n,a);const u=r?.owner,i=u&&u.type==="app"?{id:"",type:"app",scheme:"app",external_id:u.external_id??(u.handle.startsWith("app:")?u.handle:`app:${u.handle}`),handle:u.handle}:null;return k(e,n,o,a,void 0,r===void 0?void 0:{id:n,type:o,kind:r.kind??null,name:r.name??n,...r.preview===void 0?{}:{preview:r.preview},owner:i,...r.kind_decl===void 0?{}:{kind_decl:r.kind_decl},...r.privacy===void 0?{}:{privacy:r.privacy}})}t(ee,"remoteStub");export{Z as callerNode,Y as callerStub,C as defaultForwardDeps,W as envelopeOfForwarded,T as forwardVerb,M as forwarding,N as originates,X as queryWithoutMachine,L as relayError,ee as remoteStub,P as unknownError,Q as withMachine};
1
+ var _=Object.defineProperty;var t=(e,n)=>_(e,"name",{value:n,configurable:!0});import{ApiError as p}from"../../api/errors.js";import{openDb as v}from"../../core/canvas/db.js";import{getById as x,nodeObject as $}from"../../core/graph/objects.js";import{envelopeFor as g}from"../../core/peer/envelope.js";import{isUnreachable as j}from"../../core/peer/client.js";import{machineReach as D}from"../../core/peer/directory.js";import{defaultHomeDeps as O,homeOf as S,relocate as q}from"../../core/peer/home.js";import{ensureStub as y,rehomeStub as A,stubOf as E}from"../../core/peer/stubs.js";import{peerCall as F}from"../../core/peer/client.js";const C={...O,call:t((e,n,o,a)=>F(e,n,{...o===void 0?{}:{envelope:o},...a===void 0?{}:{signal:a}}),"call"),envelope:t(async e=>await g(e),"envelope"),label:t(async e=>{try{const n=await D(e);return{id:e,name:n?.name??e}}catch{return{id:e,name:e}}},"label")},M={current:C},N=t(e=>e.class==="person"||e.class==="broker"||e.class==="cron","originates"),m=t(e=>{const n=e?.error;return typeof n=="object"&&n!==null&&typeof n.code=="string"?n.code:null},"errorCode");function L(e,n){const o=n?.error;return new p(e,o?.code??"error",o?.message??`the home machine answered ${e}`,o?.details)}t(L,"relayError");function P(e,n){return new p(503,"runtime_unreachable",`No machine of yours answers for ${e} (unreachable: ${n.join(", ")}).`,{id:e,unreachable:n})}t(P,"unknownError");const Q=t((e,n)=>e!==null&&typeof e=="object"&&!Array.isArray(e)?{...e,machine:n}:e,"withMachine");async function T(e,n,o){const a=M.current,r=await v(),u=await x(r,n),i=u===null?null:await E(r,u),w=e.principal;if(!N(w)){if(i!==null)throw new p(404,"not_here",`${n} is not homed on this machine (it is a stub of ${i.home_machine})`,{id:n,home_machine:i.home_machine});return{kind:"local"}}if(u!==null&&i===null)return{kind:"local"};const b={...a,call:t((s,d)=>a.call(s,d),"call")};let l=await S(r,n,{hint:e.query.get("machine"),deps:b});for(let s=0;s<2;s++){if(l.where==="nowhere"||l.where==="here"){if(i!==null)throw new p(404,"not_found",`${n} is no longer on any machine of yours`,{id:n});return{kind:"local"}}if(l.where==="unknown")return{kind:"unknown",unreachable:l.unreachable};const d=l.machine,c=await a.call(d,o,await a.envelope(w)),f=await a.label(d);if(j(c))return{kind:"unknown",unreachable:[`${f.name} (${c.unreachable.reason})`]};const k=l.source!=="locate";if(c.status===404&&s===0&&(m(c.body)==="not_here"||k&&m(c.body)==="not_found")){const h=await q(r,n,d,b);if(h.where==="machine"){l=h;continue}if(h.where==="unknown")return{kind:"unknown",unreachable:h.unreachable};if(m(c.body)==="not_found")return{kind:"remote",status:c.status,body:c.body,machine:f};if(i!==null)throw new p(404,"not_found",`${n} is no longer on any machine of yours`,{id:n});return{kind:"local"}}return{kind:"remote",status:c.status,body:c.body,machine:f}}return{kind:"unknown",unreachable:[]}}t(T,"forwardVerb");function W(e){if(e.actor.kind==="person")return{sub:e.sub,act:{sub:e.via}};const{app:n,node:o,node_scopes:a,place:r}=e.actor;return{sub:e.sub,act:{sub:e.via,act:{sub:n,node:o,node_scopes:a,place:r}}}}t(W,"envelopeOfForwarded");function X(e){const n={};for(const[o,a]of e.query)o!=="machine"&&(n[o]=a);return n}t(X,"queryWithoutMachine");async function Y(e,n){const o=n.principal;return o.class!=="forwarded"||o.actor.kind!=="app"||o.actor.node===null?null:await y(e,o.actor.node,"node",o.via,W(o))}t(Y,"callerStub");async function Z(e,n){return n.principal.class==="broker"?await $(e,n.principal.node):null}t(Z,"callerNode");async function ee(e,n,o,a,r){await A(e,n,a);const u=r?.owner,i=u&&u.type==="app"?{id:"",type:"app",scheme:"app",external_id:u.external_id??(u.handle.startsWith("app:")?u.handle:`app:${u.handle}`),handle:u.handle}:null;return await y(e,n,o,a,void 0,r===void 0?void 0:{id:n,type:o,kind:r.kind??null,name:r.name??n,...r.preview===void 0?{}:{preview:r.preview},owner:i,...r.kind_decl===void 0?{}:{kind_decl:r.kind_decl},...r.privacy===void 0?{}:{privacy:r.privacy}})}t(ee,"remoteStub");export{Z as callerNode,Y as callerStub,C as defaultForwardDeps,W as envelopeOfForwarded,T as forwardVerb,M as forwarding,N as originates,X as queryWithoutMachine,L as relayError,ee as remoteStub,P as unknownError,Q as withMachine};
@@ -1 +1 @@
1
- var u=Object.defineProperty;var a=(e,t)=>u(e,"name",{value:t,configurable:!0});import{ApiError as c}from"../../api/errors.js";import{withCanvasWrite as l}from"../../core/canvas/db.js";import{getById as d}from"../../core/graph/objects.js";import{stubOf as v}from"../../core/peer/stubs.js";import{ackFor as y,claimFor as f,ingestPeerEvents as h,MAX_EVENTS_PER_CALL as p}from"../../core/peer/ingest.js";function m(e){if(e.principal.class!=="machine")throw new c(403,"permission_error","peer routes are for a machine");return e.principal.via}a(m,"via");const o=a(e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:{},"fields"),s=a(e=>typeof e=="string"&&e!=="","text");function w(e){const t=o(e),r=o(t.object);return s(t.key)&&s(t.message_id)&&s(t.event)&&typeof t.level=="number"&&s(r.id)&&s(r.type)&&typeof r.name=="string"&&(t.actor===null||s(o(t.actor).id)&&s(o(t.actor).type))&&o(t.attrs)===t.attrs}a(w,"validEvent");const b=a(e=>{const t=m(e),r=o(e.body).events;if(!Array.isArray(r))throw new c(400,"invalid_request","events must be an array");if(r.length>p)throw new c(400,"invalid_request",`at most ${p} events per call`);const n=r.findIndex(i=>!w(i));if(n>=0)throw new c(400,"invalid_request",`events[${n}] is not a well-formed event`);return{status:200,body:l(i=>h(i,t,r))}},"peerEvents"),_=a(e=>{const t=m(e),r=o(e.body).limit;return{status:200,body:{rows:l(i=>f(i,t,typeof r=="number"?r:50))}}},"peerClaim"),k=a(e=>{const t=m(e),r=o(e.body).acks;if(!Array.isArray(r)||r.some(n=>!s(o(n).key)||!s(o(n).claim_token)))throw new c(400,"invalid_request","acks must be an array of {key, claim_token}");return{status:200,body:{acked:l(n=>y(n,t,r))}}},"peerAck"),A=a(e=>{m(e);const t=o(e.body).id;if(!s(t))throw new c(400,"invalid_request","id must be a non-empty string");return l(r=>{const n=d(r,t);if(n===null)return{status:200,body:{answer:"no"}};const i=v(r,n);return{status:200,body:i===null?{answer:"here"}:{answer:"moved",machine:i.home_machine}}})},"peerLocate"),T=[{method:"POST",pattern:"/v1/peer/events",handler:b},{method:"POST",pattern:"/v1/peer/outbox/claim",handler:_},{method:"POST",pattern:"/v1/peer/outbox/ack",handler:k},{method:"POST",pattern:"/v1/peer/locate",handler:A}];export{k as peerAck,_ as peerClaim,b as peerEvents,A as peerLocate,T as peerRoutes};
1
+ var u=Object.defineProperty;var s=(e,t)=>u(e,"name",{value:t,configurable:!0});import{ApiError as c}from"../../api/errors.js";import{withCanvasWrite as l}from"../../core/canvas/db.js";import{getById as y}from"../../core/graph/objects.js";import{stubOf as d}from"../../core/peer/stubs.js";import{ackFor as w,claimFor as v,ingestPeerEvents as f,MAX_EVENTS_PER_CALL as p}from"../../core/peer/ingest.js";function m(e){if(e.principal.class!=="machine")throw new c(403,"permission_error","peer routes are for a machine");return e.principal.via}s(m,"via");const a=s(e=>e!==null&&typeof e=="object"&&!Array.isArray(e)?e:{},"fields"),o=s(e=>typeof e=="string"&&e!=="","text");function h(e){const t=a(e),r=a(t.object);return o(t.key)&&o(t.message_id)&&o(t.event)&&typeof t.level=="number"&&o(r.id)&&o(r.type)&&typeof r.name=="string"&&(t.actor===null||o(a(t.actor).id)&&o(a(t.actor).type))&&a(t.attrs)===t.attrs}s(h,"validEvent");const b=s(async e=>{const t=m(e),r=a(e.body).events;if(!Array.isArray(r))throw new c(400,"invalid_request","events must be an array");if(r.length>p)throw new c(400,"invalid_request",`at most ${p} events per call`);const n=r.findIndex(i=>!h(i));if(n>=0)throw new c(400,"invalid_request",`events[${n}] is not a well-formed event`);return{status:200,body:await l(async i=>await f(i,t,r))}},"peerEvents"),_=s(async e=>{const t=m(e),r=a(e.body).limit;return{status:200,body:{rows:await l(async i=>await v(i,t,typeof r=="number"?r:50))}}},"peerClaim"),k=s(async e=>{const t=m(e),r=a(e.body).acks;if(!Array.isArray(r)||r.some(n=>!o(a(n).key)||!o(a(n).claim_token)))throw new c(400,"invalid_request","acks must be an array of {key, claim_token}");return{status:200,body:{acked:await l(async n=>await w(n,t,r))}}},"peerAck"),A=s(async e=>{m(e);const t=a(e.body).id;if(!o(t))throw new c(400,"invalid_request","id must be a non-empty string");return await l(async r=>{const n=await y(r,t);if(n===null)return{status:200,body:{answer:"no"}};const i=await d(r,n);return{status:200,body:i===null?{answer:"here"}:{answer:"moved",machine:i.home_machine}}})},"peerLocate"),T=[{method:"POST",pattern:"/v1/peer/events",handler:b},{method:"POST",pattern:"/v1/peer/outbox/claim",handler:_},{method:"POST",pattern:"/v1/peer/outbox/ack",handler:k},{method:"POST",pattern:"/v1/peer/locate",handler:A}];export{k as peerAck,_ as peerClaim,b as peerEvents,A as peerLocate,T as peerRoutes};
@@ -8,9 +8,9 @@ export interface PeerIngressContext {
8
8
  /** Its key set (the app listener's cache, or the laptop's own). */
9
9
  jwks: JwksCache;
10
10
  /** The audience peer call tokens must carry: `machineUrl()` on the laptop, `runtime.audience` on the hosted runtime. Null before it is known: every request is refused 503. */
11
- audience(): string | null;
11
+ audience(): Promise<string | null>;
12
12
  /** The account owner (`user:<id>`) this runtime belongs to. Null when it has none: no relation reaches the machine and every request is refused 403. */
13
- owner(): string | null;
13
+ owner(): Promise<string | null>;
14
14
  /** This machine's id (`runtime:<id>`). */
15
15
  self(): string;
16
16
  /** Pulls the directory's grants when a token's app link is ahead of the mirror. Absent: a mirror behind a token's `rev` answers 503. */
@@ -18,13 +18,13 @@ export interface PeerIngressContext {
18
18
  /** The router that serves the request; defaults to the daemon's own (`buildRouter(() => null)`), built on first use. */
19
19
  router?: () => Router | Promise<Router>;
20
20
  /** False while the JWKS or grants are not loaded: every request is refused 503 (audited). Defaults to ready. */
21
- ready?: () => boolean;
21
+ ready?: () => Promise<boolean>;
22
22
  }
23
23
  /** Whether the daemon's own route table serves this request: the routes `servePeer` hands to its router (`peer.*` and every daemon route a forwarded call reaches). */
24
24
  export declare function isDaemonRoute(method: string, pathname: string): Promise<boolean>;
25
25
  /** The account owner this runtime belongs to: the owner a successful `crtr sys join` recorded (a laptop), else — on a hosted runtime, which is
26
26
  * provisioned without join — the one `sub` its mirrored grants all carry. Null when neither names exactly one owner. Never throws. */
27
- export declare function runtimeOwner(): string | null;
27
+ export declare function runtimeOwner(): Promise<string | null>;
28
28
  /** A bearer the caller already tried to verify and that failed: `servePeer` answers it as its own refusal (and audits it). */
29
29
  export interface PeerRefusal {
30
30
  status: number;
@@ -1 +1 @@
1
- var H=Object.defineProperty;var o=(e,t)=>H(e,"name",{value:t,configurable:!0});import{randomUUID as j}from"node:crypto";import{verifyCallToken as z}from"@north-light/identity";import{ENVELOPE_HEADER as I}from"../../core/peer/envelope.js";import{mirrorGrantLink as L,peerAuthority as U}from"./authority.js";import{peerVersionRefusal as q,PEER_VERSION_HEADER as D}from"../../core/peer/version.js";import{auditOutcome as v,writePeerAudit as G}from"../../core/audit.js";import{emitEvent as C}from"../../core/events/emit.js";import{joinedOwner as P}from"../../core/directory/join.js";import{allGrants as N}from"../../core/grants/mirror.js";import{errorCodes as T}from"../../api/error-codes.js";let O;function S(){return O??=import("../api/server.js").then(e=>e.buildRouter(()=>null)),O}o(S,"defaultRouter");async function x(e,t){return(await S()).match(e.toUpperCase(),t)!==null}o(x,"isDaemonRoute");function V(e,t,r,a,i,m){if(e.headersSent){e.destroy();return}const l=T[r];e.writeHead(t,{"content-type":"application/json; charset=utf-8","Request-Id":i,"X-Content-Type-Options":"nosniff"}),e.end(JSON.stringify({error:{code:r,message:a,origin:"runtime",...m===void 0?{}:{details:m},...l?{type:l.type}:{},request_id:i}}))}o(V,"refuse");const _=o((e,t)=>{const r=e.headers[t.toLowerCase()];return Array.isArray(r)?r[0]:r},"header");function ee(){try{const e=P();if(e!==null)return e;const t=new Set(N().map(r=>r.sub));return t.size===1?[...t][0]:null}catch{return null}}o(ee,"runtimeOwner");async function te(e,t,r,a){const i=t.getHeader("Request-Id")?.toString()??j();t.setHeader("Request-Id",i);const m=_(e,I),l=new URL(e.url??"/","http://peer.local"),E=(e.method??"GET").toUpperCase();let d={class:m===void 0?"machine":"forwarded",grantee:null,sub:null,via:"unauthenticated",operation:`${E} ${l.pathname}`,node_id:null},R=!1;const b=o((n,c={})=>{if(!R){R=!0;try{G({request_id:i,resource:l.pathname,...d,...c,outcome:n})}catch(u){C({level:"error",event:"daemon.peer.audit_failed",error:u instanceof Error?u:new Error(String(u)),fields:{request_id:i}})}}},"record"),s=o((n,c,u,f)=>{b(v(n)),V(t,n,c,u,i,f)},"deny");try{if(r.ready&&!r.ready()){s(503,"runtime_starting","runtime_starting");return}let n;if(a!==void 0&&!("chain"in a)){s(a.status,a.code,a.message);return}if(a!==void 0)n=a;else{const y=r.audience();if(y===null){s(503,"runtime_starting","this machine does not yet know its own address");return}const g=_(e,"authorization");if(!g?.startsWith("Bearer ")||g.length<=7){s(401,"unauthorized","a machine token is required");return}try{n=await z({token:g.slice(7),jwks:r.jwks,issuer:r.issuer,audience:y})}catch{s(401,"unauthorized","invalid machine token");return}}d={...d,grantee:n.sub,sub:n.sub,via:n.chain[0]?.sub??"unauthenticated"};const c=await(r.router??S)(),u=c.match(E,l.pathname);d={...d,operation:u?.operation.name??d.operation,node_id:u?.params.id??null};const f=r.owner(),p=await U(n,m,{self:r.self,relation:o(y=>f!==null&&y===f?"owner":null,"relation"),grantLink:L(r.syncGrants??(async()=>{}))});if("status"in p){s(p.status,p.code,p.message);return}const h=q(_(e,D));if(h!==null){s(426,h.code,h.message,h.details);return}const{principal:w}=p,k=w.class==="forwarded"&&w.actor.kind==="app"?w.actor:null,A={grantee:k?.app??n.sub,node_id:k?.node??d.node_id};t.once("close",()=>b(t.writableFinished?v(t.statusCode):"aborted",A)),await c.handle(e,t,null,w)}catch(n){C({level:"error",event:"daemon.peer.ingress_failed",error:n instanceof Error?n:new Error(String(n)),fields:{request_id:i}}),s(500,"server_failure","peer request failed")}}o(te,"servePeer");export{x as isDaemonRoute,ee as runtimeOwner,te as servePeer};
1
+ var H=Object.defineProperty;var a=(e,t)=>H(e,"name",{value:t,configurable:!0});import{randomUUID as j}from"node:crypto";import{verifyCallToken as z}from"@north-light/identity";import{ENVELOPE_HEADER as I}from"../../core/peer/envelope.js";import{mirrorGrantLink as L,peerAuthority as U}from"./authority.js";import{peerVersionRefusal as q,PEER_VERSION_HEADER as D}from"../../core/peer/version.js";import{auditOutcome as v,writePeerAudit as G}from"../../core/audit.js";import{emitEvent as C}from"../../core/events/emit.js";import{joinedOwner as P}from"../../core/directory/join.js";import{allGrants as N}from"../../core/grants/mirror.js";import{errorCodes as T}from"../../api/error-codes.js";let O;function S(){return O??=import("../api/server.js").then(e=>e.buildRouter(()=>null)),O}a(S,"defaultRouter");async function x(e,t){return(await S()).match(e.toUpperCase(),t)!==null}a(x,"isDaemonRoute");function V(e,t,r,o,i,m){if(e.headersSent){e.destroy();return}const l=T[r];e.writeHead(t,{"content-type":"application/json; charset=utf-8","Request-Id":i,"X-Content-Type-Options":"nosniff"}),e.end(JSON.stringify({error:{code:r,message:o,origin:"runtime",...m===void 0?{}:{details:m},...l?{type:l.type}:{},request_id:i}}))}a(V,"refuse");const _=a((e,t)=>{const r=e.headers[t.toLowerCase()];return Array.isArray(r)?r[0]:r},"header");async function ee(){try{const e=P();if(e!==null)return e;const t=new Set((await N()).map(r=>r.sub));return t.size===1?[...t][0]:null}catch{return null}}a(ee,"runtimeOwner");async function te(e,t,r,o){const i=t.getHeader("Request-Id")?.toString()??j();t.setHeader("Request-Id",i);const m=_(e,I),l=new URL(e.url??"/","http://peer.local"),E=(e.method??"GET").toUpperCase();let d={class:m===void 0?"machine":"forwarded",grantee:null,sub:null,via:"unauthenticated",operation:`${E} ${l.pathname}`,node_id:null},R=!1;const b=a(async(n,c={})=>{if(!R){R=!0;try{await G({request_id:i,resource:l.pathname,...d,...c,outcome:n})}catch(u){C({level:"error",event:"daemon.peer.audit_failed",error:u instanceof Error?u:new Error(String(u)),fields:{request_id:i}})}}},"record"),s=a(async(n,c,u,f)=>{await b(v(n)),V(t,n,c,u,i,f)},"deny");try{if(r.ready&&!await r.ready()){await s(503,"runtime_starting","runtime_starting");return}let n;if(o!==void 0&&!("chain"in o)){await s(o.status,o.code,o.message);return}if(o!==void 0)n=o;else{const y=await r.audience();if(y===null){await s(503,"runtime_starting","this machine does not yet know its own address");return}const g=_(e,"authorization");if(!g?.startsWith("Bearer ")||g.length<=7){await s(401,"unauthorized","a machine token is required");return}try{n=await z({token:g.slice(7),jwks:r.jwks,issuer:r.issuer,audience:y})}catch{await s(401,"unauthorized","invalid machine token");return}}d={...d,grantee:n.sub,sub:n.sub,via:n.chain[0]?.sub??"unauthenticated"};const c=await(r.router??S)(),u=c.match(E,l.pathname);d={...d,operation:u?.operation.name??d.operation,node_id:u?.params.id??null};const f=await r.owner(),p=await U(n,m,{self:r.self,relation:a(y=>f!==null&&y===f?"owner":null,"relation"),grantLink:L(r.syncGrants??(async()=>{}))});if("status"in p){await s(p.status,p.code,p.message);return}const w=q(_(e,D));if(w!==null){await s(426,w.code,w.message,w.details);return}const{principal:h}=p,k=h.class==="forwarded"&&h.actor.kind==="app"?h.actor:null,A={grantee:k?.app??n.sub,node_id:k?.node??d.node_id};t.once("close",()=>{b(t.writableFinished?v(t.statusCode):"aborted",A)}),await c.handle(e,t,null,h)}catch(n){C({level:"error",event:"daemon.peer.ingress_failed",error:n instanceof Error?n:new Error(String(n)),fields:{request_id:i}}),await s(500,"server_failure","peer request failed")}}a(te,"servePeer");export{x as isDaemonRoute,ee as runtimeOwner,te as servePeer};
@@ -1,4 +1,4 @@
1
- import type { DatabaseSync } from 'node:sqlite';
1
+ import { type CanvasDb } from '../../core/canvas/db.js';
2
2
  import { type PeerRequest, type PeerResult } from '../../core/peer/client.js';
3
3
  import { type Machine } from '../../core/peer/directory.js';
4
4
  export declare const STABLE_BACKOFF_MS: {
@@ -9,7 +9,7 @@ export declare const STABLE_BACKOFF_MS: {
9
9
  export declare const RELAY_RETRY_WINDOW_MS: number;
10
10
  export declare const PULL_INTERVAL_MS: number;
11
11
  export interface OutboxDeps {
12
- db(): DatabaseSync;
12
+ db(): Promise<CanvasDb>;
13
13
  call(machineId: string, request: PeerRequest): Promise<PeerResult>;
14
14
  reach(machineId: string): Promise<Machine | null>;
15
15
  machines(): Promise<Machine[]>;
@@ -1 +1 @@
1
- var C=Object.defineProperty;var l=(n,f)=>C(n,"name",{value:f,configurable:!0});import{openDb as I,withCanvasWrite as j}from"../../core/canvas/db.js";import{emitEvent as B}from"../../core/events/emit.js";import{isUnreachable as O,peerCall as D}from"../../core/peer/client.js";import{listMachines as U,machineReach as F,normalizeMachineId as g,ownMachineId as N}from"../../core/peer/directory.js";import{relayConnected as W}from"../../core/peer/events.js";import{ingestPeerEvents as q,isCatalogLag as S}from"../../core/peer/ingest.js";import{CATALOG_LAG_RETRY_MS as G,dueRows as X,expireOld as Y,markDone as z,markExpired as E,markRetry as A,markWaiting as L,onPeerEnqueued as H,pendingFor as J,pruneOutbox as K,OUTBOX_MAX_AGE_MS as V}from"../../core/peer/outbox-store.js";const T={first:1e3,max:10*6e4},P=5*6e4,$=5*6e4,R=50,Q=20,Z={db:I,call:l((n,f)=>D(n,f),"call"),reach:F,machines:U,self:N,now:Date.now},M=l(n=>Math.min(T.first*2**Math.max(0,n-1),T.max),"stableBackoffMs");function ee(n){const f=new Set;async function p(c,o,i){const t=n.db(),a=n.now(),s=await n.call(c,{method:"POST",path:"/v1/peer/events",body:{events:o.map(e=>JSON.parse(e.payload_json))}}),d=l((e,x=o)=>{for(const m of x){const u=m.attempts+1,w=m.first_failed_at??a;i&&e?L(t,m.id,u):i?a-w>=P?L(t,m.id,u):A(t,m.id,u,a+Math.min(M(u),P-(a-w)),w):a-w>=V?E(t,m.id):A(t,m.id,u,a+M(u),w)}},"fail");if(O(s)){d(s.unreachable.reason==="machine_offline");return}const r=s.body;if(s.status!==200||r===null||!Array.isArray(r.accepted)){d(!1);return}const _=new Set(r.accepted),k=new Map((Array.isArray(r.rejected)?r.rejected:[]).map(e=>[e.key,e.code??""])),y=[];for(const e of o)_.has(e.idempotency_key)?z(t,e.id):k.has(e.idempotency_key)?S(k.get(e.idempotency_key))&&a-e.created_at<G?y.push(e):E(t,e.id):A(t,e.id,e.attempts+1,a+M(e.attempts+1),e.first_failed_at??a);d(!1,y)}l(p,"sendBatch");async function b(c){const o=c.filter(i=>!f.has(i.id));for(const i of o)f.add(i.id);try{const i=new Map;for(const t of o)i.set(t.peer,[...i.get(t.peer)??[],t]);await Promise.all([...i].map(async([t,a])=>{const d=(await n.reach(t).catch(()=>null))?.reach.kind==="relay";for(let r=0;r<a.length;r+=R)await p(t,a.slice(r,r+R),d)}))}finally{for(const i of o)f.delete(i.id)}}l(b,"pushRows");let h=0;return{async run(){const c=n.db(),o=n.now();o-h>=60*6e4&&(h=o,Y(c,o),K(c,o)),await b(X(c,o))},flush:l(c=>b(J(n.db(),c,n.now())),"flush"),async pull(){const c=n.self(),o=(await n.machines()).filter(t=>g(t.machine_id)!==c&&t.kind!=="device"&&t.reach.kind==="stable");let i=0;for(const t of o){const a=g(t.machine_id);for(let s=0;s<Q;s++){const d=await n.call(a,{method:"POST",path:"/v1/peer/outbox/claim",body:{limit:100}}),r=!O(d)&&d.status===200?d.body?.rows:void 0;if(!Array.isArray(r)||r.length===0)break;const _=j(e=>q(e,a,r.map(x=>x.payload)));i+=_.accepted.length;const k=new Set([..._.accepted,..._.rejected.filter(e=>!S(e.code)).map(e=>e.key)]),y=r.filter(e=>k.has(e.key)).map(e=>({key:e.key,claim_token:e.claim_token}));if(y.length>0&&await n.call(a,{method:"POST",path:"/v1/peer/outbox/ack",body:{acks:y}}),r.length<100)break}}return i}}}l(ee,"createOutboxLane");function le(n){if(!n.joined)return()=>{};const f=n.deps??Z,p=ee(f),b=l(a=>s=>{B({level:"warn",event:`daemon.peer.${a}_failed`,error:s})},"quiet"),h=l((a,s)=>n.register(a().then(()=>{},b(s))),"guarded"),v=H(a=>h(()=>p.flush(a),"outbox_flush")),c=setInterval(()=>h(()=>p.run(),"outbox_run"),n.tickMs??5e3);c.unref();const o=l(()=>h(async()=>{(await f.machines()).find(s=>g(s.machine_id)===f.self())?.reach.kind==="relay"&&await p.pull()},"outbox_pull"),"pull"),i=W.on(o),t=setInterval(o,$);return t.unref(),o(),()=>{v(),i(),clearInterval(c),clearInterval(t)}}l(le,"startPeerOutbox");export{$ as PULL_INTERVAL_MS,P as RELAY_RETRY_WINDOW_MS,T as STABLE_BACKOFF_MS,ee as createOutboxLane,Z as liveOutboxDeps,M as stableBackoffMs,le as startPeerOutbox};
1
+ var C=Object.defineProperty;var l=(a,f)=>C(a,"name",{value:f,configurable:!0});import{openDb as I,withCanvasWrite as j}from"../../core/canvas/db.js";import{emitEvent as B}from"../../core/events/emit.js";import{isUnreachable as O,peerCall as D}from"../../core/peer/client.js";import{listMachines as U,machineReach as F,normalizeMachineId as g,ownMachineId as N}from"../../core/peer/directory.js";import{relayConnected as W}from"../../core/peer/events.js";import{ingestPeerEvents as q,isCatalogLag as S}from"../../core/peer/ingest.js";import{CATALOG_LAG_RETRY_MS as G,dueRows as X,expireOld as Y,markDone as z,markExpired as E,markRetry as A,markWaiting as L,onPeerEnqueued as H,pendingFor as J,pruneOutbox as K,OUTBOX_MAX_AGE_MS as V}from"../../core/peer/outbox-store.js";const T={first:1e3,max:10*6e4},P=5*6e4,$=5*6e4,R=50,Q=20,Z={db:I,call:l((a,f)=>D(a,f),"call"),reach:F,machines:U,self:N,now:Date.now},M=l(a=>Math.min(T.first*2**Math.max(0,a-1),T.max),"stableBackoffMs");function ee(a){const f=new Set;async function u(c,o,i){const t=await a.db(),n=a.now(),s=await a.call(c,{method:"POST",path:"/v1/peer/events",body:{events:o.map(e=>JSON.parse(e.payload_json))}}),d=l(async(e,x=o)=>{for(const m of x){const h=m.attempts+1,_=m.first_failed_at??n;i&&e?await L(t,m.id,h):i?n-_>=P?await L(t,m.id,h):await A(t,m.id,h,n+Math.min(M(h),P-(n-_)),_):n-_>=V?await E(t,m.id):await A(t,m.id,h,n+M(h),_)}},"fail");if(O(s)){await d(s.unreachable.reason==="machine_offline");return}const r=s.body;if(s.status!==200||r===null||!Array.isArray(r.accepted)){await d(!1);return}const p=new Set(r.accepted),k=new Map((Array.isArray(r.rejected)?r.rejected:[]).map(e=>[e.key,e.code??""])),y=[];for(const e of o)p.has(e.idempotency_key)?await z(t,e.id):k.has(e.idempotency_key)?S(k.get(e.idempotency_key))&&n-e.created_at<G?y.push(e):await E(t,e.id):await A(t,e.id,e.attempts+1,n+M(e.attempts+1),e.first_failed_at??n);await d(!1,y)}l(u,"sendBatch");async function b(c){const o=c.filter(i=>!f.has(i.id));for(const i of o)f.add(i.id);try{const i=new Map;for(const t of o)i.set(t.peer,[...i.get(t.peer)??[],t]);await Promise.all([...i].map(async([t,n])=>{const d=(await a.reach(t).catch(()=>null))?.reach.kind==="relay";for(let r=0;r<n.length;r+=R)await u(t,n.slice(r,r+R),d)}))}finally{for(const i of o)f.delete(i.id)}}l(b,"pushRows");let w=0;return{async run(){const c=await a.db(),o=a.now();o-w>=60*6e4&&(w=o,await Y(c,o),await K(c,o)),await b(await X(c,o))},flush:l(async c=>b(await J(await a.db(),c,a.now())),"flush"),async pull(){const c=a.self(),o=(await a.machines()).filter(t=>g(t.machine_id)!==c&&t.kind!=="device"&&t.reach.kind==="stable");let i=0;for(const t of o){const n=g(t.machine_id);for(let s=0;s<Q;s++){const d=await a.call(n,{method:"POST",path:"/v1/peer/outbox/claim",body:{limit:100}}),r=!O(d)&&d.status===200?d.body?.rows:void 0;if(!Array.isArray(r)||r.length===0)break;const p=await j(async e=>await q(e,n,r.map(x=>x.payload)));i+=p.accepted.length;const k=new Set([...p.accepted,...p.rejected.filter(e=>!S(e.code)).map(e=>e.key)]),y=r.filter(e=>k.has(e.key)).map(e=>({key:e.key,claim_token:e.claim_token}));if(y.length>0&&await a.call(n,{method:"POST",path:"/v1/peer/outbox/ack",body:{acks:y}}),r.length<100)break}}return i}}}l(ee,"createOutboxLane");function le(a){if(!a.joined)return()=>{};const f=a.deps??Z,u=ee(f),b=l(n=>s=>{B({level:"warn",event:`daemon.peer.${n}_failed`,error:s})},"quiet"),w=l((n,s)=>a.register(n().then(()=>{},b(s))),"guarded"),v=H(n=>w(()=>u.flush(n),"outbox_flush")),c=setInterval(()=>w(()=>u.run(),"outbox_run"),a.tickMs??5e3);c.unref();const o=l(()=>w(async()=>{(await f.machines()).find(s=>g(s.machine_id)===f.self())?.reach.kind==="relay"&&await u.pull()},"outbox_pull"),"pull"),i=W.on(o),t=setInterval(o,$);return t.unref(),o(),()=>{v(),i(),clearInterval(c),clearInterval(t)}}l(le,"startPeerOutbox");export{$ as PULL_INTERVAL_MS,P as RELAY_RETRY_WINDOW_MS,T as STABLE_BACKOFF_MS,ee as createOutboxLane,Z as liveOutboxDeps,M as stableBackoffMs,le as startPeerOutbox};
@@ -1 +1 @@
1
- var U=Object.defineProperty;var o=(e,i)=>U(e,"name",{value:i,configurable:!0});import{JwksCache as E}from"@north-light/identity";import{randomUUID as N}from"node:crypto";import{readConfig as k}from"../../core/config.js";import{hasSyncedGrants as O}from"../../core/grants/mirror.js";import{emitEvent as _}from"../../core/events/emit.js";import{directoryIssuer as b,machineUrl as j,ownMachineId as R}from"../../core/peer/directory.js";import{RunError as l}from"../../core/runs/operations.js";import{createResumeDetector as G}from"../resume-detector.js";import{applySyncNotice as H,NoticeLedger as M}from"../api/sync-notice.js";import{runtimeOwner as J,servePeer as T}from"./ingress.js";import{startLocalIngress as D}from"./local-ingress.js";import{startRelayClient as L}from"./relay-client.js";const $="/v1/runtime/sync-notice",z=5e3;async function A(e,i,f){if(e.headersSent){e.destroy();return}e.writeHead(i,{"content-type":"application/json; charset=utf-8"}),e.end(JSON.stringify(f))}o(A,"answerJson");function oe(e){const i=e.unsandboxed??(()=>k("user").runtime?.unsandboxed===!0),f=e.issuer??b;let s;const S=new M;async function m(){const t=s;s=void 0,t!==void 0&&(clearInterval(t.resume),await t.client.stop(),await t.ingress.close())}o(m,"stopStarted");async function C(t,r){const c=new E(r,fetch,e.jwksUrl?e.jwksUrl():k("user").runtime?.jwksUrl),d={issuer:r,jwks:c,audience:j,owner:J,self:R,ready:o(()=>O(r.replace(/\/$/,"")),"ready"),syncGrants:e.syncGrants,...e.ingress},w=await D(o(async(a,u)=>{const x=(a.url??"").split("?",1)[0];if(a.method==="POST"&&x===$){a.resume();try{const n=d.audience();if(n===null||d.ready?.()===!1)throw new l(503,"runtime_starting","runtime_starting");await H(await S.accept(a.headers.authorization,c,r,n),e.syncGrants,N()),u.writeHead(204),u.end()}catch(n){const I=n instanceof l?n.status:500;await A(u,I,{error:{code:n instanceof l?n.code:"server_failure",message:n instanceof l?n.message:"sync notice failed"}})}return}await T(a,u,d)},"serve"),e.socketPath);let y;try{y=L({issuer:r,relayOrigin:t,socketPath:w.socketPath,...e.client})}catch(a){throw await w.close(),a}const P=G(),v=setInterval(()=>{P.check()&&(_({level:"info",event:"daemon.peer.relay_resume"}),y.reconnectNow())},e.resumeCheckMs??z);v.unref(),s={relay:t,ingress:w,client:y,resume:v,jwks:c},_({level:"info",event:"daemon.peer.relay_started",fields:{relay:t}})}o(C,"begin");let h=Promise.resolve(),p=!1;const g=o(t=>{const r=h.then(t);return h=r.catch(()=>{}),r},"serial");return{observe(t){return g(async()=>{if(p)return;const r=f();if(t===null)return;if(t.reach?.kind!=="relay"||!i()||r===null){await m();return}const c=t.reach.relay.replace(/\/$/,"");s?.relay!==c&&(await m(),await C(c,r))})},running:o(()=>s!==void 0,"running"),stop(){return p=!0,g(m)}}}o(oe,"createPeerRelay");export{z as RESUME_CHECK_MS,$ as SYNC_NOTICE_PATH,oe as createPeerRelay};
1
+ var U=Object.defineProperty;var a=(e,c)=>U(e,"name",{value:c,configurable:!0});import{JwksCache as E}from"@north-light/identity";import{randomUUID as N}from"node:crypto";import{readConfig as k}from"../../core/config.js";import{hasSyncedGrants as O}from"../../core/grants/mirror.js";import{emitEvent as _}from"../../core/events/emit.js";import{directoryIssuer as b,machineUrl as j,ownMachineId as R}from"../../core/peer/directory.js";import{RunError as m}from"../../core/runs/operations.js";import{createResumeDetector as G}from"../resume-detector.js";import{applySyncNotice as H,NoticeLedger as M}from"../api/sync-notice.js";import{runtimeOwner as J,servePeer as T}from"./ingress.js";import{startLocalIngress as D}from"./local-ingress.js";import{startRelayClient as L}from"./relay-client.js";const $="/v1/runtime/sync-notice",z=5e3;async function A(e,c,f){if(e.headersSent){e.destroy();return}e.writeHead(c,{"content-type":"application/json; charset=utf-8"}),e.end(JSON.stringify(f))}a(A,"answerJson");function ae(e){const c=e.unsandboxed??(()=>k("user").runtime?.unsandboxed===!0),f=e.issuer??b;let s;const S=new M;async function d(){const t=s;s=void 0,t!==void 0&&(clearInterval(t.resume),await t.client.stop(),await t.ingress.close())}a(d,"stopStarted");async function C(t,r){const i=new E(r,fetch,e.jwksUrl?e.jwksUrl():k("user").runtime?.jwksUrl),u={issuer:r,jwks:i,audience:j,owner:J,self:R,ready:a(async()=>await O(r.replace(/\/$/,"")),"ready"),syncGrants:e.syncGrants,...e.ingress},w=await D(a(async(o,l)=>{const x=(o.url??"").split("?",1)[0];if(o.method==="POST"&&x===$){o.resume();try{const n=await u.audience();if(n===null||u.ready&&!await u.ready())throw new m(503,"runtime_starting","runtime_starting");await H(await S.accept(o.headers.authorization,i,r,n),e.syncGrants,N()),l.writeHead(204),l.end()}catch(n){const I=n instanceof m?n.status:500;await A(l,I,{error:{code:n instanceof m?n.code:"server_failure",message:n instanceof m?n.message:"sync notice failed"}})}return}await T(o,l,u)},"serve"),e.socketPath);let y;try{y=L({issuer:r,relayOrigin:t,socketPath:w.socketPath,...e.client})}catch(o){throw await w.close(),o}const P=G(),v=setInterval(()=>{P.check()&&(_({level:"info",event:"daemon.peer.relay_resume"}),y.reconnectNow())},e.resumeCheckMs??z);v.unref(),s={relay:t,ingress:w,client:y,resume:v,jwks:i},_({level:"info",event:"daemon.peer.relay_started",fields:{relay:t}})}a(C,"begin");let h=Promise.resolve(),p=!1;const g=a(t=>{const r=h.then(t);return h=r.catch(()=>{}),r},"serial");return{observe(t){return g(async()=>{if(p)return;const r=f();if(t===null)return;if(t.reach?.kind!=="relay"||!c()||r===null){await d();return}const i=t.reach.relay.replace(/\/$/,"");s?.relay!==i&&(await d(),await C(i,r))})},running:a(()=>s!==void 0,"running"),stop(){return p=!0,g(d)}}}a(ae,"createPeerRelay");export{z as RESUME_CHECK_MS,$ as SYNC_NOTICE_PATH,ae as createPeerRelay};
@@ -1,6 +1,6 @@
1
- import type { DatabaseSync } from 'node:sqlite';
2
1
  import type { ObjectRow } from '../../core/graph/types.js';
3
2
  import type { RequestPrincipal } from '../api/router.js';
3
+ import type { CanvasDb } from '../../core/canvas/db.js';
4
4
  export declare const READ_LEAF_DEADLINE_MS = 15000;
5
5
  export interface ReadDelegation {
6
6
  plugin: string;
@@ -15,6 +15,6 @@ export type ReadLeafResult = {
15
15
  };
16
16
  /** The delegation for a custom object, or null when its kind has no read leaf or no installed plugin declares it any more (`declared=0`: an inert
17
17
  * kind shows the last announcement). Sync: runs inside the first read transaction. */
18
- export declare function readDelegationFor(db: DatabaseSync, object: ObjectRow): ReadDelegation | null;
18
+ export declare function readDelegationFor(db: CanvasDb, object: ObjectRow): Promise<ReadDelegation | null>;
19
19
  /** Run the declared read leaf as `principal`. Never throws. */
20
20
  export declare function runReadLeaf(d: ReadDelegation, principal: RequestPrincipal, deadlineMs?: number): Promise<ReadLeafResult>;
@@ -1,2 +1,2 @@
1
- var f=Object.defineProperty;var l=(n,o)=>f(n,"name",{value:o,configurable:!0});import{randomUUID as g}from"node:crypto";import{prepared as h}from"../../core/sqlite-statements.js";import{listInstalledPlugins as v}from"../../core/resolver.js";import{validatePluginCommands as b}from"../../core/command-plugins/discovery.js";import{executeExternalLeafAsync as E}from"../../core/command-plugins/transport/exec-invoke-async.js";import{invokeHttpLeaf as k}from"../../core/command-plugins/transport/http-invoke.js";import{sha256Hex as x,signedHeaderDigest as _}from"../../core/command-plugins/transport/sign.js";import{pluginAppEnv as w}from"../../core/plugin-app.js";import{callProvider as y}from"../../core/providers/call.js";import{callerFromRequest as L}from"../api/handlers/providers.js";import{signCallHeaders as P}from"../api/handlers/plugin-app-token.js";const j=15e3;function C(n,o){const a=h(n,`SELECT k.read_json, k.declared, i.scheme, i.external_id FROM object_kinds k
2
- LEFT JOIN identities i ON i.object = k.owner WHERE k.name = ?`).get(o.type);if(a===void 0||a.read_json===null||a.declared===0||a.scheme!=="app"||a.external_id===null||!a.external_id.startsWith("app:"))return null;const e=JSON.parse(a.read_json).command;return{plugin:a.external_id.slice(4),command:e,id:o.id,name:o.name}}l(C,"readDelegationFor");async function J(n,o,a=j){try{const e=v("user").find(r=>r.name===n.plugin);if(e===void 0||!e.enabled)return{unavailable:`plugin ${n.plugin} is not installed`};const u={id:n.id,name:n.name};let d;if(e.manifest.provider?.id===e.name){const r=AbortSignal.timeout(a),t=y(L(o),{provider:e.name,tool:n.command.join(" "),arguments:u},{requestId:g(),signal:r});t.catch(()=>{}),d=(await Promise.race([t,new Promise((p,i)=>{r.addEventListener("abort",()=>i(new Error(`provider read leaf gave no answer within ${a} ms`)),{once:!0})})])).body}else{const r=b(e),t=r.transport;let i=r.manifest?.roots.find(m=>m.name===e.name);for(const m of n.command)i=i?.kind==="branch"?i.children.find(s=>s?.name===m):void 0;if(i?.kind!=="leaf"||t?.kind!=="exec"&&t?.kind!=="http")return{unavailable:`plugin ${n.plugin} has no read leaf ${n.command.join(" ")}`};if(t.kind==="http"){const m=i;d=await k({registration:{name:e.name,endpoint:t.endpoint,...t.authEnv!==void 0?{authEnv:t.authEnv}:{}},...r.manifest?.baseUrl!==void 0?{baseUrl:r.manifest.baseUrl}:{},timeouts:{...r.manifest?.timeouts,requestMs:a},params:m.params,rest:m.rest,output:m.output,commandPath:[e.name,...n.command]},u,void 0,{callHeaders:l(async s=>P(e.name,o,{method:s.method,url:s.url.href,body_sha256:x(s.body),..._(s.headers)}).headers,"callHeaders")})}else{if(t.executable===void 0)return{unavailable:`plugin ${n.plugin} has no read leaf ${n.command.join(" ")}`};d=await E({plugin:e,executable:t.executable,commandPath:[e.name,...n.command],output:i.output},u,{deadlineMs:a,cwd:e.root,env:{...process.env,...w(e.name)??{}}})}}const c=d?.markdown;return typeof c=="string"?{markdown:c}:{unavailable:"read leaf returned no markdown"}}catch(e){return{unavailable:e instanceof Error?e.message:String(e)}}}l(J,"runReadLeaf");export{j as READ_LEAF_DEADLINE_MS,C as readDelegationFor,J as runReadLeaf};
1
+ var f=Object.defineProperty;var l=(n,o)=>f(n,"name",{value:o,configurable:!0});import{randomUUID as g}from"node:crypto";import{listInstalledPlugins as h}from"../../core/resolver.js";import{validatePluginCommands as v}from"../../core/command-plugins/discovery.js";import{executeExternalLeafAsync as b}from"../../core/command-plugins/transport/exec-invoke-async.js";import{invokeHttpLeaf as E}from"../../core/command-plugins/transport/http-invoke.js";import{sha256Hex as w,signedHeaderDigest as k}from"../../core/command-plugins/transport/sign.js";import{pluginAppEnv as x}from"../../core/plugin-app.js";import{callProvider as _}from"../../core/providers/call.js";import{callerFromRequest as y}from"../api/handlers/providers.js";import{signCallHeaders as L}from"../api/handlers/plugin-app-token.js";const P=15e3;async function O(n,o){const a=await n.prepare(`SELECT k.read_json, k.declared, i.scheme, i.external_id FROM object_kinds k
2
+ LEFT JOIN identities i ON i.object = k.owner WHERE k.name = ?`).get(o.type);if(a===void 0||a.read_json===null||a.declared===0||a.scheme!=="app"||a.external_id===null||!a.external_id.startsWith("app:"))return null;const e=JSON.parse(a.read_json).command;return{plugin:a.external_id.slice(4),command:e,id:o.id,name:o.name}}l(O,"readDelegationFor");async function q(n,o,a=P){try{const e=h("user").find(r=>r.name===n.plugin);if(e===void 0||!e.enabled)return{unavailable:`plugin ${n.plugin} is not installed`};const u={id:n.id,name:n.name};let d;if(e.manifest.provider?.id===e.name){const r=AbortSignal.timeout(a),t=_(await y(o),{provider:e.name,tool:n.command.join(" "),arguments:u},{requestId:g(),signal:r});t.catch(()=>{}),d=(await Promise.race([t,new Promise((p,i)=>{r.addEventListener("abort",()=>i(new Error(`provider read leaf gave no answer within ${a} ms`)),{once:!0})})])).body}else{const r=v(e),t=r.transport;let i=r.manifest?.roots.find(m=>m.name===e.name);for(const m of n.command)i=i?.kind==="branch"?i.children.find(s=>s?.name===m):void 0;if(i?.kind!=="leaf"||t?.kind!=="exec"&&t?.kind!=="http")return{unavailable:`plugin ${n.plugin} has no read leaf ${n.command.join(" ")}`};if(t.kind==="http"){const m=i;d=await E({registration:{name:e.name,endpoint:t.endpoint,...t.authEnv!==void 0?{authEnv:t.authEnv}:{}},...r.manifest?.baseUrl!==void 0?{baseUrl:r.manifest.baseUrl}:{},timeouts:{...r.manifest?.timeouts,requestMs:a},params:m.params,rest:m.rest,output:m.output,commandPath:[e.name,...n.command]},u,void 0,{callHeaders:l(async s=>(await L(e.name,o,{method:s.method,url:s.url.href,body_sha256:w(s.body),...k(s.headers)})).headers,"callHeaders")})}else{if(t.executable===void 0)return{unavailable:`plugin ${n.plugin} has no read leaf ${n.command.join(" ")}`};d=await b({plugin:e,executable:t.executable,commandPath:[e.name,...n.command],output:i.output},u,{deadlineMs:a,cwd:e.root,env:{...process.env,...x(e.name)??{}}})}}const c=d?.markdown;return typeof c=="string"?{markdown:c}:{unavailable:"read leaf returned no markdown"}}catch(e){return{unavailable:e instanceof Error?e.message:String(e)}}}l(q,"runReadLeaf");export{P as READ_LEAF_DEADLINE_MS,O as readDelegationFor,q as runReadLeaf};