@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 +1 @@
1
- var p=Object.defineProperty;var o=(r,e)=>p(r,"name",{value:e,configurable:!0});import{envHomeOverride as m}from"../../shared/env.js";import{loadProfileManifest as h,lookupProfile as v}from"../../core/profiles/manifest.js";import{readProfileEnvVars as g}from"../../core/profiles/env-store.js";import{readAppEnvVars as R}from"../../core/profiles/app-env-store.js";import{ADMITTED_HOST_PATH_ENV as f,buildOperationalEnvBase as w}from"../../core/runtime/spawn-env.js";import{getNode as c}from"../../core/canvas/canvas.js";import{contextDir as y}from"../../core/canvas/paths.js";import{appendRunEvent as O}from"../../core/runs/events.js";import{payerOfGrant as b}from"../../core/grants/mirror.js";import{scopeAllowed as E}from"../../core/scopes.js";import{cronPrincipalOf as C}from"./authority.js";function _(r){if(r.profile==null)return null;let e;try{e=v(r.profile)}catch{return null}if(e.kind==="resolved")return e.entry.profileId;if(e.kind==="absent")return null;throw new l(`the armed profile "${r.profile}" is still on this host but its manifest could not be read (${e.manifestPath}) \u2014 running as root would silently give this cron a different identity, env store, and purview. Repair the manifest, or re-arm the cron under a profile that resolves.`)}o(_,"resolveLiveProfile");function M(r){return{...C(r),cron_id:r.cron_id,origin_run_id:r.origin_run_id,isolated:r.isolated,creator:r.created_by}}o(M,"cronBirthPrincipalOf");function $(r,e){const n=r.creator===null?null:c(r.creator);return n!==null&&r.origin_run_id!==null&&n.run_id===r.origin_run_id&&c(r.origin_run_id)?.deleting_at==null&&n.grantee===r.grantee&&(n.sub??"user:local")===r.sub&&(n.grant_id??null)===r.grant_id&&(r.scopes===null?n.scopes==null:r.scopes.every(t=>E(n.scopes,t)))?{parent:n.node_id,...r.scopes===null?{}:{scopes:[...r.scopes]}}:{root:!0,rootLifecycle:"terminal",...r.scopes===null?{}:{scopes:[...r.scopes]},run:{grantee:r.grantee,sub:r.sub,grant_id:r.grant_id,client_id:null,metadata_json:JSON.stringify({cron_id:r.cron_id}),run_id:e,event_cursor:1,usage_json:JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0})},withinCreate:o((t,s)=>{O(t,e,e,"run.started",{scopes:s.scopes??null,payer:b(r.grant_id),usage:JSON.parse(s.usage_json)})},"withinCreate")}}o($,"cronBirthPlacement");function B(r){try{return _(r)}catch{return null}}o(B,"resolveLiveProfileOrRoot");function V(r){if(r.profile!=null)try{return h(r.profile).manifest.name}catch{return}}o(V,"resolveLiveProfileName");class l extends Error{static{o(this,"ArmedContextError")}constructor(e){super(e),this.name="ArmedContextError"}}function N(r){if(r==null)return{};let e;try{e=JSON.parse(r)}catch(i){throw new l(`the armed env snapshot is not valid JSON (${i.message}) \u2014 this cron's stored env_json is corrupt, so the run would silently drop every armed variable. Re-arm the cron with a valid --env.`)}if(typeof e!="object"||e===null||Array.isArray(e))throw new l("the armed env snapshot is not a JSON object \u2014 this cron's stored env_json is corrupt. Re-arm the cron with a valid --env.");const n={};for(const[i,t]of Object.entries(e)){if(typeof t!="string")throw new l(`the armed env snapshot's value for "${i}" is not a string \u2014 this cron's stored env_json is corrupt, so the run would silently drop that variable. Re-arm the cron with a valid --env.`);n[i]=t}return n}o(N,"parseArmedEnv");function F(r,e){const n=N(r.env_json),i=r.grantee==="app:terminal",t=i?_(r):null,s=w({targetCwd:r.cwd,targetProfileId:t,skipSpawnAllow:!i}),a={...s,...R(r.grantee),...i?g(t):{},...n,...t!==null?{CRTR_PROFILE_ID:t}:{},CRTR_CRON_ID:r.cron_id,CRTR_CRON_NAME:r.name,CRTR_RUN_ID:e},u=m();if(u!==void 0&&u!==""&&(a.CRTR_HOME=u),r.anchor_node!=null){a.CRTR_ANCHOR=r.anchor_node;const d=c(r.anchor_node);d!==null&&(a.CRTR_CONTEXT_DIR=y(d.node_id,d.grantee))}return a[f]=s[f],{profileId:t,env:a}}o(F,"buildArmedRunContext");export{l as ArmedContextError,F as buildArmedRunContext,$ as cronBirthPlacement,M as cronBirthPrincipalOf,_ as resolveLiveProfile,V as resolveLiveProfileName,B as resolveLiveProfileOrRoot};
1
+ var p=Object.defineProperty;var o=(r,e)=>p(r,"name",{value:e,configurable:!0});import{envHomeOverride as m}from"../../shared/env.js";import{loadProfileManifest as h,lookupProfile as v}from"../../core/profiles/manifest.js";import{readProfileEnvVars as g}from"../../core/profiles/env-store.js";import{readAppEnvVars as R}from"../../core/profiles/app-env-store.js";import{ADMITTED_HOST_PATH_ENV as f,buildOperationalEnvBase as w}from"../../core/runtime/spawn-env.js";import{getNode as c}from"../../core/canvas/canvas.js";import{contextDir as y}from"../../core/canvas/paths.js";import{appendRunEvent as O}from"../../core/runs/events.js";import{payerOfGrant as b}from"../../core/grants/mirror.js";import{scopeAllowed as E}from"../../core/scopes.js";import{cronPrincipalOf as C}from"./authority.js";function _(r){if(r.profile==null)return null;let e;try{e=v(r.profile)}catch{return null}if(e.kind==="resolved")return e.entry.profileId;if(e.kind==="absent")return null;throw new l(`the armed profile "${r.profile}" is still on this host but its manifest could not be read (${e.manifestPath}) \u2014 running as root would silently give this cron a different identity, env store, and purview. Repair the manifest, or re-arm the cron under a profile that resolves.`)}o(_,"resolveLiveProfile");function M(r){return{...C(r),cron_id:r.cron_id,origin_run_id:r.origin_run_id,isolated:r.isolated,creator:r.created_by}}o(M,"cronBirthPrincipalOf");async function $(r,e){const n=r.creator===null?null:await c(r.creator);return n!==null&&r.origin_run_id!==null&&n.run_id===r.origin_run_id&&(await c(r.origin_run_id))?.deleting_at==null&&n.grantee===r.grantee&&(n.sub??"user:local")===r.sub&&(n.grant_id??null)===r.grant_id&&(r.scopes===null?n.scopes==null:r.scopes.every(t=>E(n.scopes,t)))?{parent:n.node_id,...r.scopes===null?{}:{scopes:[...r.scopes]}}:{root:!0,rootLifecycle:"terminal",...r.scopes===null?{}:{scopes:[...r.scopes]},run:{grantee:r.grantee,sub:r.sub,grant_id:r.grant_id,client_id:null,metadata_json:JSON.stringify({cron_id:r.cron_id}),run_id:e,event_cursor:1,usage_json:JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0})},withinCreate:o(async(t,a)=>{await O(t,e,e,"run.started",{scopes:a.scopes??null,payer:await b(r.grant_id),usage:JSON.parse(a.usage_json)})},"withinCreate")}}o($,"cronBirthPlacement");function B(r){try{return _(r)}catch{return null}}o(B,"resolveLiveProfileOrRoot");function V(r){if(r.profile!=null)try{return h(r.profile).manifest.name}catch{return}}o(V,"resolveLiveProfileName");class l extends Error{static{o(this,"ArmedContextError")}constructor(e){super(e),this.name="ArmedContextError"}}function N(r){if(r==null)return{};let e;try{e=JSON.parse(r)}catch(i){throw new l(`the armed env snapshot is not valid JSON (${i.message}) \u2014 this cron's stored env_json is corrupt, so the run would silently drop every armed variable. Re-arm the cron with a valid --env.`)}if(typeof e!="object"||e===null||Array.isArray(e))throw new l("the armed env snapshot is not a JSON object \u2014 this cron's stored env_json is corrupt. Re-arm the cron with a valid --env.");const n={};for(const[i,t]of Object.entries(e)){if(typeof t!="string")throw new l(`the armed env snapshot's value for "${i}" is not a string \u2014 this cron's stored env_json is corrupt, so the run would silently drop that variable. Re-arm the cron with a valid --env.`);n[i]=t}return n}o(N,"parseArmedEnv");async function F(r,e){const n=N(r.env_json),i=r.grantee==="app:terminal",t=i?_(r):null,a=w({targetCwd:r.cwd,targetProfileId:t,skipSpawnAllow:!i}),s={...a,...R(r.grantee),...i?g(t):{},...n,...t!==null?{CRTR_PROFILE_ID:t}:{},CRTR_CRON_ID:r.cron_id,CRTR_CRON_NAME:r.name,CRTR_RUN_ID:e},u=m();if(u!==void 0&&u!==""&&(s.CRTR_HOME=u),r.anchor_node!=null){s.CRTR_ANCHOR=r.anchor_node;const d=await c(r.anchor_node);d!==null&&(s.CRTR_CONTEXT_DIR=y(d.node_id,d.grantee))}return s[f]=a[f],{profileId:t,env:s}}o(F,"buildArmedRunContext");export{l as ArmedContextError,F as buildArmedRunContext,$ as cronBirthPlacement,M as cronBirthPrincipalOf,_ as resolveLiveProfile,V as resolveLiveProfileName,B as resolveLiveProfileOrRoot};
@@ -21,7 +21,7 @@ export type CronAuthority =
21
21
  * grantee and sub; every stored scope must still be covered by it; `crtr:schedule` must be
22
22
  * in the effective set. A null `grant_id` passes only for `app:terminal` on a runtime with
23
23
  * no issuer. */
24
- export declare function checkCronFire(p: CronPrincipal): CronAuthority;
24
+ export declare function checkCronFire(p: CronPrincipal): Promise<CronAuthority>;
25
25
  /** May this principal start a node? The fire check plus `crtr:act`. */
26
- export declare function checkCronBirth(p: CronPrincipal): CronAuthority;
26
+ export declare function checkCronBirth(p: CronPrincipal): Promise<CronAuthority>;
27
27
  export declare function cronPrincipalOf(c: Cron): CronPrincipal;
@@ -1 +1 @@
1
- var c=Object.defineProperty;var i=(r,e)=>c(r,"name",{value:e,configurable:!0});import{covers as u}from"@north-light/identity";import{activeRecord as g,grantRecord as d}from"../../core/grants/mirror.js";import{readConfig as l}from"../../core/config.js";import{isUnsandboxedMachine as f}from"../../core/runtime/unsandboxed.js";import{SCOPE_VOCABULARY as m,isOwnMemoryScope as _,scopeAllowed as s}from"../../core/scopes.js";function t(r,e){return{allowed:!1,reason:r,message:e}}i(t,"refuse");function h(r){if(r.grantee!=="app:terminal"&&f())return t("unsandboxed_machine",`This computer runs only your own terminal agents; ${r.grantee} runs on your hosted machine.`);let e;if(r.grant_id===null){if(r.grantee!=="app:terminal"||l("user").runtime?.issuer)return t("grant_missing",`cron has no grant for ${r.grantee}; re-arm it from a node of that app`);e=m}else{const n=d(r.grant_id);if(n===null)return t("grant_missing",`grant ${r.grant_id} is not in this runtime's grant mirror`);if(n.status!=="active")return t("grant_revoked",`grant ${r.grant_id} is ${n.status}`);if(n.expires_at!==null&&Date.parse(n.expires_at)<=Date.now())return t("grant_revoked",`grant ${r.grant_id} expired at ${n.expires_at}`);if(n.grantee!==r.grantee||n.sub!==r.sub)return t("grant_revoked",`grant ${r.grant_id} no longer belongs to ${r.grantee} for ${r.sub}`);const o=g(n);if(o===null)return t("grant_revoked",`grant ${r.grant_id} cannot be read`);e=o.resolved}if(r.scopes!==null){const n=r.scopes.find(o=>!_(o,r.grantee)&&!e.some(a=>u(a,o)));if(n!==void 0)return t("scope_narrowed",`scope ${n} is no longer covered by the grant`)}return!s(e,"crtr:schedule")||!s(r.scopes,"crtr:schedule")?t("scope_missing","the cron no longer holds crtr:schedule"):{allowed:!0,effectiveScopes:e}}i(h,"checkCronFire");function k(r){const e=h(r);return e.allowed&&(!s(e.effectiveScopes,"crtr:act")||!s(r.scopes,"crtr:act"))?t("scope_missing","the cron no longer holds crtr:act"):e}i(k,"checkCronBirth");function y(r){return{grantee:r.grantee,sub:r.sub,grant_id:r.grant_id,scopes:r.scopes}}i(y,"cronPrincipalOf");export{k as checkCronBirth,h as checkCronFire,y as cronPrincipalOf};
1
+ var c=Object.defineProperty;var a=(r,e)=>c(r,"name",{value:e,configurable:!0});import{covers as u}from"@north-light/identity";import{activeRecord as g,grantRecord as d}from"../../core/grants/mirror.js";import{readConfig as l}from"../../core/config.js";import{isUnsandboxedMachine as f}from"../../core/runtime/unsandboxed.js";import{SCOPE_VOCABULARY as m,isOwnMemoryScope as _,scopeAllowed as i}from"../../core/scopes.js";function t(r,e){return{allowed:!1,reason:r,message:e}}a(t,"refuse");async function h(r){if(r.grantee!=="app:terminal"&&f())return t("unsandboxed_machine",`This computer runs only your own terminal agents; ${r.grantee} runs on your hosted machine.`);let e;if(r.grant_id===null){if(r.grantee!=="app:terminal"||l("user").runtime?.issuer)return t("grant_missing",`cron has no grant for ${r.grantee}; re-arm it from a node of that app`);e=m}else{const n=await d(r.grant_id);if(n===null)return t("grant_missing",`grant ${r.grant_id} is not in this runtime's grant mirror`);if(n.status!=="active")return t("grant_revoked",`grant ${r.grant_id} is ${n.status}`);if(n.expires_at!==null&&Date.parse(n.expires_at)<=Date.now())return t("grant_revoked",`grant ${r.grant_id} expired at ${n.expires_at}`);if(n.grantee!==r.grantee||n.sub!==r.sub)return t("grant_revoked",`grant ${r.grant_id} no longer belongs to ${r.grantee} for ${r.sub}`);const o=g(n);if(o===null)return t("grant_revoked",`grant ${r.grant_id} cannot be read`);e=o.resolved}if(r.scopes!==null){const n=r.scopes.find(o=>!_(o,r.grantee)&&!e.some(s=>u(s,o)));if(n!==void 0)return t("scope_narrowed",`scope ${n} is no longer covered by the grant`)}return!i(e,"crtr:schedule")||!i(r.scopes,"crtr:schedule")?t("scope_missing","the cron no longer holds crtr:schedule"):{allowed:!0,effectiveScopes:e}}a(h,"checkCronFire");async function y(r){const e=await h(r);return e.allowed&&(!i(e.effectiveScopes,"crtr:act")||!i(r.scopes,"crtr:act"))?t("scope_missing","the cron no longer holds crtr:act"):e}a(y,"checkCronBirth");function k(r){return{grantee:r.grantee,sub:r.sub,grant_id:r.grant_id,scopes:r.scopes}}a(k,"cronPrincipalOf");export{y as checkCronBirth,h as checkCronFire,k as cronPrincipalOf};
@@ -1 +1 @@
1
- var c=Object.defineProperty;var u=(n,e)=>c(n,"name",{value:e,configurable:!0});import{getCron as i,setCronLastOutputHash as v}from"../../core/canvas/crons.js";import{escalateFailure as l,failureSummary as h}from"./escalation.js";import{resolveCronSink as g}from"./sinks.js";async function S(n,e,t,a=!1){const r=await m(n,e,t,a);if(!r.refused&&!t&&n.on_output==="on-change"){const s=i(n.cron_id);s!==null&&s.on_output==="on-change"&&v(n.cron_id,e.stdoutSha256)}return r}u(S,"disposeSettledRun");async function m(n,e,t,a=!1){const r=t?"out-of-band: ":"",s=i(n.cron_id);if(s===null&&!a)return{delivered:`${r}cron canceled mid-run \u2014 nothing delivered`,paused:!1};const d=s??n,p=e.timedOut||e.processErrorMessage!==null||e.exitCode!==0;let o=!0;if(d.on_output==="on-change"&&(o=d.last_output_hash!==e.stdoutSha256),p)return d.on_output==="silent"?{delivered:`${r}silent`,paused:!1}:t?{delivered:`out-of-band: ${h(e,null)} \u2014 not escalated`,paused:!1}:{delivered:await l(d,e,null),paused:!0};switch(d.on_output){case"silent":return{delivered:`${r}silent`,paused:!1};case"on-failure":return{delivered:`${r}ok \u2014 nothing to deliver (on-failure)`,paused:!1};case"on-change":return o?f(d,e,t,r):{delivered:`${r}unchanged \u2014 not delivered (on-change)`,paused:!1};case"always":return f(d,e,t,r)}}u(m,"disposeRun");async function f(n,e,t,a){if(e.stdoutHead.trim()==="")return{delivered:`${a}empty stdout \u2014 nothing delivered`,paused:!1};try{const r=g(n,e.runId,e.stdoutHead);return r.kind==="none"?{delivered:`${a}${r.delivered}`,paused:!1,...r.refused===!0?{refused:!0}:{}}:{delivered:"",paused:!1,obligation:r}}catch(r){const s=`delivery failed: ${r.message}`;return t?{delivered:`out-of-band: ${s} \u2014 not escalated`,paused:!1}:{delivered:await l(n,e,s),paused:!0}}}u(f,"resolveOrEscalate");export{S as disposeSettledRun};
1
+ var c=Object.defineProperty;var i=(n,e)=>c(n,"name",{value:e,configurable:!0});import{getCron as o,setCronLastOutputHash as v}from"../../core/canvas/crons.js";import{escalateFailure as l,failureSummary as h}from"./escalation.js";import{resolveCronSink as g}from"./sinks.js";async function S(n,e,t,d=!1){const r=await m(n,e,t,d);if(!r.refused&&!t&&n.on_output==="on-change"){const a=await o(n.cron_id);a!==null&&a.on_output==="on-change"&&await v(n.cron_id,e.stdoutSha256)}return r}i(S,"disposeSettledRun");async function m(n,e,t,d=!1){const r=t?"out-of-band: ":"",a=await o(n.cron_id);if(a===null&&!d)return{delivered:`${r}cron canceled mid-run \u2014 nothing delivered`,paused:!1};const s=a??n,p=e.timedOut||e.processErrorMessage!==null||e.exitCode!==0;let u=!0;if(s.on_output==="on-change"&&(u=s.last_output_hash!==e.stdoutSha256),p)return s.on_output==="silent"?{delivered:`${r}silent`,paused:!1}:t?{delivered:`out-of-band: ${h(e,null)} \u2014 not escalated`,paused:!1}:{delivered:await l(s,e,null),paused:!0};switch(s.on_output){case"silent":return{delivered:`${r}silent`,paused:!1};case"on-failure":return{delivered:`${r}ok \u2014 nothing to deliver (on-failure)`,paused:!1};case"on-change":return u?f(s,e,t,r):{delivered:`${r}unchanged \u2014 not delivered (on-change)`,paused:!1};case"always":return f(s,e,t,r)}}i(m,"disposeRun");async function f(n,e,t,d){if(e.stdoutHead.trim()==="")return{delivered:`${d}empty stdout \u2014 nothing delivered`,paused:!1};try{const r=await g(n,e.runId,e.stdoutHead);return r.kind==="none"?{delivered:`${d}${r.delivered}`,paused:!1,...r.refused===!0?{refused:!0}:{}}:{delivered:"",paused:!1,obligation:r}}catch(r){const a=`delivery failed: ${r.message}`;return t?{delivered:`out-of-band: ${a} \u2014 not escalated`,paused:!1}:{delivered:await l(n,e,a),paused:!0}}}i(f,"resolveOrEscalate");export{S as disposeSettledRun};
@@ -11,4 +11,4 @@ export type CronEnd = {
11
11
  * that can still take mail: gone, deleting, or finalized with no wake ahead. */
12
12
  export declare function endCron(c: Cron, end: CronEnd | null, options?: {
13
13
  preserveRunningProcess?: boolean;
14
- }): boolean;
14
+ }): Promise<boolean>;
@@ -1,2 +1,2 @@
1
- var p=Object.defineProperty;var r=(e,n)=>p(e,"name",{value:n,configurable:!0});import{getNode as c}from"../../core/canvas/canvas.js";import{withCanvasWrite as f}from"../../core/canvas/db.js";import{CRON_RUN_RING as h,cancelCron as m,listCronRuns as y,parseCronSink as g}from"../../core/canvas/crons.js";import{hasNoNaturalCycle as $}from"../../core/runtime/revive-all.js";import{isParked as _}from"../../core/runtime/lifecycle.js";import{enqueueNodeMail as x}from"../../core/feed/messages.js";import{cadenceDisplay as v}from"../../core/wake.js";const k=/^delivered: /,b=r(e=>e.exit_code===0&&(e.stdout_head??"")==="","EMPTY_OK");function w(e){return e.filter(n=>n.exit_code!==null||!(n.delivered??"").startsWith("skipped"))}r(w,"realRuns");function N(e,n,s){const t=w(s),i=s.length>=h,d=t.find(u=>k.test(u.delivered??"")),a=n.kind==="expired"?`expired at ${e.expires_at} and was deleted${e.held?" while held by exit 75; the pending occurrence never fired":""}`:`was canceled by ${n.by} and deleted`,l=[`Cron "${e.name}" (${e.cron_id}, ${e.recur!=null?v(e.recur):"one-shot"}) ${a}. It was delivering to you, so nothing will wake you from it any more.`,"",`- runs made: ${i?`at least ${t.length} (the run log keeps the last ${h} entries)`:t.length}`,d!==void 0?`- last delivery to you: ${d.finished}`:`- last delivery to you: ${i?`none in its last ${t.length} runs`:"never delivered"}`],o=t[0];if(o!==void 0){const u=o.exit_code===null?"no exit observed":o.exit_code===-1?"timed out":`exit ${o.exit_code}`;l.push(`- last run: ${o.finished} \u2014 ${u} \u2014 ${o.delivered??""}`)}return t.length>0&&t.every(b)&&l.push("","Every recorded run exited 0 with empty stdout, so the check may have been failing without saying so. A pipeline exits with its last stage, so `probe 2>&1 | grep \u2026 | jq \u2026` hides a failed probe unless the command starts with `set -o pipefail`."),{label:`\u23F0 cron ${e.name} ${n.kind==="expired"?"expired":"canceled"}`,body:l.join(`
2
- `)}}r(N,"endedMessage");function C(e){return e.deleting_at!=null||e.run_id!=null&&c(e.run_id)?.deleting_at!=null}r(C,"runIsDeleting");function K(e,n,s){const t=g(e.sink),i=t?.kind==="node"?c(t.node):null,d=n!==null&&i!==null&&!C(i)&&(!$(i)||_(i));return f(()=>{const a=d?y(e.cron_id):[];if(!m(e.cron_id,s))return!1;if(d){const{label:l,body:o}=N(e,n,a);x(i.node_id,{kind:"message",label:l,senderNodeId:null,bodyJson:{body:o},urgency:"normal",wake:1,idempotencyKey:`cron-ended:${e.cron_id}`})}return!0})}r(K,"endCron");export{K as endCron};
1
+ var p=Object.defineProperty;var r=(e,n)=>p(e,"name",{value:n,configurable:!0});import{getNode as c}from"../../core/canvas/canvas.js";import{withCanvasWrite as f}from"../../core/canvas/db.js";import{CRON_RUN_RING as h,cancelCron as m,listCronRuns as y,parseCronSink as g}from"../../core/canvas/crons.js";import{hasNoNaturalCycle as $}from"../../core/runtime/revive-all.js";import{isParked as w}from"../../core/runtime/lifecycle.js";import{enqueueNodeMail as _}from"../../core/feed/messages.js";import{cadenceDisplay as x}from"../../core/wake.js";const v=/^delivered: /,k=r(e=>e.exit_code===0&&(e.stdout_head??"")==="","EMPTY_OK");function b(e){return e.filter(n=>n.exit_code!==null||!(n.delivered??"").startsWith("skipped"))}r(b,"realRuns");function N(e,n,l){const t=b(l),i=l.length>=h,d=t.find(u=>v.test(u.delivered??"")),a=n.kind==="expired"?`expired at ${e.expires_at} and was deleted${e.held?" while held by exit 75; the pending occurrence never fired":""}`:`was canceled by ${n.by} and deleted`,s=[`Cron "${e.name}" (${e.cron_id}, ${e.recur!=null?x(e.recur):"one-shot"}) ${a}. It was delivering to you, so nothing will wake you from it any more.`,"",`- runs made: ${i?`at least ${t.length} (the run log keeps the last ${h} entries)`:t.length}`,d!==void 0?`- last delivery to you: ${d.finished}`:`- last delivery to you: ${i?`none in its last ${t.length} runs`:"never delivered"}`],o=t[0];if(o!==void 0){const u=o.exit_code===null?"no exit observed":o.exit_code===-1?"timed out":`exit ${o.exit_code}`;s.push(`- last run: ${o.finished} \u2014 ${u} \u2014 ${o.delivered??""}`)}return t.length>0&&t.every(k)&&s.push("","Every recorded run exited 0 with empty stdout, so the check may have been failing without saying so. A pipeline exits with its last stage, so `probe 2>&1 | grep \u2026 | jq \u2026` hides a failed probe unless the command starts with `set -o pipefail`."),{label:`\u23F0 cron ${e.name} ${n.kind==="expired"?"expired":"canceled"}`,body:s.join(`
2
+ `)}}r(N,"endedMessage");async function C(e){return e.deleting_at!=null||e.run_id!=null&&(await c(e.run_id))?.deleting_at!=null}r(C,"runIsDeleting");async function K(e,n,l){const t=g(e.sink),i=t?.kind==="node"?await c(t.node):null,d=n!==null&&i!==null&&!await C(i)&&(!$(i)||w(i));return await f(async()=>{const a=d?await y(e.cron_id):[];if(!await m(e.cron_id,l))return!1;if(d){const{label:s,body:o}=N(e,n,a);await _(i.node_id,{kind:"message",label:s,senderNodeId:null,bodyJson:{body:o},urgency:"normal",wake:1,idempotencyKey:`cron-ended:${e.cron_id}`})}return!0})}r(K,"endCron");export{K as endCron};
@@ -1,3 +1,3 @@
1
- var m=Object.defineProperty;var a=(e,r)=>m(e,"name",{value:r,configurable:!0});import{getNode as f}from"../../core/canvas/canvas.js";import{nodeAgentDir as h}from"../../core/canvas/node-agent-paths.js";import{newNodeId as p}from"../../core/runtime/nodes.js";import{fullName as $}from"../../core/canvas/labels.js";import{listCronRuns as _,setCronState as w}from"../../core/canvas/crons.js";import{emitEvent as l}from"../../core/events/emit.js";import{spawnChild as y}from"../../core/runtime/spawn.js";import{cronWakeOrigin as g}from"../../core/runtime/bearings.js";import{cadenceDisplay as b}from"../../core/wake.js";import{cronBirthPlacement as v,cronBirthPrincipalOf as O,resolveLiveProfileOrRoot as k}from"./armed-context.js";import{checkCronBirth as S}from"./authority.js";function T(e,r){return r!==null?r:e.timedOut?`run timed out after ${e.runTimeoutS}s (killed; recorded exit -1)`:e.processErrorMessage!==null?`run process error: ${e.processErrorMessage}`:`command exited ${e.exitCode??"(no exit observed)"}`}a(T,"failureSummary");function x(e,r,s){const t=e.created_by!=null?f(e.created_by):null,o=e.created_by==null?"created by: (no creating node recorded)":t!==null?`created by: node ${e.created_by} ("${$(t)}") \u2014 still on the canvas; consider telling it what happened`:`created by: node ${e.created_by} (now gone)`,i=e.recur!=null?`every ${b(e.recur)}`:`one-shot at ${e.fire_at}`,d=_(e.cron_id).slice(0,10).map(n=>{const c=n.exit_code===null?"no exit":`exit ${n.exit_code}`,u=(n.stderr_head??n.stdout_head??"").split(`
2
- `)[0]?.slice(0,120)??"";return`- ${n.started} \u2014 ${c}, ${n.duration_ms}ms \u2014 ${n.delivered??""}${u!==""?` \u2014 ${u}`:""}`});return["A scheduled cron FAILED and has paused itself. You were spawned to deal with it.","",`- cron: "${e.name}" (${e.cron_id})`,`- schedule: ${i}${e.tz!=null?` (tz ${e.tz})`:""}`,`- context: cwd ${e.cwd}${e.profile!=null?`, profile ${e.profile}`:""}`,`- ${o}`,`- this failure: ${T(r,s)}`,"","## The command","","```bash",e.command,"```","","## This run","",`- exit: ${r.timedOut?"-1 (timeout)":String(r.exitCode)}`,`- stdout (head): ${r.stdoutHead===""?"(empty)":""}`,...r.stdoutHead!==""?["```",r.stdoutHead,"```"]:[],`- stderr (head): ${r.stderrHead===""?"(empty)":""}`,...r.stderrHead!==""?["```",r.stderrHead,"```"]:[],"","## Recent runs (most recent first, this failure not yet recorded)","",...d.length>0?d:["(no prior runs recorded)"],"","## Your mandate","","Diagnose why it failed and decide what to do:",`- Transient or fixable: fix the environment/command context, verify with \`crtr cron run ${e.cron_id}\` (fires now, out of band, shows you the result), then \`crtr cron resume ${e.cron_id}\` to re-arm it.`,`- Obsolete: \`crtr cron cancel ${e.cron_id}\`.`,"- The user's call (or the fix needs a change you cannot make): `crtr human send`.","","The cron stays paused until someone resumes it \u2014 nothing refires while you work."].join(`
3
- `)}a(x,"buildEscalationKickoff");async function j(e,r,s){w(e.cron_id,"paused");try{const t=O(e),o=S(t);if(!o.allowed)return l({level:"warn",event:"cron.birth.refused",fields:{cron_id:e.cron_id,grant_id:e.grant_id,reason:o.reason,stage:"escalation"}}),`failure: cron paused; no escalation node (refused: ${o.reason})`;const i=p(),d=v(t,i),n=await y({nodeId:i,kind:"general",isolated:e.isolated,cwd:e.isolated?h(i,e.grantee):e.cwd,prompt:x(e,r,s),...d,readiness:"launch",profile:k(e),wakeOrigin:g(e,"node_birth")});return l({level:"info",event:"cron.failure.escalated",fields:{cron_id:e.cron_id,name:e.name,escalation_node:n.node.node_id}}),`failure: cron paused, escalation node ${n.node.node_id} spawned`}catch(t){return l({level:"error",event:"cron.escalation.spawn_failed",error:t,fields:{cron_id:e.cron_id,name:e.name}}),`failure: cron paused; escalation spawn failed: ${t.message}`}}a(j,"escalateFailure");function M(e){return[`${e}.`,"This is a ONE-SHOT, so it has been PAUSED rather than released: its side effects may have completed in full,","and re-firing would enact them a second time. Determine whether the work actually landed, then either","`crtr cron run` it to redo it deliberately, or `crtr cron cancel` it."].join(" ")}a(M,"crashedOneShotSummary");export{M as crashedOneShotSummary,j as escalateFailure,T as failureSummary};
1
+ var m=Object.defineProperty;var i=(e,r)=>m(e,"name",{value:r,configurable:!0});import{getNode as f}from"../../core/canvas/canvas.js";import{nodeAgentDir as h}from"../../core/canvas/node-agent-paths.js";import{newNodeId as p}from"../../core/runtime/nodes.js";import{fullName as w}from"../../core/canvas/labels.js";import{listCronRuns as $,setCronState as _}from"../../core/canvas/crons.js";import{emitEvent as l}from"../../core/events/emit.js";import{spawnChild as y}from"../../core/runtime/spawn.js";import{cronWakeOrigin as g}from"../../core/runtime/bearings.js";import{cadenceDisplay as b}from"../../core/wake.js";import{cronBirthPlacement as v,cronBirthPrincipalOf as O,resolveLiveProfileOrRoot as k}from"./armed-context.js";import{checkCronBirth as S}from"./authority.js";function T(e,r){return r!==null?r:e.timedOut?`run timed out after ${e.runTimeoutS}s (killed; recorded exit -1)`:e.processErrorMessage!==null?`run process error: ${e.processErrorMessage}`:`command exited ${e.exitCode??"(no exit observed)"}`}i(T,"failureSummary");async function x(e,r,s){const n=e.created_by!=null?await f(e.created_by):null,o=e.created_by==null?"created by: (no creating node recorded)":n!==null?`created by: node ${e.created_by} ("${w(n)}") \u2014 still on the canvas; consider telling it what happened`:`created by: node ${e.created_by} (now gone)`,a=e.recur!=null?`every ${b(e.recur)}`:`one-shot at ${e.fire_at}`,d=(await $(e.cron_id)).slice(0,10).map(t=>{const c=t.exit_code===null?"no exit":`exit ${t.exit_code}`,u=(t.stderr_head??t.stdout_head??"").split(`
2
+ `)[0]?.slice(0,120)??"";return`- ${t.started} \u2014 ${c}, ${t.duration_ms}ms \u2014 ${t.delivered??""}${u!==""?` \u2014 ${u}`:""}`});return["A scheduled cron FAILED and has paused itself. You were spawned to deal with it.","",`- cron: "${e.name}" (${e.cron_id})`,`- schedule: ${a}${e.tz!=null?` (tz ${e.tz})`:""}`,`- context: cwd ${e.cwd}${e.profile!=null?`, profile ${e.profile}`:""}`,`- ${o}`,`- this failure: ${T(r,s)}`,"","## The command","","```bash",e.command,"```","","## This run","",`- exit: ${r.timedOut?"-1 (timeout)":String(r.exitCode)}`,`- stdout (head): ${r.stdoutHead===""?"(empty)":""}`,...r.stdoutHead!==""?["```",r.stdoutHead,"```"]:[],`- stderr (head): ${r.stderrHead===""?"(empty)":""}`,...r.stderrHead!==""?["```",r.stderrHead,"```"]:[],"","## Recent runs (most recent first, this failure not yet recorded)","",...d.length>0?d:["(no prior runs recorded)"],"","## Your mandate","","Diagnose why it failed and decide what to do:",`- Transient or fixable: fix the environment/command context, verify with \`crtr cron run ${e.cron_id}\` (fires now, out of band, shows you the result), then \`crtr cron resume ${e.cron_id}\` to re-arm it.`,`- Obsolete: \`crtr cron cancel ${e.cron_id}\`.`,"- The user's call (or the fix needs a change you cannot make): `crtr human send`.","","The cron stays paused until someone resumes it \u2014 nothing refires while you work."].join(`
3
+ `)}i(x,"buildEscalationKickoff");async function j(e,r,s){await _(e.cron_id,"paused");try{const n=O(e),o=await S(n);if(!o.allowed)return l({level:"warn",event:"cron.birth.refused",fields:{cron_id:e.cron_id,grant_id:e.grant_id,reason:o.reason,stage:"escalation"}}),`failure: cron paused; no escalation node (refused: ${o.reason})`;const a=await p(),d=await v(n,a),t=await y({nodeId:a,kind:"general",isolated:e.isolated,cwd:e.isolated?await h(a,e.grantee):e.cwd,prompt:await x(e,r,s),...d,readiness:"launch",profile:k(e),wakeOrigin:await g(e,"node_birth")});return l({level:"info",event:"cron.failure.escalated",fields:{cron_id:e.cron_id,name:e.name,escalation_node:t.node.node_id}}),`failure: cron paused, escalation node ${t.node.node_id} spawned`}catch(n){return l({level:"error",event:"cron.escalation.spawn_failed",error:n,fields:{cron_id:e.cron_id,name:e.name}}),`failure: cron paused; escalation spawn failed: ${n.message}`}}i(j,"escalateFailure");function M(e){return[`${e}.`,"This is a ONE-SHOT, so it has been PAUSED rather than released: its side effects may have completed in full,","and re-firing would enact them a second time. Determine whether the work actually landed, then either","`crtr cron run` it to redo it deliberately, or `crtr cron cancel` it."].join(" ")}i(M,"crashedOneShotSummary");export{M as crashedOneShotSummary,j as escalateFailure,T as failureSummary};
@@ -2,4 +2,4 @@
2
2
  * crtr-data group (Linux sandbox), the folder takes the group of its parent and stays group-writable. */
3
3
  export declare function ensureCronFolder(app: string, cronId: string): string;
4
4
  /** Delete every `<app space>/crons/<id>` whose cron row no longer exists. */
5
- export declare function sweepOrphanCronFolders(): number;
5
+ export declare function sweepOrphanCronFolders(): Promise<number>;
@@ -1 +1 @@
1
- var l=Object.defineProperty;var c=(r,e)=>l(r,"name",{value:e,configurable:!0});import{chmodSync as m,chownSync as u,existsSync as f,mkdirSync as a,readdirSync as s,rmSync as y,statSync as v}from"node:fs";import{dirname as S,join as i}from"node:path";import{getCron as h}from"../../core/canvas/crons.js";import{emitEvent as d}from"../../core/events/emit.js";import{appsRoot as w,cronFolder as x}from"../../core/layout.js";function E(r,e){const n=x(r,e);for(const o of[n,i(n,"home")])if(a(o,{recursive:!0}),process.platform==="linux"){const t=v(S(o));try{u(o,process.getuid(),t.gid),m(o,1528)}catch{}}return n}c(E,"ensureCronFolder");function O(){let r=0;const e=w();if(!f(e))return 0;for(const n of s(e)){const o=i(e,n,"crons");if(f(o)){for(const t of s(o))if(h(t)===null)try{y(i(o,t),{recursive:!0,force:!0}),r++}catch(p){d({level:"warn",event:"cron.folder.sweep_failed",error:p,fields:{cron_id:t,app:n}})}}}return r>0&&d({level:"info",event:"cron.folder.swept",fields:{removed:r}}),r}c(O,"sweepOrphanCronFolders");export{E as ensureCronFolder,O as sweepOrphanCronFolders};
1
+ var l=Object.defineProperty;var c=(r,e)=>l(r,"name",{value:e,configurable:!0});import{chmodSync as m,chownSync as u,existsSync as f,mkdirSync as a,readdirSync as s,rmSync as y,statSync as v}from"node:fs";import{dirname as S,join as i}from"node:path";import{getCron as h}from"../../core/canvas/crons.js";import{emitEvent as d}from"../../core/events/emit.js";import{appsRoot as w,cronFolder as x}from"../../core/layout.js";function E(r,e){const n=x(r,e);for(const o of[n,i(n,"home")])if(a(o,{recursive:!0}),process.platform==="linux"){const t=v(S(o));try{u(o,process.getuid(),t.gid),m(o,1528)}catch{}}return n}c(E,"ensureCronFolder");async function O(){let r=0;const e=w();if(!f(e))return 0;for(const n of s(e)){const o=i(e,n,"crons");if(f(o)){for(const t of s(o))if(await h(t)===null)try{y(i(o,t),{recursive:!0,force:!0}),r++}catch(p){d({level:"warn",event:"cron.folder.sweep_failed",error:p,fields:{cron_id:t,app:n}})}}}return r>0&&d({level:"info",event:"cron.folder.swept",fields:{removed:r}}),r}c(O,"sweepOrphanCronFolders");export{E as ensureCronFolder,O as sweepOrphanCronFolders};
@@ -1,4 +1,4 @@
1
1
  import { type Cron, type HeldSettle } from '../../core/canvas/crons.js';
2
2
  export declare const EXIT_HELD = 75;
3
3
  export declare const HELD_DELIVERED = "deferred (exit 75) \u2014 held for poke";
4
- export declare function decideHeldSettle(c: Cron, startedAtIso: string, finishedAtMs: number): HeldSettle | undefined;
4
+ export declare function decideHeldSettle(c: Cron, startedAtIso: string, finishedAtMs: number): Promise<HeldSettle | undefined>;
@@ -1 +1 @@
1
- var i=Object.defineProperty;var n=(t,r)=>i(t,"name",{value:r,configurable:!0});import{getCron as d}from"../../core/canvas/crons.js";const a=75,f="deferred (exit 75) \u2014 held for poke",_="9999-12-31T23:59:59.999Z";function p(t,r,o){const e=d(t.cron_id);if(e!==null)return e.state==="active"&&e.last_poke_at!==null&&r<e.last_poke_at?{kind:"redue",nowIso:new Date(o).toISOString()}:t.recur!=null?{kind:"park"}:{kind:"park",fireAt:e.expires_at??_}}n(p,"decideHeldSettle");export{a as EXIT_HELD,f as HELD_DELIVERED,p as decideHeldSettle};
1
+ var i=Object.defineProperty;var n=(t,r)=>i(t,"name",{value:r,configurable:!0});import{getCron as a}from"../../core/canvas/crons.js";const s=75,u="deferred (exit 75) \u2014 held for poke",d="9999-12-31T23:59:59.999Z";async function f(t,r,o){const e=await a(t.cron_id);if(e!==null)return e.state==="active"&&e.last_poke_at!==null&&r<e.last_poke_at?{kind:"redue",nowIso:new Date(o).toISOString()}:t.recur!=null?{kind:"park"}:{kind:"park",fireAt:e.expires_at??d}}n(f,"decideHeldSettle");export{s as EXIT_HELD,u as HELD_DELIVERED,f as decideHeldSettle};
@@ -1,3 +1,3 @@
1
1
  import type { RunDueCronOptions } from './passes.js';
2
2
  /** Recover leases from prior daemon instances. Verify launch identity, not pid liveness: a reboot can recycle the pid, and killing its new owner would signal a stranger. */
3
- export declare function recoverStaleCronLeases(now: number, options?: RunDueCronOptions): void;
3
+ export declare function recoverStaleCronLeases(now: number, options?: RunDueCronOptions): Promise<void>;
@@ -1 +1 @@
1
- var v=Object.defineProperty;var d=(e,r)=>v(e,"name",{value:r,configurable:!0});import{randomUUID as m}from"node:crypto";import{setTimeout as S}from"node:timers/promises";import{CRON_DEATH_POLL_MS as w,CRON_KILL_GRACE_MS as A,EMPTY_STDOUT_SHA256 as f}from"./capture.js";import{cronDaemonInstanceId as C}from"./live-runs.js";import{crashedOneShotSummary as L,escalateFailure as H}from"./escalation.js";import{settleRun as h}from"./settle.js";import{runningCrons as M,stopLeasedCronRun as p,setCronState as g,verifyLeasedCronRun as l}from"../../core/canvas/crons.js";import{emitEvent as c}from"../../core/events/emit.js";const i=new Set;function K(e,r={}){for(const t of M()){if(t.run_lease_owner===C||i.has(t.cron_id))continue;if(t.run_pid===null||!l(t)){i.add(t.cron_id),y(t,e,r);continue}const o=t.run_started_at!=null?new Date(t.run_started_at).getTime():e;if(e-o<t.run_timeout_s*1e3)continue;const a={runId:t.run_execution_id??m(),startedAtIso:t.run_started_at??new Date(e).toISOString(),exitCode:-1,timedOut:!0,runTimeoutS:t.run_timeout_s,processErrorMessage:null,stdoutHead:"",stdoutSha256:f,stderrHead:`run timed out after ${t.run_timeout_s}s (recovered stale lease from a prior daemon instance)`};i.add(t.cron_id);const n=(async()=>{await p(t),await x(t),await h(t,{outOfBand:!1,outcome:{kind:"disposed",ctx:a},record:{runId:a.runId,startedAtIso:a.startedAtIso,finishedAtMs:e,durationMs:e-o,exitCode:-1,stdoutHead:null,stderrHead:a.stderrHead},lease:{kind:"clear"}})})().finally(()=>i.delete(t.cron_id));r.register?.(n),n.catch(s=>{c({level:"error",event:"cron.stale_lease.settle_failed",error:s,fields:{cron_id:t.cron_id}})})}}d(K,"recoverStaleCronLeases");async function x(e){if(!await I(e)&&(await p(e,"SIGKILL"),!await I(e)))throw new Error(`cron ${e.cron_id} run ${e.run_pid} survived SIGKILL`)}d(x,"awaitLeasedRunDeath");async function I(e){const r=Date.now()+A;for(;Date.now()<r;){if(!l(e))return!0;await S(w)}return!l(e)}d(I,"pollLeasedRunGone");function y(e,r,t){const o=e.recur==null,a=e.run_started_at!=null?new Date(e.run_started_at).getTime():r,n=e.run_pid===null?"the daemon life that claimed this run ended before its launch pid was recorded \u2014 the command may have started and its outcome is unknown":"the daemon life that owned this run ended before it settled \u2014 the process is gone and its outcome was never observed",s={runId:e.run_execution_id??m(),startedAtIso:e.run_started_at??new Date(r).toISOString(),exitCode:null,timedOut:!1,runTimeoutS:e.run_timeout_s,processErrorMessage:n,stdoutHead:"",stdoutSha256:f,stderrHead:`run outcome unobserved: ${n}`},_=(async()=>{let u=`crashed: ${n}${o?"":" \u2014 the next occurrence is unaffected"}`;o&&(g(e.cron_id,"paused"),u=e.on_output==="silent"?`crashed: ${n} \u2014 one-shot paused, not re-fired (silent: not escalated)`:`crashed one-shot: ${await H(e,s,L(n))}`),await h(e,{outOfBand:!1,outcome:{kind:"stated",delivered:u,paused:o},record:{runId:s.runId,startedAtIso:s.startedAtIso,finishedAtMs:r,durationMs:Math.max(0,r-a),exitCode:null,stdoutHead:null,stderrHead:s.stderrHead},lease:"release"}),c({level:"warn",event:"cron.run.unobserved",fields:{cron_id:e.cron_id,name:e.name,one_shot:o}})})().finally(()=>i.delete(e.cron_id));t.register?.(_),_.catch(u=>{c({level:"error",event:"cron.crashed_run.settle_failed",error:u,fields:{cron_id:e.cron_id}})})}d(y,"settleCrashedRun");export{K as recoverStaleCronLeases};
1
+ var v=Object.defineProperty;var d=(e,r)=>v(e,"name",{value:r,configurable:!0});import{randomUUID as m}from"node:crypto";import{setTimeout as w}from"node:timers/promises";import{CRON_DEATH_POLL_MS as S,CRON_KILL_GRACE_MS as A,EMPTY_STDOUT_SHA256 as f}from"./capture.js";import{cronDaemonInstanceId as C}from"./live-runs.js";import{crashedOneShotSummary as L,escalateFailure as y}from"./escalation.js";import{settleRun as h}from"./settle.js";import{runningCrons as H,stopLeasedCronRun as p,setCronState as M,verifyLeasedCronRun as l}from"../../core/canvas/crons.js";import{emitEvent as c}from"../../core/events/emit.js";const i=new Set;async function K(e,r={}){for(const t of await H()){if(t.run_lease_owner===C||i.has(t.cron_id))continue;if(t.run_pid===null||!l(t)){i.add(t.cron_id),x(t,e,r);continue}const a=t.run_started_at!=null?new Date(t.run_started_at).getTime():e;if(e-a<t.run_timeout_s*1e3)continue;const o={runId:t.run_execution_id??m(),startedAtIso:t.run_started_at??new Date(e).toISOString(),exitCode:-1,timedOut:!0,runTimeoutS:t.run_timeout_s,processErrorMessage:null,stdoutHead:"",stdoutSha256:f,stderrHead:`run timed out after ${t.run_timeout_s}s (recovered stale lease from a prior daemon instance)`};i.add(t.cron_id);const n=(async()=>{await p(t),await g(t),await h(t,{outOfBand:!1,outcome:{kind:"disposed",ctx:o},record:{runId:o.runId,startedAtIso:o.startedAtIso,finishedAtMs:e,durationMs:e-a,exitCode:-1,stdoutHead:null,stderrHead:o.stderrHead},lease:{kind:"clear"}})})().finally(()=>i.delete(t.cron_id));r.register?.(n),n.catch(s=>{c({level:"error",event:"cron.stale_lease.settle_failed",error:s,fields:{cron_id:t.cron_id}})})}}d(K,"recoverStaleCronLeases");async function g(e){if(!await I(e)&&(await p(e,"SIGKILL"),!await I(e)))throw new Error(`cron ${e.cron_id} run ${e.run_pid} survived SIGKILL`)}d(g,"awaitLeasedRunDeath");async function I(e){const r=Date.now()+A;for(;Date.now()<r;){if(!l(e))return!0;await w(S)}return!l(e)}d(I,"pollLeasedRunGone");function x(e,r,t){const a=e.recur==null,o=e.run_started_at!=null?new Date(e.run_started_at).getTime():r,n=e.run_pid===null?"the daemon life that claimed this run ended before its launch pid was recorded \u2014 the command may have started and its outcome is unknown":"the daemon life that owned this run ended before it settled \u2014 the process is gone and its outcome was never observed",s={runId:e.run_execution_id??m(),startedAtIso:e.run_started_at??new Date(r).toISOString(),exitCode:null,timedOut:!1,runTimeoutS:e.run_timeout_s,processErrorMessage:n,stdoutHead:"",stdoutSha256:f,stderrHead:`run outcome unobserved: ${n}`},_=(async()=>{let u=`crashed: ${n}${a?"":" \u2014 the next occurrence is unaffected"}`;a&&(await M(e.cron_id,"paused"),u=e.on_output==="silent"?`crashed: ${n} \u2014 one-shot paused, not re-fired (silent: not escalated)`:`crashed one-shot: ${await y(e,s,L(n))}`),await h(e,{outOfBand:!1,outcome:{kind:"stated",delivered:u,paused:a},record:{runId:s.runId,startedAtIso:s.startedAtIso,finishedAtMs:r,durationMs:Math.max(0,r-o),exitCode:null,stdoutHead:null,stderrHead:s.stderrHead},lease:"release"}),c({level:"warn",event:"cron.run.unobserved",fields:{cron_id:e.cron_id,name:e.name,one_shot:a}})})().finally(()=>i.delete(e.cron_id));t.register?.(_),_.catch(u=>{c({level:"error",event:"cron.crashed_run.settle_failed",error:u,fields:{cron_id:e.cron_id}})})}d(x,"settleCrashedRun");export{K as recoverStaleCronLeases};
@@ -2,5 +2,5 @@ export interface RunDueCronOptions {
2
2
  /** Registers settlement work for graceful-teardown draining. */
3
3
  register?: (work: Promise<void>) => void;
4
4
  }
5
- export declare function expireDueCrons(nowIso: string): void;
6
- export declare function applyOverlapPolicies(now: number, nowIso: string): void;
5
+ export declare function expireDueCrons(nowIso: string): Promise<void>;
6
+ export declare function applyOverlapPolicies(now: number, nowIso: string): Promise<void>;
@@ -1 +1 @@
1
- var c=Object.defineProperty;var o=(n,e)=>c(n,"name",{value:e,configurable:!0});import{randomUUID as l}from"node:crypto";import{cronDaemonInstanceId as s,liveRunFor as u}from"./live-runs.js";import{advanceCron as a,dueOverlapCrons as p,expiredIdleCrons as f,listCronRuns as m,recordCronRun as _}from"../../core/canvas/crons.js";import{emitEvent as v}from"../../core/events/emit.js";import{nextSlotAfter as x}from"../../core/wake.js";import{endCron as h}from"./ended.js";const d="skipped (overlap=skip)";function A(n){for(const e of f(n))h(e,{kind:"expired"})&&v({level:"info",event:"cron.expired",fields:{cron_id:e.cron_id,name:e.name,expires_at:e.expires_at}})}o(A,"expireDueCrons");function k(n){return m(n)[0]?.delivered?.startsWith(d)===!0}o(k,"latestRunIsSkip");function E(n,e){for(const r of p(e)){if(r.overlap==="queue")continue;if(r.overlap==="skip"){let t;try{t=x(r.recur,new Date(n))}catch{continue}a(r.cron_id,t),k(r.cron_id)||_({run_id:l(),cron_id:r.cron_id,started:e,finished:e,duration_ms:0,exit_code:null,stdout_head:null,stderr_head:null,delivered:`${d}: fire landed while the previous run was in flight (consecutive skips are not re-recorded until a run settles)`});continue}const i=u(r.cron_id);r.run_lease_owner===s&&i!==void 0&&!i.replaced&&(i.replaced=!0,i.kill())}}o(E,"applyOverlapPolicies");export{E as applyOverlapPolicies,A as expireDueCrons};
1
+ var d=Object.defineProperty;var t=(n,e)=>d(n,"name",{value:e,configurable:!0});import{randomUUID as c}from"node:crypto";import{cronDaemonInstanceId as l,liveRunFor as s}from"./live-runs.js";import{advanceCron as u,dueOverlapCrons as p,expiredIdleCrons as f,listCronRuns as m,recordCronRun as _}from"../../core/canvas/crons.js";import{emitEvent as v}from"../../core/events/emit.js";import{nextSlotAfter as x}from"../../core/wake.js";import{endCron as w}from"./ended.js";const a="skipped (overlap=skip)";async function A(n){for(const e of await f(n))await w(e,{kind:"expired"})&&v({level:"info",event:"cron.expired",fields:{cron_id:e.cron_id,name:e.name,expires_at:e.expires_at}})}t(A,"expireDueCrons");async function h(n){return(await m(n))[0]?.delivered?.startsWith(a)===!0}t(h,"latestRunIsSkip");async function E(n,e){for(const r of await p(e)){if(r.overlap==="queue")continue;if(r.overlap==="skip"){let o;try{o=x(r.recur,new Date(n))}catch{continue}await u(r.cron_id,o),await h(r.cron_id)||await _({run_id:c(),cron_id:r.cron_id,started:e,finished:e,duration_ms:0,exit_code:null,stdout_head:null,stderr_head:null,delivered:`${a}: fire landed while the previous run was in flight (consecutive skips are not re-recorded until a run settles)`});continue}const i=s(r.cron_id);r.run_lease_owner===l&&i!==void 0&&!i.replaced&&(i.replaced=!0,i.kill())}}t(E,"applyOverlapPolicies");export{E as applyOverlapPolicies,A as expireDueCrons};
@@ -26,5 +26,5 @@ export declare function rebuildCronExecutions(list?: () => Promise<Array<{
26
26
  nodeId: string;
27
27
  }>>): Promise<void>;
28
28
  /** Close rebuilt executions whose row no longer records them (their lease settled elsewhere). Own executions close in the executor. */
29
- export declare function reapRebuiltCronExecutions(): void;
29
+ export declare function reapRebuiltCronExecutions(): Promise<void>;
30
30
  export {};
@@ -1 +1 @@
1
- var k=Object.defineProperty;var i=(r,n)=>k(r,"name",{value:n,configurable:!0});import{createServer as F}from"node:http";import{chmodSync as g,existsSync as x,mkdirSync as A,readdirSync as O,rmSync as v,unlinkSync as z}from"node:fs";import{dirname as H,join as f}from"node:path";import{peerUid as M}from"../../native/linux.js";import{nodeRunDir as a}from"../../core/canvas/paths.js";import{readConfig as U,readMergedLaunchConfig as j}from"../../core/config.js";import{readRotationConfig as q}from"../../core/subscription-state.js";import{runningCrons as _}from"../../core/canvas/crons.js";import{emitEvent as u}from"../../core/events/emit.js";import{cronLaunchId as s}from"../../core/spaces/process.js";import{ensureAppSpace as B}from"../../core/spaces/space.js";import{launcherPresent as y,listSandboxes as b}from"../../core/grants/sandboxes.js";import{uidForApp as J}from"../../core/spaces/users.js";import{setModeBeneath as L,writeFileBeneath as N}from"../../core/spaces/open-beneath.js";import{cronExecutionFor as S,cronExecutions as D,dropCronExecution as C,registerCronExecution as w}from"./live-runs.js";let p=null;function ar(r){p=r}i(ar,"setCronRequestHandler");const E=i(r=>process.platform==="linux"?M(r.socket):null,"linuxPeerUid");let I=E;function dr(r){I=r??E}i(dr,"__setCronPeerUidForTest");const m=new Map;function T(r){return f(a(s(r)),"cli.sock")}i(T,"cronSocketPath");function W(r){return{class:"cron",app:r.grantee,sub:r.sub,grant:r.grantId,scopes:r.scopes,cron:r.cronId,execution:r.executionId,origin_run:r.originRunId,isolated:r.isolated,anchor:r.anchor,uid:r.uid}}i(W,"cronPrincipalClassOf");function d(r,n,t,o){r.writeHead(n,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:t,message:o,type:"invalid_request_error",origin:"runtime",retryable:!1}}))}i(d,"refuse");function G(r){return(n,t)=>{try{const o=S(r);if(o===void 0){d(t,401,"unauthorized","this cron execution has ended");return}const e=I(n);if(e!==null&&e!==o.uid){u({event:"api.principal.denied",level:"warn",fields:{method:n.method,execution:r}}),d(t,401,"unauthorized","missing or invalid bearer token");return}if(p===null){d(t,503,"daemon_unavailable","the API server is not running");return}p(n,t,W(o))}catch(o){u({event:"api.principal.failed",level:"error",error:o instanceof Error?o:new Error(String(o))}),t.headersSent||d(t,401,"unauthorized","missing or invalid bearer token")}}}i(G,"onCronRequest");async function P(r){const n=T(r);x(n)&&z(n);const t=F(G(r));await new Promise((o,e)=>{t.once("error",e),t.listen(n,()=>{t.off("error",e),o()})}),g(n,438),m.set(r,t)}i(P,"listen");async function lr(r,n,t){const o=a(s(r.executionId));w(r);try{A(o,{recursive:!0,mode:504}),g(o,504);const e={user:U("user"),launch:j(n,t),rotation:q()},c=f(o,"cron-launch.json");if(N(o,c,JSON.stringify({configSnapshot:e}),{atomic:!0,mode:416}),y()){const l=await B(r.grantee);L(o,c,416,{uid:process.getuid(),gid:l.gid})}await P(r.executionId)}catch(e){throw R(r.executionId),e}}i(lr,"openCronExecution");function R(r){C(r);const n=m.get(r);m.delete(r),n!==void 0&&(n.closeAllConnections(),n.close());try{v(a(s(r)),{recursive:!0,force:!0})}catch{}}i(R,"closeCronExecution");let h=Promise.resolve();function fr(){return h}i(fr,"cronExecutionsReady");function pr(r=b){return h=(async()=>{if(r===b&&!y())return;const t=new Set((await r()).map(e=>e.nodeId));for(const e of _()){const c=e.run_execution_id;if(!(c==null||!t.has(s(c))||S(c)!==void 0))try{w({executionId:c,cronId:e.cron_id,grantee:e.grantee,sub:e.sub,grantId:e.grant_id,scopes:e.scopes,originRunId:e.origin_run_id,isolated:e.isolated,anchor:e.anchor_node,uid:J(e.grantee),rebuilt:!0,refusal:null}),await P(c),u({level:"info",event:"cron.execution.rebuilt",fields:{cron_id:e.cron_id,execution_id:c}})}catch(l){C(c),u({level:"error",event:"cron.execution.rebuild_failed",error:l,fields:{cron_id:e.cron_id,execution_id:c}})}}if(process.platform!=="linux")return;const o=H(a(s("x")));if(x(o)){for(const e of O(o))if(!(!e.startsWith("cron-")||t.has(e)))try{v(f(o,e),{recursive:!0,force:!0})}catch{}}})().catch(t=>{u({level:"error",event:"cron.execution.rebuild_failed",error:t})}),h}i(pr,"rebuildCronExecutions");function mr(){const r=new Set(_().map(n=>n.run_execution_id));for(const n of D())n.rebuilt&&!r.has(n.executionId)&&R(n.executionId)}i(mr,"reapRebuiltCronExecutions");export{dr as __setCronPeerUidForTest,R as closeCronExecution,fr as cronExecutionsReady,W as cronPrincipalClassOf,T as cronSocketPath,lr as openCronExecution,mr as reapRebuiltCronExecutions,pr as rebuildCronExecutions,ar as setCronRequestHandler};
1
+ var k=Object.defineProperty;var i=(r,n)=>k(r,"name",{value:n,configurable:!0});import{createServer as F}from"node:http";import{chmodSync as g,existsSync as x,mkdirSync as A,readdirSync as O,rmSync as v,unlinkSync as z}from"node:fs";import{dirname as H,join as f}from"node:path";import{peerUid as M}from"../../native/linux.js";import{nodeRunDir as s}from"../../core/canvas/paths.js";import{readConfig as U,readMergedLaunchConfig as j}from"../../core/config.js";import{readRotationConfig as q}from"../../core/subscription-state.js";import{runningCrons as _}from"../../core/canvas/crons.js";import{emitEvent as u}from"../../core/events/emit.js";import{cronLaunchId as a}from"../../core/spaces/process.js";import{ensureAppSpace as B}from"../../core/spaces/space.js";import{launcherPresent as y,listSandboxes as b}from"../../core/grants/sandboxes.js";import{uidForApp as J}from"../../core/spaces/users.js";import{setModeBeneath as L,writeFileBeneath as N}from"../../core/spaces/open-beneath.js";import{cronExecutionFor as w,cronExecutions as D,dropCronExecution as S,registerCronExecution as C}from"./live-runs.js";let p=null;function sr(r){p=r}i(sr,"setCronRequestHandler");const E=i(r=>process.platform==="linux"?M(r.socket):null,"linuxPeerUid");let I=E;function dr(r){I=r??E}i(dr,"__setCronPeerUidForTest");const m=new Map;function T(r){return f(s(a(r)),"cli.sock")}i(T,"cronSocketPath");function W(r){return{class:"cron",app:r.grantee,sub:r.sub,grant:r.grantId,scopes:r.scopes,cron:r.cronId,execution:r.executionId,origin_run:r.originRunId,isolated:r.isolated,anchor:r.anchor,uid:r.uid}}i(W,"cronPrincipalClassOf");function d(r,n,t,o){r.writeHead(n,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:t,message:o,type:"invalid_request_error",origin:"runtime",retryable:!1}}))}i(d,"refuse");function G(r){return(n,t)=>{try{const o=w(r);if(o===void 0){d(t,401,"unauthorized","this cron execution has ended");return}const e=I(n);if(e!==null&&e!==o.uid){u({event:"api.principal.denied",level:"warn",fields:{method:n.method,execution:r}}),d(t,401,"unauthorized","missing or invalid bearer token");return}if(p===null){d(t,503,"daemon_unavailable","the API server is not running");return}p(n,t,W(o))}catch(o){u({event:"api.principal.failed",level:"error",error:o instanceof Error?o:new Error(String(o))}),t.headersSent||d(t,401,"unauthorized","missing or invalid bearer token")}}}i(G,"onCronRequest");async function P(r){const n=T(r);x(n)&&z(n);const t=F(G(r));await new Promise((o,e)=>{t.once("error",e),t.listen(n,()=>{t.off("error",e),o()})}),g(n,438),m.set(r,t)}i(P,"listen");async function lr(r,n,t){const o=s(a(r.executionId));C(r);try{A(o,{recursive:!0,mode:504}),g(o,504);const e={user:U("user"),launch:j(n,t),rotation:q()},c=f(o,"cron-launch.json");if(N(o,c,JSON.stringify({configSnapshot:e}),{atomic:!0,mode:416}),y()){const l=await B(r.grantee);L(o,c,416,{uid:process.getuid(),gid:l.gid})}await P(r.executionId)}catch(e){throw R(r.executionId),e}}i(lr,"openCronExecution");function R(r){S(r);const n=m.get(r);m.delete(r),n!==void 0&&(n.closeAllConnections(),n.close());try{v(s(a(r)),{recursive:!0,force:!0})}catch{}}i(R,"closeCronExecution");let h=Promise.resolve();function fr(){return h}i(fr,"cronExecutionsReady");function pr(r=b){return h=(async()=>{if(r===b&&!y())return;const t=new Set((await r()).map(e=>e.nodeId));for(const e of await _()){const c=e.run_execution_id;if(!(c==null||!t.has(a(c))||w(c)!==void 0))try{C({executionId:c,cronId:e.cron_id,grantee:e.grantee,sub:e.sub,grantId:e.grant_id,scopes:e.scopes,originRunId:e.origin_run_id,isolated:e.isolated,anchor:e.anchor_node,uid:await J(e.grantee),rebuilt:!0,refusal:null}),await P(c),u({level:"info",event:"cron.execution.rebuilt",fields:{cron_id:e.cron_id,execution_id:c}})}catch(l){S(c),u({level:"error",event:"cron.execution.rebuild_failed",error:l,fields:{cron_id:e.cron_id,execution_id:c}})}}if(process.platform!=="linux")return;const o=H(s(a("x")));if(x(o)){for(const e of O(o))if(!(!e.startsWith("cron-")||t.has(e)))try{v(f(o,e),{recursive:!0,force:!0})}catch{}}})().catch(t=>{u({level:"error",event:"cron.execution.rebuild_failed",error:t})}),h}i(pr,"rebuildCronExecutions");async function mr(){const r=new Set((await _()).map(n=>n.run_execution_id));for(const n of D())n.rebuilt&&!r.has(n.executionId)&&R(n.executionId)}i(mr,"reapRebuiltCronExecutions");export{dr as __setCronPeerUidForTest,R as closeCronExecution,fr as cronExecutionsReady,W as cronPrincipalClassOf,T as cronSocketPath,lr as openCronExecution,mr as reapRebuiltCronExecutions,pr as rebuildCronExecutions,sr as setCronRequestHandler};
@@ -1 +1 @@
1
- var p=Object.defineProperty;var l=(e,u)=>p(e,"name",{value:u,configurable:!0});import{consumeCron as _,recordCronRunLocked as y,releaseCronRunLease as I,setCronState as b}from"../../core/canvas/crons.js";import{withCanvasWrite as k}from"../../core/canvas/db.js";import{enqueueDaemonAction as v}from"../../core/canvas/daemon-actions.js";import{enqueueNodeMail as g}from"../../core/feed/messages.js";import{emitEvent as w}from"../../core/events/emit.js";import{disposeSettledRun as C}from"./disposition.js";function h(e){return typeof e=="object"&&(e.kind==="park"||e.kind==="redue")}l(h,"occurrenceStaysOwed");async function M(e,u){const{outOfBand:s,outcome:o,record:n,lease:a}=u;let r,t,d;if(o.kind==="disposed"){const i=await C(e,o.ctx,s,o.selfCanceled??!1);r=i.delivered,t=i.paused,d=i.obligation}else o.kind==="refused"?(r=`refused: ${o.reason}`,t=!s&&e.recur==null,t&&b(e.cron_id,"paused"),w({level:"warn",event:"cron.fire.refused",fields:{cron_id:e.cron_id,execution_id:n.runId,grant_id:e.grant_id,reason:o.reason,out_of_band:s}})):(r=o.delivered,t=o.paused??!1);const f=k(i=>{d!==void 0&&(d.kind==="node"?r=`delivered: ${g(d.destinationNodeId,{kind:"message",label:d.label,senderNodeId:d.senderNodeId,bodyJson:{body:d.stdout},urgency:d.urgency,wake:1,idempotencyKey:n.runId}).deliveryId}`:d.kind==="action"&&(r=`delivered: ${v({adapter:d.adapter,bodyJson:d.bodyJson,idempotencyKey:n.runId})}`));const c={run_id:n.runId,cron_id:e.cron_id,started:n.startedAtIso,finished:new Date(n.finishedAtMs).toISOString(),duration_ms:n.durationMs,exit_code:n.exitCode,stdout_head:n.stdoutHead,stderr_head:n.stderrHead,delivered:r};return y(i,c),c});return a!=="none"&&I(e.cron_id,a==="release"?void 0:a),!s&&e.recur==null&&!t&&!h(a)&&_(e.cron_id),f}l(M,"settleRun");export{M as settleRun};
1
+ var p=Object.defineProperty;var c=(e,u)=>p(e,"name",{value:u,configurable:!0});import{consumeCron as _,recordCronRunLocked as y,releaseCronRunLease as w,setCronState as I}from"../../core/canvas/crons.js";import{withCanvasWrite as b}from"../../core/canvas/db.js";import{enqueueDaemonAction as k}from"../../core/canvas/daemon-actions.js";import{enqueueNodeMail as v}from"../../core/feed/messages.js";import{emitEvent as g}from"../../core/events/emit.js";import{disposeSettledRun as C}from"./disposition.js";function h(e){return typeof e=="object"&&(e.kind==="park"||e.kind==="redue")}c(h,"occurrenceStaysOwed");async function M(e,u){const{outOfBand:a,outcome:t,record:n,lease:s}=u;let o,i,d;if(t.kind==="disposed"){const r=await C(e,t.ctx,a,t.selfCanceled??!1);o=r.delivered,i=r.paused,d=r.obligation}else t.kind==="refused"?(o=`refused: ${t.reason}`,i=!a&&e.recur==null,i&&await I(e.cron_id,"paused"),g({level:"warn",event:"cron.fire.refused",fields:{cron_id:e.cron_id,execution_id:n.runId,grant_id:e.grant_id,reason:t.reason,out_of_band:a}})):(o=t.delivered,i=t.paused??!1);const f=await b(async r=>{d!==void 0&&(d.kind==="node"?o=`delivered: ${(await v(d.destinationNodeId,{kind:"message",label:d.label,senderNodeId:d.senderNodeId,bodyJson:{body:d.stdout},urgency:d.urgency,wake:1,idempotencyKey:n.runId})).deliveryId}`:d.kind==="action"&&(o=`delivered: ${await k({adapter:d.adapter,bodyJson:d.bodyJson,idempotencyKey:n.runId})}`));const l={run_id:n.runId,cron_id:e.cron_id,started:n.startedAtIso,finished:new Date(n.finishedAtMs).toISOString(),duration_ms:n.durationMs,exit_code:n.exitCode,stdout_head:n.stdoutHead,stderr_head:n.stderrHead,delivered:o};return await y(r,l),l});return s!=="none"&&await w(e.cron_id,s==="release"?void 0:s),!a&&e.recur==null&&!i&&!h(s)&&await _(e.cron_id),f}c(M,"settleRun");export{M as settleRun};
@@ -17,4 +17,4 @@ export type CronSinkResolution = {
17
17
  bodyJson: unknown;
18
18
  };
19
19
  /** Resolve a completed run into a durable obligation. No sink effect happens here. */
20
- export declare function resolveCronSink(c: Cron, runId: string, stdout: string): CronSinkResolution;
20
+ export declare function resolveCronSink(c: Cron, runId: string, stdout: string): Promise<CronSinkResolution>;
@@ -1,2 +1,2 @@
1
- var u=Object.defineProperty;var a=(e,o)=>u(e,"name",{value:o,configurable:!0});import{newNodeId as l}from"../../core/runtime/nodes.js";import{nodeAgentDir as f}from"../../core/canvas/node-agent-paths.js";import{getNode as s}from"../../core/canvas/canvas.js";import{parseCronSink as p}from"../../core/canvas/crons.js";import{hasNoNaturalCycle as k}from"../../core/runtime/revive-all.js";import{isParked as c}from"../../core/runtime/lifecycle.js";import{cronWakeOrigin as h}from"../../core/runtime/bearings.js";import{emitEvent as _}from"../../core/events/emit.js";import{cronBirthPrincipalOf as v,resolveLiveProfile as w,resolveLiveProfileName as y}from"./armed-context.js";import{checkCronBirth as g}from"./authority.js";function J(e,o,i){const n=p(e.sink);if(n===null)return{kind:"none",delivered:"no sink armed \u2014 nothing delivered"};if(n.kind==="node"){const r=s(n.node);if(r===null)throw new Error(`node sink ${n.node} is gone`);if(k(r)&&!c(r))throw new Error(`node sink ${n.node} has no natural cycle ahead (done or finalized)`);return{kind:"node",destinationNodeId:n.node,senderNodeId:e.created_by!==null&&s(e.created_by)!==null?e.created_by:null,label:`\u23F0 cron ${e.name}`,stdout:i,urgency:e.tier}}if(n.kind==="spawn"){const r=v(e),d=g(r);if(!d.allowed)return _({level:"warn",event:"cron.birth.refused",fields:{cron_id:e.cron_id,grant_id:e.grant_id,reason:d.reason,stage:"enqueue"}}),{kind:"none",delivered:`refused: ${d.reason}`,refused:!0};const t=l(),m=[`Scheduled cron "${e.name}" (${e.cron_id}) fired and delivered its output to you as your kickoff.`,"","## Command output","",i].join(`
2
- `);return{kind:"action",adapter:{adapter:"cron_spawn",cronId:e.cron_id,nodeId:t,kind:n.spawn,cwd:e.isolated?f(t,e.grantee):e.cwd,isolated:e.isolated,principal:r,profile:w(e),wakeOrigin:h(e,"node_birth"),prompt:m},bodyJson:{runId:o,stdout:i}}}return{kind:"action",adapter:{adapter:"cron_human",cronId:e.cron_id,requestId:l(),title:`\u23F0 cron ${e.name}`,summary:`Scheduled cron "${e.name}" delivered output for your attention.`,sessionName:`cron ${e.name} (${e.cron_id})`,profileName:y(e)??null},bodyJson:{runId:o,stdout:i}}}a(J,"resolveCronSink");export{J as resolveCronSink};
1
+ var u=Object.defineProperty;var t=(e,o)=>u(e,"name",{value:o,configurable:!0});import{newNodeId as l}from"../../core/runtime/nodes.js";import{nodeAgentDir as f}from"../../core/canvas/node-agent-paths.js";import{getNode as s}from"../../core/canvas/canvas.js";import{parseCronSink as p}from"../../core/canvas/crons.js";import{hasNoNaturalCycle as c}from"../../core/runtime/revive-all.js";import{isParked as k}from"../../core/runtime/lifecycle.js";import{cronWakeOrigin as w}from"../../core/runtime/bearings.js";import{emitEvent as h}from"../../core/events/emit.js";import{cronBirthPrincipalOf as y,resolveLiveProfile as _,resolveLiveProfileName as v}from"./armed-context.js";import{checkCronBirth as g}from"./authority.js";async function J(e,o,i){const n=p(e.sink);if(n===null)return{kind:"none",delivered:"no sink armed \u2014 nothing delivered"};if(n.kind==="node"){const r=await s(n.node);if(r===null)throw new Error(`node sink ${n.node} is gone`);if(c(r)&&!k(r))throw new Error(`node sink ${n.node} has no natural cycle ahead (done or finalized)`);return{kind:"node",destinationNodeId:n.node,senderNodeId:e.created_by!==null&&await s(e.created_by)!==null?e.created_by:null,label:`\u23F0 cron ${e.name}`,stdout:i,urgency:e.tier}}if(n.kind==="spawn"){const r=y(e),a=await g(r);if(!a.allowed)return h({level:"warn",event:"cron.birth.refused",fields:{cron_id:e.cron_id,grant_id:e.grant_id,reason:a.reason,stage:"enqueue"}}),{kind:"none",delivered:`refused: ${a.reason}`,refused:!0};const d=await l(),m=[`Scheduled cron "${e.name}" (${e.cron_id}) fired and delivered its output to you as your kickoff.`,"","## Command output","",i].join(`
2
+ `);return{kind:"action",adapter:{adapter:"cron_spawn",cronId:e.cron_id,nodeId:d,kind:n.spawn,cwd:e.isolated?await f(d,e.grantee):e.cwd,isolated:e.isolated,principal:r,profile:_(e),wakeOrigin:await w(e,"node_birth"),prompt:m},bodyJson:{runId:o,stdout:i}}}return{kind:"action",adapter:{adapter:"cron_human",cronId:e.cron_id,requestId:await l(),title:`\u23F0 cron ${e.name}`,summary:`Scheduled cron "${e.name}" delivered output for your attention.`,sessionName:`cron ${e.name} (${e.cron_id})`,profileName:v(e)??null},bodyJson:{runId:o,stdout:i}}}t(J,"resolveCronSink");export{J as resolveCronSink};
@@ -19,13 +19,22 @@ export { recoverStaleCronLeases } from './cron/lease-recovery.js';
19
19
  export declare function executeCron(c: Cron, opts: {
20
20
  outOfBand: boolean;
21
21
  }): Promise<CronRunRecord | null>;
22
+ /** `executeCron` with its admission exposed: `admitted` resolves once the lease is held, the
23
+ * recurrence is advanced and the live run is registered (or the run ended earlier without
24
+ * launching), so a caller can wait for the claim before it looks at the cron row again. */
25
+ export declare function startCron(c: Cron, opts: {
26
+ outOfBand: boolean;
27
+ }): {
28
+ admitted: Promise<void>;
29
+ settled: Promise<CronRunRecord | null>;
30
+ };
22
31
  /** The daemon's cron pass: expire clock-bounded rows, apply overlap policies,
23
- * then kick off every due active idle cron. Each lease is claimed synchronously,
24
- * but its launch is NEVER awaited in the tick; returns one settlement promise per
32
+ * then kick off every due active idle cron. Each lease and recurrence advance is
33
+ * awaited here, but the launch is NEVER awaited in the tick; returns one settlement promise per
25
34
  * admitted run.
26
35
  *
27
36
  * A run that launches or revives a node is admitted unconditionally: the
28
37
  * broker slot ledger is the one admission gate, so such a run's node is born
29
38
  * or revived frozen at the cap and the node-lifecycle tick starts it when a
30
39
  * slot frees. The cron itself always fires and settles. */
31
- export declare function runDueCrons(now: number, options?: RunDueCronOptions): Promise<void>[];
40
+ export declare function runDueCrons(now: number, options?: RunDueCronOptions): Promise<Promise<void>[]>;
@@ -1,2 +1,2 @@
1
- var $=Object.defineProperty;var c=(e,t)=>$(e,"name",{value:t,configurable:!0});import{randomUUID as v}from"node:crypto";import{CRON_OUTPUT_HEAD_BYTES as g,EMPTY_STDOUT_SHA256 as y,formatCronOutputHead as I}from"./cron/capture.js";import{clearLiveRun as S,cronDaemonInstanceId as M,registerLiveRun as B}from"./cron/live-runs.js";import{closeCronExecution as L,openCronExecution as P}from"./cron/run-socket.js";import{appProcessSandboxed as U}from"../core/spaces/process.js";import{nodeAgentDir as F}from"../core/canvas/paths.js";import{uidForApp as N}from"../core/spaces/users.js";import{buildArmedRunContext as Y}from"./cron/armed-context.js";import{ensureCronFolder as q}from"./cron/folders.js";import{checkCronFire as J,cronPrincipalOf as V}from"./cron/authority.js";import{decideHeldSettle as X,EXIT_HELD as z,HELD_DELIVERED as G}from"./cron/held.js";import{settleRun as x}from"./cron/settle.js";import{applyOverlapPolicies as K,expireDueCrons as Q}from"./cron/passes.js";import{dueClockCrons as W,acquireCronRunLease as Z,attachCronRunPid as j,advanceCron as ee,setCronState as te}from"../core/canvas/crons.js";import{emitEvent as re}from"../core/events/emit.js";import{runAppCommand as ne}from"../core/runtime/run-command.js";import{nextSlotAfter as oe}from"../core/wake.js";import{CRON_OUTPUT_HEAD_BYTES as Me}from"./cron/capture.js";import{cronDaemonInstanceId as be,markSelfCanceledCronRun as ke}from"./cron/live-runs.js";import{recoverStaleCronLeases as ve}from"./cron/lease-recovery.js";async function se(e,t){const{runId:s,outOfBand:r,startedAtIso:o,finishedAtMs:n,code:i,timedOut:l,processError:u}=t,m=!r&&!l&&u==null&&i===z&&!t.wasReplaced&&!t.wasSelfCanceled;let p,f;return t.wasReplaced?(p={kind:"stated",delivered:"replaced (overlap=replace)"},f="release"):m?(p={kind:"stated",delivered:G},f=X(e,o,n)??"release"):(p={kind:"disposed",ctx:{runId:s,startedAtIso:o,exitCode:l?-1:i,timedOut:l,runTimeoutS:e.run_timeout_s,processErrorMessage:u!=null?u.message:null,stdoutHead:t.stdoutHead,stdoutSha256:t.stdoutSha256,stderrHead:t.stderrHead},selfCanceled:t.wasSelfCanceled},f=r?"release":{kind:"clear"}),x(e,{outOfBand:r,outcome:p,record:{runId:s,startedAtIso:o,finishedAtMs:n,durationMs:n-t.startedAtMs,exitCode:l?-1:i,stdoutHead:t.stdoutHead===""?null:t.stdoutHead,stderrHead:u!=null?`run process error: ${u.message}`.slice(0,g):t.stderrHead===""?null:t.stderrHead},lease:f})}c(se,"settleClosedRun");function H(e,t,s,r){const o=Date.now(),n=`${s}: ${r.message}`.slice(0,g);return x(e,{outOfBand:t.outOfBand,outcome:{kind:"disposed",ctx:{runId:t.runId,startedAtIso:t.startedAtIso,exitCode:null,timedOut:!1,runTimeoutS:e.run_timeout_s,processErrorMessage:r.message,stdoutHead:"",stdoutSha256:y,stderrHead:n}},record:{runId:t.runId,startedAtIso:t.startedAtIso,finishedAtMs:o,durationMs:o-t.startedAtMs,exitCode:null,stdoutHead:null,stderrHead:n},lease:"release"})}c(H,"settleUnspawnedRun");function T(e,t){let s;try{s=oe(e.recur,new Date(t))}catch(r){return re({level:"error",event:"cron.recur.unparseable",error:r,fields:{cron_id:e.cron_id,name:e.name,recur:e.recur}}),te(e.cron_id,"paused"),new Error(`unparseable recurrence ${JSON.stringify(e.recur)}: ${r.message} \u2014 this cron cannot be rescheduled until its recurrence is fixed (\`crtr cron cancel\` and re-arm it), so it has been paused.`)}return ee(e.cron_id,s),null}c(T,"advanceRecurrence");function de(e,t){const{outOfBand:s}=t;return new Promise((r,o)=>{const n=v(),i=Date.now(),l=new Date(i).toISOString(),u={runId:n,outOfBand:s,startedAtIso:l,startedAtMs:i};if(!Z(e.cron_id,M,l,s,n)){r(null);return}const m=J(V(e));if(!m.allowed){try{if(!s&&e.recur!=null){const h=T(e,i);if(h!==null)throw h}}catch(h){H(e,u,"run could not be armed",h).then(r,o);return}const d=Date.now();x(e,{outOfBand:s,outcome:{kind:"refused",reason:m.reason,message:m.message},record:{runId:n,startedAtIso:l,finishedAtMs:d,durationMs:d-i,exitCode:null,stdoutHead:null,stderrHead:`${m.reason}: ${m.message}`.slice(0,g)},lease:"release"}).then(r,o);return}let p;try{if(e.isolated&&q(e.grantee,e.cron_id),{env:p}=Y(e,n),!s&&e.recur!=null){const d=T(e,i);if(d!==null)throw d}}catch(d){H(e,u,"run could not be armed",d).then(r,o);return}let f=null,D=!1;const w={runId:n,replaced:!1,selfCanceled:!1,kill:c(()=>{f!==null?f():D=!0},"kill")};B(e.cron_id,w);const C=U()?{executionId:n,cronId:e.cron_id,grantee:e.grantee,sub:e.sub,grantId:e.grant_id,scopes:e.scopes,originRunId:e.origin_run_id,isolated:e.isolated,anchor:e.anchor_node,uid:N(e.grantee),rebuilt:!1,refusal:null}:null,E=c(()=>{C!==null&&L(n)},"closeExecution");c(async()=>(C!==null&&await P(C,e.cwd,e.profile),ne({command:e.command,cwd:e.cwd,env:p,app:e.grantee,isolated:e.isolated,principal:{sub:e.sub,grantId:e.grant_id,scopes:e.scopes},...e.isolated?{folder:e.cwd}:{},...C!==null?{cron:{executionId:n,...e.anchor_node===null||e.isolated?{}:{anchorDir:F(e.anchor_node,e.grantee)}}}:e.anchor_node===null||e.isolated?{}:{nodeId:e.anchor_node},timeoutMs:e.run_timeout_s*1e3,headBytes:g})),"launch")().then(d=>{if(d.pid===null){S(e.cron_id,n),E(),d.completion.then(a=>{H(e,u,"run failed to spawn",a.processError??new Error("bash did not provide a process id")).then(r,o)},o);return}let h=!1;const A=c(()=>{d.completion.then(a=>{const O=w.replaced,b=w.selfCanceled,_=C?.refusal??null;if(S(e.cron_id,n),E(),h){r(null);return}if(_!==null&&!O){const R=Date.now(),k=I(a.stderr,a.stderrTruncated);x(e,{outOfBand:s,outcome:{kind:"refused",reason:_.reason,message:_.message},record:{runId:n,startedAtIso:l,finishedAtMs:R,durationMs:R-i,exitCode:a.exitCode,stdoutHead:I(a.stdout,a.stdoutTruncated)||null,stderrHead:`${_.reason}: ${_.message}
2
- ${k}`.trim().slice(0,g)},lease:"release"}).then(r,o);return}se(e,{runId:n,outOfBand:s,startedAtIso:l,startedAtMs:i,finishedAtMs:Date.now(),code:a.exitCode,timedOut:a.timedOut,processError:a.processError,stdoutHead:I(a.stdout,a.stdoutTruncated),stderrHead:I(a.stderr,a.stderrTruncated),stdoutSha256:a.stdoutSha256,wasReplaced:O,wasSelfCanceled:b}).then(r,o)},o)},"settleCommand");if(!j(e.cron_id,M,l,d.pid)&&!w.selfCanceled){h=!0,d.terminate(),A();return}f=d.terminate,D&&d.terminate(),A()},d=>{S(e.cron_id,n),E(),H(e,u,"run failed to spawn",d).then(r,o)})})}c(de,"executeCron");function Ae(e,t={}){const s=new Date(e).toISOString();Q(s),K(e,s);const r=[];for(const o of W(s)){const n=de(o,{outOfBand:!1}).then(()=>{});r.push(n),t.register?.(n)}for(const o of r)o.catch(()=>{});return r}c(Ae,"runDueCrons");export{Me as CRON_OUTPUT_HEAD_BYTES,be as cronDaemonInstanceId,de as executeCron,ke as markSelfCanceledCronRun,ve as recoverStaleCronLeases,Ae as runDueCrons};
1
+ var N=Object.defineProperty;var i=(e,t)=>N(e,"name",{value:t,configurable:!0});import{randomUUID as Y}from"node:crypto";import{CRON_OUTPUT_HEAD_BYTES as E,EMPTY_STDOUT_SHA256 as q,formatCronOutputHead as A}from"./cron/capture.js";import{clearLiveRun as C,cronDaemonInstanceId as $,registerLiveRun as J}from"./cron/live-runs.js";import{closeCronExecution as V,openCronExecution as X}from"./cron/run-socket.js";import{appProcessSandboxed as z}from"../core/spaces/process.js";import{nodeAgentDir as G}from"../core/canvas/paths.js";import{uidForApp as K}from"../core/spaces/users.js";import{buildArmedRunContext as Q}from"./cron/armed-context.js";import{ensureCronFolder as W}from"./cron/folders.js";import{checkCronFire as Z,cronPrincipalOf as j}from"./cron/authority.js";import{decideHeldSettle as ee,EXIT_HELD as te,HELD_DELIVERED as re}from"./cron/held.js";import{settleRun as O}from"./cron/settle.js";import{applyOverlapPolicies as ne,expireDueCrons as oe}from"./cron/passes.js";import{dueClockCrons as se,acquireCronRunLease as ae,releaseCronRunLease as de,attachCronRunPid as ie,advanceCron as le,setCronState as ue}from"../core/canvas/crons.js";import{emitEvent as L}from"../core/events/emit.js";import{runAppCommand as ce}from"../core/runtime/run-command.js";import{nextSlotAfter as fe}from"../core/wake.js";import{CRON_OUTPUT_HEAD_BYTES as Pe}from"./cron/capture.js";import{cronDaemonInstanceId as Ue,markSelfCanceledCronRun as Fe}from"./cron/live-runs.js";import{recoverStaleCronLeases as Ye}from"./cron/lease-recovery.js";async function me(e,t){const{runId:o,outOfBand:s,startedAtIso:u,finishedAtMs:c,code:d,timedOut:n,processError:f}=t,w=!s&&!n&&f==null&&d===te&&!t.wasReplaced&&!t.wasSelfCanceled;let p,r;return t.wasReplaced?(p={kind:"stated",delivered:"replaced (overlap=replace)"},r="release"):w?(p={kind:"stated",delivered:re},r=await ee(e,u,c)??"release"):(p={kind:"disposed",ctx:{runId:o,startedAtIso:u,exitCode:n?-1:d,timedOut:n,runTimeoutS:e.run_timeout_s,processErrorMessage:f!=null?f.message:null,stdoutHead:t.stdoutHead,stdoutSha256:t.stdoutSha256,stderrHead:t.stderrHead},selfCanceled:t.wasSelfCanceled},r=s?"release":{kind:"clear"}),O(e,{outOfBand:s,outcome:p,record:{runId:o,startedAtIso:u,finishedAtMs:c,durationMs:c-t.startedAtMs,exitCode:n?-1:d,stdoutHead:t.stdoutHead===""?null:t.stdoutHead,stderrHead:f!=null?`run process error: ${f.message}`.slice(0,E):t.stderrHead===""?null:t.stderrHead},lease:r})}i(me,"settleClosedRun");function R(e,t,o,s){const u=Date.now(),c=`${o}: ${s.message}`.slice(0,E);return O(e,{outOfBand:t.outOfBand,outcome:{kind:"disposed",ctx:{runId:t.runId,startedAtIso:t.startedAtIso,exitCode:null,timedOut:!1,runTimeoutS:e.run_timeout_s,processErrorMessage:s.message,stdoutHead:"",stdoutSha256:q,stderrHead:c}},record:{runId:t.runId,startedAtIso:t.startedAtIso,finishedAtMs:u,durationMs:u-t.startedAtMs,exitCode:null,stdoutHead:null,stderrHead:c},lease:"release"})}i(R,"settleUnspawnedRun");async function P(e,t){let o;try{o=fe(e.recur,new Date(t))}catch(s){return L({level:"error",event:"cron.recur.unparseable",error:s,fields:{cron_id:e.cron_id,name:e.name,recur:e.recur}}),await ue(e.cron_id,"paused"),new Error(`unparseable recurrence ${JSON.stringify(e.recur)}: ${s.message} \u2014 this cron cannot be rescheduled until its recurrence is fixed (\`crtr cron cancel\` and re-arm it), so it has been paused.`)}return await le(e.cron_id,o),null}i(P,"advanceRecurrence");function ye(e,t){return B(e,t).settled}i(ye,"executeCron");function B(e,t){const{outOfBand:o}=t;let s=i(()=>{},"admit");const u=new Promise(d=>{s=d}),c=new Promise((d,n)=>{let f=!1,w=i(()=>{},"undo");const p=i(r=>{if(w(),!f){n(r);return}f=!1,de(e.cron_id).then(()=>n(r),m=>{L({level:"error",event:"cron.lease.release_failed",error:m,fields:{cron_id:e.cron_id}}),n(r)})},"fail");(async()=>{const r=Y(),m=Date.now(),_=new Date(m).toISOString(),S={runId:r,outOfBand:o,startedAtIso:_,startedAtMs:m};if(!await ae(e.cron_id,$,_,o,r)){d(null);return}f=!0;const g=await Z(j(e));if(!g.allowed){try{if(!o&&e.recur!=null){const h=await P(e,m);if(h!==null)throw h}}catch(h){R(e,S,"run could not be armed",h).then(d,n);return}const a=Date.now();O(e,{outOfBand:o,outcome:{kind:"refused",reason:g.reason,message:g.message},record:{runId:r,startedAtIso:_,finishedAtMs:a,durationMs:a-m,exitCode:null,stdoutHead:null,stderrHead:`${g.reason}: ${g.message}`.slice(0,E)},lease:"release"}).then(d,n);return}let T;try{if(e.isolated&&W(e.grantee,e.cron_id),{env:T}=await Q(e,r),!o&&e.recur!=null){const a=await P(e,m);if(a!==null)throw a}}catch(a){R(e,S,"run could not be armed",a).then(d,n);return}let M=null,b=!1;const D={runId:r,replaced:!1,selfCanceled:!1,kill:i(()=>{M!==null?M():b=!0},"kill")};J(e.cron_id,D),w=i(()=>C(e.cron_id,r),"undo"),s();const x=z()?{executionId:r,cronId:e.cron_id,grantee:e.grantee,sub:e.sub,grantId:e.grant_id,scopes:e.scopes,originRunId:e.origin_run_id,isolated:e.isolated,anchor:e.anchor_node,uid:await K(e.grantee),rebuilt:!1,refusal:null}:null,I=i(()=>{x!==null&&V(r)},"closeExecution");w=i(()=>{C(e.cron_id,r),I()},"undo"),i(async()=>(x!==null&&await X(x,e.cwd,e.profile),ce({command:e.command,cwd:e.cwd,env:T,app:e.grantee,isolated:e.isolated,principal:{sub:e.sub,grantId:e.grant_id,scopes:e.scopes},...e.isolated?{folder:e.cwd}:{},...x!==null?{cron:{executionId:r,...e.anchor_node===null||e.isolated?{}:{anchorDir:G(e.anchor_node,e.grantee)}}}:e.anchor_node===null||e.isolated?{}:{nodeId:e.anchor_node},timeoutMs:e.run_timeout_s*1e3,headBytes:E})),"launch")().then(async a=>{if(a.pid===null){C(e.cron_id,r),I(),a.completion.then(l=>{R(e,S,"run failed to spawn",l.processError??new Error("bash did not provide a process id")).then(d,n)},n);return}w=i(()=>{C(e.cron_id,r),I(),a.terminate()},"undo");let h=!1;const v=i(()=>{a.completion.then(l=>{const y=D.replaced,U=D.selfCanceled,H=x?.refusal??null;if(C(e.cron_id,r),I(),h){d(null);return}if(H!==null&&!y){const k=Date.now(),F=A(l.stderr,l.stderrTruncated);O(e,{outOfBand:o,outcome:{kind:"refused",reason:H.reason,message:H.message},record:{runId:r,startedAtIso:_,finishedAtMs:k,durationMs:k-m,exitCode:l.exitCode,stdoutHead:A(l.stdout,l.stdoutTruncated)||null,stderrHead:`${H.reason}: ${H.message}
2
+ ${F}`.trim().slice(0,E)},lease:"release"}).then(d,n);return}me(e,{runId:r,outOfBand:o,startedAtIso:_,startedAtMs:m,finishedAtMs:Date.now(),code:l.exitCode,timedOut:l.timedOut,processError:l.processError,stdoutHead:A(l.stdout,l.stdoutTruncated),stderrHead:A(l.stderr,l.stderrTruncated),stdoutSha256:l.stdoutSha256,wasReplaced:y,wasSelfCanceled:U}).then(d,n)},n)},"settleCommand");if(!await ie(e.cron_id,$,_,a.pid)&&!D.selfCanceled){h=!0,a.terminate(),v();return}M=a.terminate,b&&a.terminate(),v()},a=>{C(e.cron_id,r),I(),R(e,S,"run failed to spawn",a).then(d,n)}).catch(p)})().catch(p)});return c.then(s,s),{admitted:u,settled:c}}i(B,"startCron");async function ke(e,t={}){const o=new Date(e).toISOString();await oe(o),await ne(e,o);const s=[];for(const u of await se(o)){const{admitted:c,settled:d}=B(u,{outOfBand:!1}),n=d.then(()=>{});n.catch(()=>{}),await c,s.push(n),t.register?.(n)}for(const u of s)u.catch(()=>{});return s}i(ke,"runDueCrons");export{Pe as CRON_OUTPUT_HEAD_BYTES,Ue as cronDaemonInstanceId,ye as executeCron,Fe as markSelfCanceledCronRun,Ye as recoverStaleCronLeases,ke as runDueCrons,B as startCron};
@@ -1,16 +1,16 @@
1
- var Pe=Object.defineProperty;var a=(t,n)=>Pe(t,"name",{value:n,configurable:!0});import{startPeerOutbox as xe}from"./peer/outbox.js";import{reportMachineStatus as Ie}from"../core/peer/directory.js";import{createPeerRelay as De}from"./peer/relay-service.js";import{writeFileSync as Te,readFileSync as Ce,rmSync as $e,mkdirSync as ee,existsSync as E,chmodSync as Le}from"node:fs";import{createServer as re}from"node:http";import{dirname as Ae}from"node:path";import{envCrtrdTcp as Ne,envDocumentPort as Me}from"../shared/env.js";import{serveCanvasConversationStore as Oe}from"../core/canvas/sessions.js";import{pollRunObservers as Fe}from"./runs/observer.js";import{randomBytes as Ge}from"node:crypto";import{apiSocketPath as He,crtrHome as je}from"../core/canvas/paths.js";import{activeAppUsers as Be}from"../core/spaces/users.js";import{ensureAppSpace as qe,ensureUserFiles as ze}from"../core/spaces/space.js";import{LAUNCHER_SOCKET as x}from"../launcher/spec.js";import{launcherRequest as D}from"../launcher/client.js";import{installLauncherEventSink as We}from"./launcher-events.js";import{initializeEmptyLayout as Ue,layoutNeedsMigration as Ke,socketDir as te}from"../core/layout.js";import{migrateLooseKeys as Je}from"../core/layout-migrate/loose-keys.js";import{relocateProfileFolders as Ve}from"../core/profiles/relocate.js";import{getNode as Qe,listNodesForSupervision as ne,setFrozen as oe}from"../core/canvas/index.js";import{createApiServer as Ye}from"./api/server.js";import{createDocumentListener as Xe}from"./api/document-listener.js";import{documentSecret as Ze}from"./api/document-secret.js";import{createAppListener as er}from"./api/app-listener.js";import{installLocalTerminalGrant as rr}from"../core/grants/local.js";import{onRunEventAppended as tr}from"../core/runs/events.js";import{runNotices as nr}from"./run-notices.js";import{createGrantSync as or,GRANT_SYNC_INTERVAL_S as ir}from"../core/grants/sync.js";import{runRemovalCascades as sr}from"../core/grants/remove.js";import{sweepSandboxes as ar}from"../core/grants/on-sync.js";import{rebuildCronExecutions as cr}from"./cron/run-socket.js";import{hasSyncedGrants as dr}from"../core/grants/mirror.js";import{readConfig as ie}from"../core/config.js";import{reconcileUndeliveredTickets as lr}from"./human/sweep.js";import{resetHandedOffDeliveries as pr}from"../core/canvas/deliveries.js";import{resetHandedOffDaemonActions as mr}from"../core/canvas/daemon-actions.js";import{sweepReviews as fr}from"./review/sweep.js";import{pidfilePath as B}from"./pidfile.js";import{rendererWarning as ur}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as hr}from"./supervise-cadence.js";import{createResumeDetector as vr}from"./resume-detector.js";import{setFatalFaultAnnouncer as wr}from"../core/canvas/recovery.js";import{BrokerSupervisionReconciler as gr}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as yr}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as Sr}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as _r}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as br}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as kr}from"./reconcilers/delivery-lane.js";import{ActionLaneReconciler as Er}from"./reconcilers/action-lane.js";import{endLiveExecution as Rr,migrateLegacyExecutionIdentities as Pr}from"../core/canvas/executions.js";import{revokePriorEpochNodeTokens as xr}from"../core/canvas/node-tokens.js";import{PendingReviewSubmitReconciler as Ir}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as Dr}from"./reconcilers/storage-maintenance.js";import{StorageDueWorkReconciler as Tr}from"./reconcilers/storage-due-work.js";import{BashDeadlineReconciler as Cr}from"./reconcilers/bash-deadline.js";import{FaultRetryBackstopReconciler as $r}from"./reconcilers/fault-retry-backstop.js";import{StructuredRequestReconciler as Lr}from"./reconcilers/structured-request-lane.js";import{reconcileStructuredRequestSidecars as Ar}from"./structured-requests/boot.js";import{captureLivenessSnapshot as se,capturePidCommand as Nr,captureTeardownSnapshot as ae,isPidAlive as Mr,isAnyPidAlive as ce,killProcessTreePids as de}from"../core/canvas/pid.js";import{bindFleet as Or,boundFleet as Fr}from"../core/runtime/fleet.js";import{bindDaemonControl as Gr,clearDaemonControl as Hr}from"./control.js";import{execDaemon as jr,spawnDaemon as Br}from"./manage.js";import{reconcileAndMigrateBoot as qr}from"../core/canvas/boot.js";import{resolveInstallId as zr}from"../core/canvas/install-id.js";import{setInstallId as Wr}from"../core/runtime/nodes.js";import{claimDaemonOwnership as Ur,releaseDaemonOwnership as le}from"../core/canvas/daemon-owner.js";import{migrate as Kr,openDb as pe,withCanvasWrite as Jr,bindDaemonCanvasOpenHook as Vr,clearDaemonCanvasOpenHook as me}from"../core/canvas/db.js";import{brokerSignalBus as q}from"./broker-signals/bus.js";import{brokerSignalStreams as Qr}from"./api/handlers/broker-signals.js";import{reconcilePackages as Yr}from"../core/graph/package-reconcile.js";import{startRepoSync as Xr}from"../core/graph/repo-sync/index.js";import{prewarmRecentRecipes as Zr,reapStaleSpares as et}from"../core/runtime/warm-pool.js";import{DaemonFleet as rt}from"./fleet.js";import{BOOT_MIGRATIONS as tt}from"./boot-migrations.js";import{applyJoinedOwner as nt}from"./joined-owner.js";import{emitEvent as f}from"../core/events/emit.js";import{operationIdContext as _}from"../core/events/operation-id.js";import{bindDaemonEventSource as ot}from"../core/events/source.js";import{activateCanvasImport as it,MigrationBlockedError as st,runForcedCanvasImport as at}from"../migrations/activation.js";import{convertLegacyProviderStore as ct,convertLegacyScopedStore as dt}from"../core/scoped-state/migrate.js";import{userScopeRoot as lt}from"../core/scope.js";import{secretsDir as pt}from"../core/layout.js";function z(t,n){return t.includes(` --canvas-home ${n} `)}a(z,"brokerCommandDeclaresCanvasHome");function W(t){return/ --epoch (\S+) /.exec(t)?.[1]??null}a(W,"brokerCommandEpoch");const mt=5e3,fe=150;async function ft(t){const n=se();if(n===null)throw f({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness"}}),new Error("prior-epoch broker census could not capture the process table");const c=je(),u=[];for(const[s,m]of n.processes){const y=m.command;if(m.zombie||!y.includes("broker-cli.js")||!z(y,c)||W(y)===t)continue;const b=y.trim().split(/\s+/).at(-1)??"";b===""||b.endsWith("broker-cli.js")||u.push({pid:s,nodeId:b})}let h=0;const o=[];for(const s of u){const m=Nr(s.pid);if(m===null||!m.includes("broker-cli.js")||!z(m,c)||W(m)===t||m.trim().split(/\s+/).at(-1)!==s.nodeId)continue;const y=ae(s.pid,null);if(!y.reused){try{process.platform==="linux"&&E(x)?await D({operation:"stop",pid:s.pid}):process.kill(s.pid,"SIGTERM")}catch{continue}h++,o.push({pid:s.pid,snap:y})}}const g=Date.now()+mt;for(;Date.now()<g&&o.some(s=>ce(s.snap.tree.length>0?s.snap.tree:[s.pid]));)await new Promise(s=>setTimeout(s,fe));let w=0;for(const s of o){const m=s.snap.tree.length>0?s.snap.tree:[s.pid];ce(m)&&(process.platform==="linux"&&E(x)?await D({operation:"stop",pid:s.pid}):de(m,"SIGKILL",s.snap.identities),w++)}w>0&&await new Promise(s=>setTimeout(s,fe));const d=se();if(d===null)throw f({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness",stage:"final"}}),new Error("prior-epoch broker census could not capture the final process table");const p=[];for(const[s,m]of d.processes){const y=m.command;m.zombie||!y.includes("broker-cli.js")||z(y,c)&&W(y)!==t&&p.push(s)}if(p.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${p.join(", ")}`);f({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:u.length,sigtermed:h,sigkilled:w}})}a(ft,"reapPriorEpochBrokers");const ut=5e3;async function ht(t){const n=Array.from(t.entries());if(n.length===0)return;for(const[o]of n){const g=Qe(o)?.status;(g==="active"||g==="idle")&&oe(o,new Date().toISOString())}const c=n.map(([,o])=>({pid:o.pid,snap:ae(o.pid,null),exited:o.handle.exited}));for(const o of c)if(!o.snap.reused)try{process.platform==="linux"&&E(x)?await D({operation:"stop",pid:o.pid}):process.kill(o.pid,"SIGTERM")}catch{}const u=new Promise(o=>{setTimeout(o,ut).unref()});await Promise.allSettled(c.map(o=>Promise.race([o.exited.then(()=>{}),u])));const h=[];for(const o of c)Mr(o.pid)&&(process.platform==="linux"&&E(x)?await D({operation:"stop",pid:o.pid}):de(o.snap.tree.length>0?o.snap.tree:[o.pid],"SIGKILL",o.snap.identities),h.push(o));await Promise.all(h.map(o=>o.exited));for(const[o]of n)Rr(o,{reason:"daemon-teardown"});f({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:c.length,sigkilled:h.length}})}a(ht,"teardownFleet");function ue(){ee(Ae(B()),{recursive:!0}),Te(B(),String(process.pid),"utf8")}a(ue,"writePidfile");function he(t){return typeof t=="object"&&t!==null&&t.code==="ENOENT"}a(he,"isMissingPathError");function ve(t){const n=B();let c;try{c=Ce(n,"utf8")}catch(u){if(he(u))return;throw u}if(c.trim()!==String(t))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${t})`);try{$e(n)}catch(u){if(he(u))return;throw u}}a(ve,"removeOwnedPidfileMirror");const vt={acceptsDetachedWork:a(()=>!0,"acceptsDetachedWork"),registerDetached:a(t=>{t.catch(()=>{})},"registerDetached")},O=new gr;wr(t=>O.handleFatalFault(t,!1));const wt=new yr,gt=new Sr,yt=new _r,St=new br,_t=new kr,bt=new Er,kt=new Ir,Et=new Dr,Rt=new Tr,Pt=new Cr,xt=new $r,It=new Lr;async function Dt(t=Date.now(),n=vt){const c=Fr(),u=await O.runFleetPreamble(c);let h,o;try{const w=ne();h=w.filter(d=>d.status==="active"||d.status==="idle"),o=w.filter(d=>d.status==="done"||d.status==="canceled"||d.status==="dead")}catch(w){f({level:"error",event:"canvas.node_list.failed",error:w});return}await O.run(t,{rows:h,fleet:c,lifecycle:n}),wt.run(t,{rows:h});const g=await gt.run(t,{rows:[...h,...o],fleet:c});yt.run(t),It.run(t),St.run(t,{lifecycle:n}),_t.run(t,{lifecycle:n}),bt.run(t,{lifecycle:n}),kt.run(t,{lifecycle:n}),Et.run(t,{lifecycle:n,fleet:c}),Rt.run(t,{lifecycle:n}),Fe(),xt.run(t,{fleet:c,lifecycle:n}),await Pt.run(t,{rows:h}),O.warnIfSaturated({fleet:c,lifecycle:n,thresholds:u,frozen:g})}a(Dt,"superviseTick");async function Tt(t){ee(te(),{recursive:!0,mode:493}),process.platform==="linux"&&Le(te(),493);const n=He();if(E(n))throw new Error(`layout refusal cannot bind occupied socket: ${n}`);const c=re((d,p)=>{if(d.method==="GET"&&d.url==="/healthz"){p.writeHead(200,{"content-type":"application/json; charset=utf-8"}),p.end(JSON.stringify({ok:!1,daemon_up:!0,store_accessible:!1,brokers_reconciled:!1,startup_phase:"blocked",startup_blocked:"layout_migration_required"}));return}p.writeHead(503,{"content-type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:{code:"layout_migration_required",message:"run crtr sys migrate while the runtime is offline",type:"server_error",origin:"runtime",retryable:!1}}))});await new Promise((d,p)=>{c.once("error",p),c.listen(n,()=>{c.off("error",p),d()})});let u;const h=t.tcp??Ne();if(h){const d=/^(.*):(\d+)$/.exec(h);if(!d||Number(d[2])>65535)throw new Error(`invalid refusal TCP address: ${h}`);const p=re(c.listeners("request")[0]);await new Promise((s,m)=>{p.once("error",m),p.listen(Number(d[2]),d[1],()=>{p.off("error",m),s()})}),u=p}ue();let o;const g=a(()=>(o??=(async()=>{c.closeAllConnections(),u?.closeAllConnections(),await Promise.all([c,u].filter(d=>d!==void 0).map(d=>new Promise((p,s)=>d.close(m=>m?s(m):p())))),ve(process.pid),process.off("SIGINT",w),process.off("SIGTERM",w)})(),o),"cleanup"),w=a(()=>{g().then(()=>process.exit(0),d=>{process.stderr.write(`[crtrd] layout refusal cleanup failed: ${String(d)}
2
- `),process.exit(1)})},"onSignal");return process.on("SIGINT",w),process.on("SIGTERM",w),g}a(Tt,"serveLayoutRefusal");async function Ct(t={}){if(Ke())return Tt(t);Ue();const n=Ur(Ge(16).toString("hex"));if(!n.claimed){if(n.reason==="incumbent_alive")process.stderr.write(`[crtrd] already running (pid ${n.incumbentPid??"?"})
1
+ var Pe=Object.defineProperty;var s=(t,n)=>Pe(t,"name",{value:n,configurable:!0});import{startPeerOutbox as xe}from"./peer/outbox.js";import{reportMachineStatus as Ie}from"../core/peer/directory.js";import{createPeerRelay as De}from"./peer/relay-service.js";import{writeFileSync as Te,readFileSync as Ce,rmSync as $e,mkdirSync as ee,existsSync as E,chmodSync as Le}from"node:fs";import{createServer as re}from"node:http";import{dirname as Ae}from"node:path";import{envCrtrdTcp as Ne,envDocumentPort as Me}from"../shared/env.js";import{serveCanvasConversationStore as Oe}from"../core/canvas/sessions.js";import{pollRunObservers as Fe}from"./runs/observer.js";import{randomBytes as Ge}from"node:crypto";import{apiSocketPath as He,crtrHome as je}from"../core/canvas/paths.js";import{activeAppUsers as Be}from"../core/spaces/users.js";import{ensureAppSpace as qe,ensureUserFiles as ze}from"../core/spaces/space.js";import{LAUNCHER_SOCKET as x}from"../launcher/spec.js";import{launcherRequest as D}from"../launcher/client.js";import{installLauncherEventSink as We}from"./launcher-events.js";import{initializeEmptyLayout as Ue,layoutNeedsMigration as Ke,socketDir as te}from"../core/layout.js";import{migrateLooseKeys as Je}from"../core/layout-migrate/loose-keys.js";import{relocateProfileFolders as Ve}from"../core/profiles/relocate.js";import{getNode as Qe,listNodesForSupervision as ne,setFrozen as oe}from"../core/canvas/index.js";import{createApiServer as Ye}from"./api/server.js";import{createDocumentListener as Xe}from"./api/document-listener.js";import{documentSecret as Ze}from"./api/document-secret.js";import{createAppListener as er}from"./api/app-listener.js";import{installLocalTerminalGrant as rr}from"../core/grants/local.js";import{onRunEventAppended as tr}from"../core/runs/events.js";import{runNotices as nr}from"./run-notices.js";import{createGrantSync as or,GRANT_SYNC_INTERVAL_S as ir}from"../core/grants/sync.js";import{runRemovalCascades as ar}from"../core/grants/remove.js";import{sweepSandboxes as sr}from"../core/grants/on-sync.js";import{rebuildCronExecutions as cr}from"./cron/run-socket.js";import{hasSyncedGrants as dr}from"../core/grants/mirror.js";import{readConfig as ie}from"../core/config.js";import{reconcileUndeliveredTickets as lr}from"./human/sweep.js";import{resetHandedOffDeliveries as pr}from"../core/canvas/deliveries.js";import{resetHandedOffDaemonActions as mr}from"../core/canvas/daemon-actions.js";import{sweepReviews as fr}from"./review/sweep.js";import{pidfilePath as B}from"./pidfile.js";import{rendererWarning as ur}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as hr}from"./supervise-cadence.js";import{createResumeDetector as wr}from"./resume-detector.js";import{setFatalFaultAnnouncer as vr}from"../core/canvas/recovery.js";import{BrokerSupervisionReconciler as gr}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as yr}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as Sr}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as _r}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as br}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as kr}from"./reconcilers/delivery-lane.js";import{ActionLaneReconciler as Er}from"./reconcilers/action-lane.js";import{endLiveExecution as Rr,migrateLegacyExecutionIdentities as Pr}from"../core/canvas/executions.js";import{revokePriorEpochNodeTokens as xr}from"../core/canvas/node-tokens.js";import{PendingReviewSubmitReconciler as Ir}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as Dr}from"./reconcilers/storage-maintenance.js";import{StorageDueWorkReconciler as Tr}from"./reconcilers/storage-due-work.js";import{BashDeadlineReconciler as Cr}from"./reconcilers/bash-deadline.js";import{FaultRetryBackstopReconciler as $r}from"./reconcilers/fault-retry-backstop.js";import{StructuredRequestReconciler as Lr}from"./reconcilers/structured-request-lane.js";import{reconcileStructuredRequestSidecars as Ar}from"./structured-requests/boot.js";import{captureLivenessSnapshot as ae,capturePidCommand as Nr,captureTeardownSnapshot as se,isPidAlive as Mr,isAnyPidAlive as ce,killProcessTreePids as de}from"../core/canvas/pid.js";import{bindFleet as Or,boundFleet as Fr}from"../core/runtime/fleet.js";import{bindDaemonControl as Gr,clearDaemonControl as Hr}from"./control.js";import{execDaemon as jr,spawnDaemon as Br}from"./manage.js";import{reconcileAndMigrateBoot as qr}from"../core/canvas/boot.js";import{resolveInstallId as zr}from"../core/canvas/install-id.js";import{setInstallId as Wr}from"../core/runtime/nodes.js";import{claimDaemonOwnership as Ur,releaseDaemonOwnership as le}from"../core/canvas/daemon-owner.js";import{migrate as Kr,bindDaemonCanvasOpenHook as Jr,clearDaemonCanvasOpenHook as pe,openDb as me,withCanvasWrite as Vr}from"../core/canvas/db.js";import{brokerSignalBus as q}from"./broker-signals/bus.js";import{brokerSignalStreams as Qr}from"./api/handlers/broker-signals.js";import{reconcilePackages as Yr}from"../core/graph/package-reconcile.js";import{startRepoSync as Xr}from"../core/graph/repo-sync/index.js";import{prewarmRecentRecipes as Zr,reapStaleSpares as et}from"../core/runtime/warm-pool.js";import{DaemonFleet as rt}from"./fleet.js";import{BOOT_MIGRATIONS as tt}from"./boot-migrations.js";import{applyJoinedOwner as nt}from"./joined-owner.js";import{emitEvent as f}from"../core/events/emit.js";import{operationIdContext as _}from"../core/events/operation-id.js";import{bindDaemonEventSource as ot}from"../core/events/source.js";import{activateCanvasImport as it,MigrationBlockedError as at,runForcedCanvasImport as st}from"../migrations/activation.js";import{convertLegacyProviderStore as ct,convertLegacyScopedStore as dt}from"../core/scoped-state/migrate.js";import{userScopeRoot as lt}from"../core/scope.js";import{secretsDir as pt}from"../core/layout.js";function z(t,n){return t.includes(` --canvas-home ${n} `)}s(z,"brokerCommandDeclaresCanvasHome");function W(t){return/ --epoch (\S+) /.exec(t)?.[1]??null}s(W,"brokerCommandEpoch");const mt=5e3,fe=150;async function ft(t){const n=ae();if(n===null)throw f({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness"}}),new Error("prior-epoch broker census could not capture the process table");const c=je(),u=[];for(const[a,m]of n.processes){const y=m.command;if(m.zombie||!y.includes("broker-cli.js")||!z(y,c)||W(y)===t)continue;const b=y.trim().split(/\s+/).at(-1)??"";b===""||b.endsWith("broker-cli.js")||u.push({pid:a,nodeId:b})}let h=0;const o=[];for(const a of u){const m=Nr(a.pid);if(m===null||!m.includes("broker-cli.js")||!z(m,c)||W(m)===t||m.trim().split(/\s+/).at(-1)!==a.nodeId)continue;const y=se(a.pid,null);if(!y.reused){try{process.platform==="linux"&&E(x)?await D({operation:"stop",pid:a.pid}):process.kill(a.pid,"SIGTERM")}catch{continue}h++,o.push({pid:a.pid,snap:y})}}const g=Date.now()+mt;for(;Date.now()<g&&o.some(a=>ce(a.snap.tree.length>0?a.snap.tree:[a.pid]));)await new Promise(a=>setTimeout(a,fe));let v=0;for(const a of o){const m=a.snap.tree.length>0?a.snap.tree:[a.pid];ce(m)&&(process.platform==="linux"&&E(x)?await D({operation:"stop",pid:a.pid}):de(m,"SIGKILL",a.snap.identities),v++)}v>0&&await new Promise(a=>setTimeout(a,fe));const d=ae();if(d===null)throw f({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness",stage:"final"}}),new Error("prior-epoch broker census could not capture the final process table");const p=[];for(const[a,m]of d.processes){const y=m.command;m.zombie||!y.includes("broker-cli.js")||z(y,c)&&W(y)!==t&&p.push(a)}if(p.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${p.join(", ")}`);f({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:u.length,sigtermed:h,sigkilled:v}})}s(ft,"reapPriorEpochBrokers");const ut=5e3;async function ht(t){const n=Array.from(t.entries());if(n.length===0)return;for(const[o]of n){const g=(await Qe(o))?.status;(g==="active"||g==="idle")&&await oe(o,new Date().toISOString())}const c=n.map(([,o])=>({pid:o.pid,snap:se(o.pid,null),exited:o.handle.exited}));for(const o of c)if(!o.snap.reused)try{process.platform==="linux"&&E(x)?await D({operation:"stop",pid:o.pid}):process.kill(o.pid,"SIGTERM")}catch{}const u=new Promise(o=>{setTimeout(o,ut).unref()});await Promise.allSettled(c.map(o=>Promise.race([o.exited.then(()=>{}),u])));const h=[];for(const o of c)Mr(o.pid)&&(process.platform==="linux"&&E(x)?await D({operation:"stop",pid:o.pid}):de(o.snap.tree.length>0?o.snap.tree:[o.pid],"SIGKILL",o.snap.identities),h.push(o));await Promise.all(h.map(o=>o.exited));for(const[o]of n)await Rr(o,{reason:"daemon-teardown"});f({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:c.length,sigkilled:h.length}})}s(ht,"teardownFleet");function ue(){ee(Ae(B()),{recursive:!0}),Te(B(),String(process.pid),"utf8")}s(ue,"writePidfile");function he(t){return typeof t=="object"&&t!==null&&t.code==="ENOENT"}s(he,"isMissingPathError");function we(t){const n=B();let c;try{c=Ce(n,"utf8")}catch(u){if(he(u))return;throw u}if(c.trim()!==String(t))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${t})`);try{$e(n)}catch(u){if(he(u))return;throw u}}s(we,"removeOwnedPidfileMirror");const wt={acceptsDetachedWork:s(()=>!0,"acceptsDetachedWork"),registerDetached:s(t=>{t.catch(()=>{})},"registerDetached")},O=new gr;vr(t=>O.handleFatalFault(t,!1));const vt=new yr,gt=new Sr,yt=new _r,St=new br,_t=new kr,bt=new Er,kt=new Ir,Et=new Dr,Rt=new Tr,Pt=new Cr,xt=new $r,It=new Lr;async function Dt(t=Date.now(),n=wt){const c=Fr(),u=await O.runFleetPreamble(c);let h,o;try{const v=await ne();h=v.filter(d=>d.status==="active"||d.status==="idle"),o=v.filter(d=>d.status==="done"||d.status==="canceled"||d.status==="dead")}catch(v){f({level:"error",event:"canvas.node_list.failed",error:v});return}await O.run(t,{rows:h,fleet:c,lifecycle:n}),await vt.run(t,{rows:h});const g=await gt.run(t,{rows:[...h,...o],fleet:c});await yt.run(t),await It.run(t),await St.run(t,{lifecycle:n}),await _t.run(t,{lifecycle:n}),await bt.run(t,{lifecycle:n}),await kt.run(t,{lifecycle:n}),await Et.run(t,{lifecycle:n,fleet:c}),Rt.run(t,{lifecycle:n}),await Fe(),xt.run(t,{fleet:c,lifecycle:n}),await Pt.run(t,{rows:h}),O.warnIfSaturated({fleet:c,lifecycle:n,thresholds:u,frozen:g})}s(Dt,"superviseTick");async function Tt(t){ee(te(),{recursive:!0,mode:493}),process.platform==="linux"&&Le(te(),493);const n=He();if(E(n))throw new Error(`layout refusal cannot bind occupied socket: ${n}`);const c=re((d,p)=>{if(d.method==="GET"&&d.url==="/healthz"){p.writeHead(200,{"content-type":"application/json; charset=utf-8"}),p.end(JSON.stringify({ok:!1,daemon_up:!0,store_accessible:!1,brokers_reconciled:!1,startup_phase:"blocked",startup_blocked:"layout_migration_required"}));return}p.writeHead(503,{"content-type":"application/json; charset=utf-8"}),p.end(JSON.stringify({error:{code:"layout_migration_required",message:"run crtr sys migrate while the runtime is offline",type:"server_error",origin:"runtime",retryable:!1}}))});await new Promise((d,p)=>{c.once("error",p),c.listen(n,()=>{c.off("error",p),d()})});let u;const h=t.tcp??Ne();if(h){const d=/^(.*):(\d+)$/.exec(h);if(!d||Number(d[2])>65535)throw new Error(`invalid refusal TCP address: ${h}`);const p=re(c.listeners("request")[0]);await new Promise((a,m)=>{p.once("error",m),p.listen(Number(d[2]),d[1],()=>{p.off("error",m),a()})}),u=p}ue();let o;const g=s(()=>(o??=(async()=>{c.closeAllConnections(),u?.closeAllConnections(),await Promise.all([c,u].filter(d=>d!==void 0).map(d=>new Promise((p,a)=>d.close(m=>m?a(m):p())))),we(process.pid),process.off("SIGINT",v),process.off("SIGTERM",v)})(),o),"cleanup"),v=s(()=>{g().then(()=>process.exit(0),d=>{process.stderr.write(`[crtrd] layout refusal cleanup failed: ${String(d)}
2
+ `),process.exit(1)})},"onSignal");return process.on("SIGINT",v),process.on("SIGTERM",v),g}s(Tt,"serveLayoutRefusal");async function Ct(t={}){if(Ke())return Tt(t);Ue();const n=await Ur(Ge(16).toString("hex"));if(!n.claimed){if(n.reason==="incumbent_alive")process.stderr.write(`[crtrd] already running (pid ${n.incumbentPid??"?"})
3
3
  `);else{const r=[n.incumbentPid!==void 0?`pid ${n.incumbentPid}`:void 0,n.verdict!==void 0?`verdict ${n.verdict}`:void 0].filter(i=>i!==void 0),e=r.length>0?` (${r.join(", ")})`:"";process.stderr.write(`[crtrd] claim lost: ${n.reason}${e}
4
4
  `),n.reason==="own_identity_indeterminate"&&process.stderr.write("[crtrd] cannot read its own process identity. crouter needs /proc on Linux, or the `ps` command elsewhere (Debian/Ubuntu: apt-get install procps).\n"),(n.reason==="own_identity_indeterminate"||n.reason==="incumbent_malformed")&&(process.exitCode=1)}return async()=>{}}const c=n.claim;let u=null;try{await ft(c.token),dt({kind:"user",root:lt()});for(const e of Ve())process.stderr.write(`[crtrd] ${e}
5
5
  `);if(process.platform==="darwin"){const{readConfig:e,updateConfig:i}=await import("../core/config.js");if(e("user").paths?.user_files===void 0){const{homedir:l}=await import("node:os");i("user",S=>{S.paths??={},S.paths.user_files??=l()})}}await ct(pt());for(const e of Je())process.stderr.write(`[crtrd] ${e}
6
- `);Kr(pe()),Vr(e=>q.install(e));const r=Jr(e=>Yr(e));for(const e of r.conflicts)process.stderr.write(`[crtrd] plugin documents not reconciled: ${e.message}
6
+ `);Kr((await me()).raw),Jr(e=>q.install(e));const r=await Vr(async e=>await Yr(e));for(const e of r.conflicts)process.stderr.write(`[crtrd] plugin documents not reconciled: ${e.message}
7
7
  `);for(const e of r.invalid)process.stderr.write(`[crtrd] package file is not a document: ${e.path}: ${e.error}
8
8
  `);for(const e of r.quarantined)process.stderr.write(`[crtrd] plugin "${e.name}" has a damaged ${e.file} (${e.reason}); ${e.movedTo!==void 0?`moved to ${e.movedTo}`:"left in place and skipped"}
9
9
  `);for(const e of r.kinds.refused)process.stderr.write(`[crtrd] plugin "${e.plugin}" kind ${e.kind} not registered: ${e.message}
10
10
  `);for(const e of r.kinds.invalid)process.stderr.write(`[crtrd] plugin "${e.plugin}" declares invalid object kinds or scopes; no kinds registered and no app token: ${e.error}
11
- `);u=nt(),process.platform==="linux"&&E(x)&&(We(),await D({operation:"users.sync",users:Be()})),xr(c.token)}catch(r){me(),q.close();try{const{released:e}=le(c);if(!e)throw new Error("daemon ownership claim was not released")}catch(e){throw new AggregateError([r,e],"daemon startup failed and cleanup also failed")}throw r}let h=!0,o,g=Promise.resolve(),w=!1,d,p;const s=new Set;let m=!1,y=!1,b,A,F,U=!1,N,T,C,$,G;const we=vr();let R,v={phase:"initializing",message:"daemon startup is running the canvas import and normal services are unavailable",blockerPaths:[]},I="initial startup activation",ge=null;function ye(){return v.phase==="ready"?null:{phase:v.phase,message:v.message,blockerPaths:v.blockerPaths}}a(ye,"startupBlock");function k(r){s.add(r),r.finally(()=>{s.delete(r)}).catch(()=>{})}a(k,"registerDetached");const K={acceptsDetachedWork:a(()=>h,"acceptsDetachedWork"),registerDetached:k};Xr(K,pe);async function Se(){try{h=!1,Qr.close(),me(),q.close(),d!==void 0&&(clearInterval(d),d=void 0),C!==void 0&&(clearInterval(C),C=void 0),G?.(),G=void 0;let r;do r=g,await r;while(r!==g);for(;s.size>0;)await Promise.allSettled([...s]);if(p!==void 0&&(await ht(p),p.dispose()),F!==void 0&&await F.close(),A!==void 0&&!U&&(U=!0,await A.close()),$!==void 0){const e=$;$=void 0,await e.stop()}if(T!==void 0){const e=T;T=void 0,await e.close()}if(N!==void 0){const e=N;N=void 0,await e.close()}if(m||(ve(process.pid),m=!0),m&&!y){const{released:e}=le(c);if(!e)throw new Error("daemon ownership claim was not released");y=!0}}finally{Hr(),process.off("SIGINT",Q),process.off("SIGTERM",Y),process.off("exit",X)}}a(Se,"cleanupAttempt");const M=1e3;let J=!1;function _e(){return J?{graceMs:M}:(J=!0,_.fresh(()=>{f({level:"info",event:"daemon.handover.armed",fields:{pid:process.pid,grace_ms:M}})}),setTimeout(()=>{be()},M),{graceMs:M})}a(_e,"requestHandover");async function be(){try{await P()}catch(r){const e=r instanceof Error?r.stack??r.message:String(r);process.stderr.write(`[crtrd] handover cleanup failed:
11
+ `);u=await nt(),process.platform==="linux"&&E(x)&&(We(),await D({operation:"users.sync",users:await Be()})),await xr(c.token)}catch(r){pe(),q.close();try{const{released:e}=await le(c);if(!e)throw new Error("daemon ownership claim was not released")}catch(e){throw new AggregateError([r,e],"daemon startup failed and cleanup also failed")}throw r}let h=!0,o,g=Promise.resolve(),v=!1,d,p;const a=new Set;let m=!1,y=!1,b,A,F,U=!1,N,T,C,$,G;const ve=wr();let R,w={phase:"initializing",message:"daemon startup is running the canvas import and normal services are unavailable",blockerPaths:[]},I="initial startup activation",ge=null;function ye(){return w.phase==="ready"?null:{phase:w.phase,message:w.message,blockerPaths:w.blockerPaths}}s(ye,"startupBlock");function k(r){a.add(r),r.finally(()=>{a.delete(r)}).catch(()=>{})}s(k,"registerDetached");const K={acceptsDetachedWork:s(()=>h,"acceptsDetachedWork"),registerDetached:k};await Xr(K,me);async function Se(){try{h=!1,Qr.close(),pe(),q.close(),d!==void 0&&(clearInterval(d),d=void 0),C!==void 0&&(clearInterval(C),C=void 0),G?.(),G=void 0;let r;do r=g,await r;while(r!==g);for(;a.size>0;)await Promise.allSettled([...a]);if(p!==void 0&&(await ht(p),p.dispose()),F!==void 0&&await F.close(),A!==void 0&&!U&&(U=!0,await A.close()),$!==void 0){const e=$;$=void 0,await e.stop()}if(T!==void 0){const e=T;T=void 0,await e.close()}if(N!==void 0){const e=N;N=void 0,await e.close()}if(m||(we(process.pid),m=!0),m&&!y){const{released:e}=await le(c);if(!e)throw new Error("daemon ownership claim was not released");y=!0}}finally{Hr(),process.off("SIGINT",Q),process.off("SIGTERM",Y),process.off("exit",X)}}s(Se,"cleanupAttempt");const M=1e3;let J=!1;function _e(){return J?{graceMs:M}:(J=!0,_.fresh(()=>{f({level:"info",event:"daemon.handover.armed",fields:{pid:process.pid,grace_ms:M}})}),setTimeout(()=>{be()},M),{graceMs:M})}s(_e,"requestHandover");async function be(){try{await P()}catch(r){const e=r instanceof Error?r.stack??r.message:String(r);process.stderr.write(`[crtrd] handover cleanup failed:
12
12
  ${e}
13
13
  `),process.exit(1)}try{process.platform==="linux"&&E(x)&&(await D({operation:"daemon.handover"}),process.exit(0)),process.pid===1&&await jr();const r=await Br({waitForJoinLock:!0});_.fresh(()=>{f({level:"info",event:"daemon.handover.completed",fields:{predecessor_pid:process.pid,successor_pid:r.pid??r.existing_pid??null,spawned:r.started}})})}catch(r){_.fresh(()=>{f({level:"error",event:"daemon.handover.successor_failed",error:r})});const e=r instanceof Error?r.message:String(r);process.stderr.write(`[crtrd] handover successor failed to start: ${e}
14
- `),process.exit(1)}process.exit(0)}a(be,"performHandover");function P(){if(b!==void 0)return b;const r=Se();return b=r,r.then(()=>{b===r&&(b=void 0)},()=>{b===r&&(b=void 0)}),r}a(P,"requestCleanup");async function V(r){try{await P(),process.exit(0)}catch(e){process.exitCode=1;const i=e instanceof Error?e.stack??`${e.name}: ${e.message}`:String(e);process.stderr.write(`[crtrd] ${r} cleanup failed:
14
+ `),process.exit(1)}process.exit(0)}s(be,"performHandover");function P(){if(b!==void 0)return b;const r=Se();return b=r,r.then(()=>{b===r&&(b=void 0)},()=>{b===r&&(b=void 0)}),r}s(P,"requestCleanup");async function V(r){try{await P(),process.exit(0)}catch(e){process.exitCode=1;const i=e instanceof Error?e.stack??`${e.name}: ${e.message}`:String(e);process.stderr.write(`[crtrd] ${r} cleanup failed:
15
15
  ${i}
16
- `),process.exit(1)}}a(V,"handleSignal");function Q(){V("SIGINT")}a(Q,"onSigint");function Y(){V("SIGTERM")}a(Y,"onSigterm");function X(){P().catch(()=>{})}a(X,"onExit");function H(r){h&&(g=g.then(r).then(()=>{},e=>{_.fresh(()=>{f({level:"error",event:"daemon.lane_job.failed",error:e})})}))}a(H,"enqueue");function Z(){!h||w||(we.check()&&R&&(f({level:"info",event:"daemon.resume.detected"}),k(R().catch(()=>{}))),w=!0,H(async()=>{if(w=!1,!!h)try{await Dt(Date.now(),K)}catch(r){_.fresh(()=>{f({level:"error",event:"daemon.tick.failed",error:r})})}}))}a(Z,"enqueueTick");let L=null;async function ke(){if(L!==null)throw{status:500,code:"admission_failed",message:`daemon admission previously failed: ${L instanceof Error?L.message:String(L)}`};if(v.phase==="ready")return{admitted:!1,already_admitted:!0,startup_phase:"ready"};if(v.phase!=="prepared"&&v.phase!=="recovering")throw{status:409,code:"not_prepared",message:v.message};const r=v.phase==="prepared";try{return await j(),v={phase:"ready",message:"",blockerPaths:[]},r?{admitted:!0,already_admitted:!1,startup_phase:"ready"}:{admitted:!1,already_admitted:!0,startup_phase:"ready"}}catch(e){throw L=e,{status:500,code:"admission_failed",message:`daemon admission failed: ${e instanceof Error?e.message:String(e)}`}}}a(ke,"admitStartup");async function Ee(r){if(I!==null)throw{status:409,code:"migration_in_progress",message:`the canvas import is already running (${I})`};I="repair";try{const e=await at({dryRun:r.dryRun});if(r.dryRun||e.pending||v.phase!=="blocked")return{result:e,resumed:!1};if(t.prepare)return v={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]},{result:e,resumed:!1};try{return await j(),v={phase:"ready",message:"",blockerPaths:[]},{result:e,resumed:!0}}catch(i){const l=i instanceof Error?i.message:String(i);return setTimeout(()=>{P().catch(()=>{})},1e3),{result:e,resumed:!1,resumeError:l}}}finally{I=null}}a(Ee,"repairMigrations");async function Re(){o=t.intervalMs??hr;const r=c.token;p=new rt({epoch:r,enqueue:H}),Or(p),v={phase:"recovering",message:"daemon startup recovery is running and normal services are unavailable",blockerPaths:[]},_.fresh(()=>{f({level:"info",event:"daemon.started",fields:{pid:process.pid,interval_ms:o}})});const e=zr();if(Wr(e),_.fresh(()=>{f({level:"info",event:"daemon.install_id.resolved",fields:{install_id:e}})}),_.fresh(()=>{let i;try{i=ur()}catch{return}i!==null&&f({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:i.slice(0,2048)}})}),await _.fresh(async()=>{await fr(),await lr(),pr(Date.now()),mr(Date.now())}),_.fresh(()=>{const{reconcile:i,migrated:l}=qr(Pr);i.changed&&f({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:i.cleared.length,same_boot_proven:i.sameBootProven}}),l.length>0&&f({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:l.length}})}),_.fresh(()=>{for(const i of ne())i.status!=="active"||i.pi_pid!=null||i.frozen_at!=null||i.respawn_not_before!=null||(oe(i.node_id,new Date().toISOString()),f({level:"warn",event:"daemon.startup.launch_debt_recorded",node_id:i.node_id}))}),_.fresh(()=>{Ar();for(const i of tt){const l=i.apply();l.changed&&f({level:"info",event:"daemon.boot_migration.applied",fields:{migration:i.id,...l.summary}})}}),k(cr()),R){const i=a(()=>{k(R().catch(()=>{})),k(Ie().then(l=>$?.observe(l)).then(()=>{},l=>{f({level:"warn",event:"daemon.peer.status_failed",error:l})}))},"refresh");k(sr().catch(()=>{})),k(ar().then(({completion:l})=>l).catch(l=>{f({level:"error",event:"daemon.grants.sweep_failed",error:l})})),i(),C=setInterval(i,ir*1e3),C.unref(),G=xe({joined:!0,register:k})}H(()=>{et(),Zr()}),d=setInterval(Z,o),Z()}a(Re,"completeStartup");function j(){return ge??=Re().catch(r=>{throw v={phase:"initializing",message:"daemon startup recovery failed and normal services are unavailable",blockerPaths:[]},r})}a(j,"resumeStartup");try{process.on("SIGINT",Q),process.on("SIGTERM",Y),process.on("exit",X),ot(),u!==null&&f({level:"info",event:"daemon.joined_owner.applied",fields:{owner:u.owner,rows:u.rows}}),N=await Oe();const r=c.token;Gr({epoch:r,requestHandover:_e,registerDetached:k,startupBlock:ye,admitStartup:ke,repairMigrations:Ee}),ue(),A=Ye({tcp:t.tcp}),await A.ready;const e=Me()??ie("user").document_port,i=Xe(e,Ze());try{await i.ready,F=i}catch(S){f({level:"warn",event:"daemon.document_listener.bind_failed",fields:{port:e,error:S instanceof Error?S.message:String(S)}})}const l=ie("user").runtime;l?.issuer?(R=or(l.issuer,k),l.unsandboxed===!0&&($=De({syncGrants:R})),tr(S=>nr().appended(S))):rr(),l?.unsandboxed===!0&&l.listener!==void 0&&f({level:"warn",event:"daemon.app_listener.refused_unsandboxed",fields:{reason:"runtime.unsandboxed is set; runtime.listener is ignored"}}),l!==void 0&&l.listener!==void 0&&l.unsandboxed!==!0&&(T=er(l,()=>dr(l.issuer.replace(/\/$/,"")),R),await T.ready);try{await it()}catch(S){if(I=null,S instanceof st)return v={phase:"blocked",message:S.message,blockerPaths:S.blockerPaths},P;throw S}process.platform==="linux"&&E(x)&&(ze(),await qe("app:terminal"));try{t.prepare?v={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]}:(await j(),v={phase:"ready",message:"",blockerPaths:[]})}finally{I=null}return P}catch(r){try{await P()}catch(e){throw new AggregateError([r,e],"daemon startup failed and cleanup also failed")}throw r}}a(Ct,"runDaemon");var co=Ct;export{z as brokerCommandDeclaresCanvasHome,W as brokerCommandEpoch,co as default,Ct as runDaemon,Dt as superviseTick,ht as teardownFleet};
16
+ `),process.exit(1)}}s(V,"handleSignal");function Q(){V("SIGINT")}s(Q,"onSigint");function Y(){V("SIGTERM")}s(Y,"onSigterm");function X(){P().catch(()=>{})}s(X,"onExit");async function H(r){h&&(g=g.then(r).then(()=>{},e=>{_.fresh(()=>{f({level:"error",event:"daemon.lane_job.failed",error:e})})}))}s(H,"enqueue");async function Z(){!h||v||(ve.check()&&R&&(f({level:"info",event:"daemon.resume.detected"}),k(R().catch(()=>{}))),v=!0,await H(async()=>{if(v=!1,!!h)try{await Dt(Date.now(),K)}catch(r){_.fresh(()=>{f({level:"error",event:"daemon.tick.failed",error:r})})}}))}s(Z,"enqueueTick");let L=null;async function ke(){if(L!==null)throw{status:500,code:"admission_failed",message:`daemon admission previously failed: ${L instanceof Error?L.message:String(L)}`};if(w.phase==="ready")return{admitted:!1,already_admitted:!0,startup_phase:"ready"};if(w.phase!=="prepared"&&w.phase!=="recovering")throw{status:409,code:"not_prepared",message:w.message};const r=w.phase==="prepared";try{return await j(),w={phase:"ready",message:"",blockerPaths:[]},r?{admitted:!0,already_admitted:!1,startup_phase:"ready"}:{admitted:!1,already_admitted:!0,startup_phase:"ready"}}catch(e){throw L=e,{status:500,code:"admission_failed",message:`daemon admission failed: ${e instanceof Error?e.message:String(e)}`}}}s(ke,"admitStartup");async function Ee(r){if(I!==null)throw{status:409,code:"migration_in_progress",message:`the canvas import is already running (${I})`};I="repair";try{const e=await st({dryRun:r.dryRun});if(r.dryRun||e.pending||w.phase!=="blocked")return{result:e,resumed:!1};if(t.prepare)return w={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]},{result:e,resumed:!1};try{return await j(),w={phase:"ready",message:"",blockerPaths:[]},{result:e,resumed:!0}}catch(i){const l=i instanceof Error?i.message:String(i);return setTimeout(()=>{P().catch(()=>{})},1e3),{result:e,resumed:!1,resumeError:l}}}finally{I=null}}s(Ee,"repairMigrations");async function Re(){o=t.intervalMs??hr;const r=c.token;p=new rt({epoch:r,enqueue:H}),Or(p),w={phase:"recovering",message:"daemon startup recovery is running and normal services are unavailable",blockerPaths:[]},_.fresh(()=>{f({level:"info",event:"daemon.started",fields:{pid:process.pid,interval_ms:o}})});const e=await zr();if(Wr(e),_.fresh(()=>{f({level:"info",event:"daemon.install_id.resolved",fields:{install_id:e}})}),_.fresh(()=>{let i;try{i=ur()}catch{return}i!==null&&f({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:i.slice(0,2048)}})}),await _.fresh(async()=>{await fr(),await lr(),await pr(Date.now()),await mr(Date.now())}),await _.fresh(async()=>{const{reconcile:i,migrated:l}=await qr(Pr);i.changed&&f({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:i.cleared.length,same_boot_proven:i.sameBootProven}}),l.length>0&&f({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:l.length}})}),await _.fresh(async()=>{for(const i of await ne())i.status!=="active"||i.pi_pid!=null||i.frozen_at!=null||i.respawn_not_before!=null||(await oe(i.node_id,new Date().toISOString()),f({level:"warn",event:"daemon.startup.launch_debt_recorded",node_id:i.node_id}))}),await _.fresh(async()=>{await Ar();for(const i of tt){const l=i.apply();l.changed&&f({level:"info",event:"daemon.boot_migration.applied",fields:{migration:i.id,...l.summary}})}}),k(cr()),R){const i=s(()=>{k(R().catch(()=>{})),k(Ie().then(l=>$?.observe(l)).then(()=>{},l=>{f({level:"warn",event:"daemon.peer.status_failed",error:l})}))},"refresh");k(ar().catch(()=>{})),k(sr().then(({completion:l})=>l).catch(l=>{f({level:"error",event:"daemon.grants.sweep_failed",error:l})})),i(),C=setInterval(i,ir*1e3),C.unref(),G=xe({joined:!0,register:k})}await H(async()=>{await et(),await Zr()}),d=setInterval(()=>{Z().catch(i=>f({level:"error",event:"daemon.tick.failed",error:i}))},o),await Z()}s(Re,"completeStartup");function j(){return ge??=Re().catch(r=>{throw w={phase:"initializing",message:"daemon startup recovery failed and normal services are unavailable",blockerPaths:[]},r})}s(j,"resumeStartup");try{process.on("SIGINT",Q),process.on("SIGTERM",Y),process.on("exit",X),ot(),u!==null&&f({level:"info",event:"daemon.joined_owner.applied",fields:{owner:u.owner,rows:u.rows}}),N=await Oe();const r=c.token;Gr({epoch:r,requestHandover:_e,registerDetached:k,startupBlock:ye,admitStartup:ke,repairMigrations:Ee}),ue(),A=Ye({tcp:t.tcp}),await A.ready;const e=Me()??ie("user").document_port,i=Xe(e,Ze());try{await i.ready,F=i}catch(S){f({level:"warn",event:"daemon.document_listener.bind_failed",fields:{port:e,error:S instanceof Error?S.message:String(S)}})}const l=ie("user").runtime;l?.issuer?(R=or(l.issuer,k),l.unsandboxed===!0&&($=De({syncGrants:R})),tr(S=>nr().appended(S))):await rr(),l?.unsandboxed===!0&&l.listener!==void 0&&f({level:"warn",event:"daemon.app_listener.refused_unsandboxed",fields:{reason:"runtime.unsandboxed is set; runtime.listener is ignored"}}),l!==void 0&&l.listener!==void 0&&l.unsandboxed!==!0&&(T=await er(l,async()=>await dr(l.issuer.replace(/\/$/,"")),R),await T.ready);try{await it()}catch(S){if(I=null,S instanceof at)return w={phase:"blocked",message:S.message,blockerPaths:S.blockerPaths},P;throw S}process.platform==="linux"&&E(x)&&(ze(),await qe("app:terminal"));try{t.prepare?w={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]}:(await j(),w={phase:"ready",message:"",blockerPaths:[]})}finally{I=null}return P}catch(r){try{await P()}catch(e){throw new AggregateError([r,e],"daemon startup failed and cleanup also failed")}throw r}}s(Ct,"runDaemon");var co=Ct;export{z as brokerCommandDeclaresCanvasHome,W as brokerCommandEpoch,co as default,Ct as runDaemon,Dt as superviseTick,ht as teardownFleet};
@@ -1 +1 @@
1
- var C=Object.defineProperty;var l=(e,t)=>C(e,"name",{value:t,configurable:!0});import{spawn as T}from"node:child_process";import{envHomeOverride as _}from"../../shared/env.js";import{deliveryBackoffMs as g}from"../../core/canvas/delivery-contract.js";import{killProcessGroup as x}from"../../core/canvas/pid.js";import{buildOperationalEnvBase as y}from"../../core/runtime/spawn-env.js";import{getNode as R}from"../../core/canvas/canvas.js";import{appProcessSandboxed as A,launchAppProcess as O}from"../../core/spaces/process.js";const I=12e4,h=2e3,E=4*1024;function w(e,t,r){return e.spawnError!==void 0?{state:"pending",nextAttemptAt:r+g(t),failure:m("spawn_error",{message:e.spawnError.message,stderr:e.stderr})}:e.timedOut?{state:"pending",nextAttemptAt:r+g(t),failure:m("timeout",{...e.signal===null?{}:{signal:e.signal},stderr:e.stderr})}:e.signal!==null?{state:"pending",nextAttemptAt:r+g(t),failure:m("signal",{signal:e.signal,stderr:e.stderr})}:e.exitCode===0?{state:"accepted"}:e.exitCode===78?{state:"permanent_failed",failure:m("exit",{exitCode:78,stderr:e.stderr})}:{state:"pending",nextAttemptAt:r+g(t),failure:m("exit",{exitCode:e.exitCode??void 0,stderr:e.stderr})}}l(w,"deliverySettlementForOutcome");function m(e,t){return{kind:e,...t}}l(m,"failure");function D(){let e=Buffer.alloc(0);return{take(t){e=t.length>=E?t.subarray(t.length-E):Buffer.concat([e,t]).subarray(Math.max(0,e.length+t.length-E))},decode(){return e.toString("utf8")}}}l(D,"stderrTailCapture");function S(e,t,r){if(r)return JSON.stringify(e);const d=e,n=d.delivery;return JSON.stringify({...d,delivery:{...n,attempt:t}})}l(S,"documentForAttempt");function L(e,t){const r=y({targetCwd:e,targetProfileId:null}),d=_();return d!==void 0&&d!==""&&(r.CRTR_HOME=d),{...r,...t}}l(L,"deliveryEnv");async function H(e,t){const r=D();let d;try{d=S(e.document,e.attempt,e.custom!==void 0)}catch(s){t(w({exitCode:null,signal:null,timedOut:!1,spawnError:s,stderr:r.decode()},e.attempt,Date.now()));return}if(process.platform==="linux"){let s;try{if(!A())throw new Error("root launcher is required for delivery");const u=e.nodeId===null||e.nodeId===void 0?null:R(e.nodeId),f=e.app??u?.grantee??(e.nodeId==null?"app:terminal":void 0);if(!f)throw new Error(`delivery origin ${e.nodeId} was deleted without a stored app`);const o=await O({...u?{nodeId:e.nodeId}:{},app:f,command:e.argv,cwd:e.cwd,env:{...y({targetCwd:e.cwd,targetProfileId:null,skipSpawnAllow:!0}),...e.custom?{CRTR_DELIVERY_ID:e.custom.deliveryId,CRTR_CAUSE_EVENT:e.custom.messageId}:{}},stdin:d,stdoutBytes:0,stderrBytes:E,stderrTail:!0});let a,p=!1;try{a=setTimeout(()=>{p=!0,o.stop().catch(i=>{console.error(`delivery process ${o.pid} could not be stopped:`,i)})},I),a.unref?.();const c=await o.completion;s={exitCode:c.exitCode,signal:c.signal,timedOut:p,stderr:c.stderr}}finally{a!==void 0&&clearTimeout(a)}}catch(u){s={exitCode:null,signal:null,timedOut:!1,spawnError:u,stderr:""}}t(w(s,e.attempt,Date.now()));return}let n;try{n=T(e.argv[0],e.argv.slice(1),{cwd:e.cwd,env:L(e.cwd,e.custom?{CRTR_DELIVERY_ID:e.custom.deliveryId,CRTR_CAUSE_EVENT:e.custom.messageId}:void 0),detached:!0,stdio:["pipe","pipe","pipe"]})}catch(s){t(w({exitCode:null,signal:null,timedOut:!1,spawnError:s,stderr:r.decode()},e.attempt,Date.now()));return}await new Promise(s=>{let u=!1,f=!1,o,a;const p=l(i=>{u||(u=!0,a!==void 0&&clearTimeout(a),!i.timedOut&&o!==void 0&&clearTimeout(o),n.stdin?.destroy(),n.stdout?.destroy(),n.stderr?.destroy(),t(w(i,e.attempt,Date.now())),s())},"finish");n.stdout?.on("data",()=>{}),n.stderr?.on("data",i=>r.take(i)),n.stdin?.on("error",()=>{}),n.on("error",i=>{p({exitCode:null,signal:null,timedOut:!1,spawnError:i,stderr:r.decode()})}),n.on("exit",(i,v)=>{p({exitCode:i,signal:v,timedOut:f,stderr:r.decode()})});const c=l(()=>{n.pid!==void 0&&(x(n.pid),o=setTimeout(()=>x(n.pid,"SIGKILL"),h),o.unref?.())},"killWithEscalation");a=setTimeout(()=>{f=!0,c()},I),a.unref?.(),n.stdin?.end(d,"utf8")})}l(H,"runDelivery");export{E as DELIVERY_STDERR_TAIL_BYTES,I as DELIVERY_TIMEOUT_MS,w as deliverySettlementForOutcome,H as runDelivery};
1
+ var C=Object.defineProperty;var l=(e,t)=>C(e,"name",{value:t,configurable:!0});import{spawn as T}from"node:child_process";import{envHomeOverride as _}from"../../shared/env.js";import{deliveryBackoffMs as g}from"../../core/canvas/delivery-contract.js";import{killProcessGroup as x}from"../../core/canvas/pid.js";import{buildOperationalEnvBase as y}from"../../core/runtime/spawn-env.js";import{getNode as R}from"../../core/canvas/canvas.js";import{appProcessSandboxed as A,launchAppProcess as O}from"../../core/spaces/process.js";const I=12e4,h=2e3,E=4*1024;function w(e,t,r){return e.spawnError!==void 0?{state:"pending",nextAttemptAt:r+g(t),failure:m("spawn_error",{message:e.spawnError.message,stderr:e.stderr})}:e.timedOut?{state:"pending",nextAttemptAt:r+g(t),failure:m("timeout",{...e.signal===null?{}:{signal:e.signal},stderr:e.stderr})}:e.signal!==null?{state:"pending",nextAttemptAt:r+g(t),failure:m("signal",{signal:e.signal,stderr:e.stderr})}:e.exitCode===0?{state:"accepted"}:e.exitCode===78?{state:"permanent_failed",failure:m("exit",{exitCode:78,stderr:e.stderr})}:{state:"pending",nextAttemptAt:r+g(t),failure:m("exit",{exitCode:e.exitCode??void 0,stderr:e.stderr})}}l(w,"deliverySettlementForOutcome");function m(e,t){return{kind:e,...t}}l(m,"failure");function D(){let e=Buffer.alloc(0);return{take(t){e=t.length>=E?t.subarray(t.length-E):Buffer.concat([e,t]).subarray(Math.max(0,e.length+t.length-E))},decode(){return e.toString("utf8")}}}l(D,"stderrTailCapture");function S(e,t,r){if(r)return JSON.stringify(e);const d=e,n=d.delivery;return JSON.stringify({...d,delivery:{...n,attempt:t}})}l(S,"documentForAttempt");function L(e,t){const r=y({targetCwd:e,targetProfileId:null}),d=_();return d!==void 0&&d!==""&&(r.CRTR_HOME=d),{...r,...t}}l(L,"deliveryEnv");async function H(e,t){const r=D();let d;try{d=S(e.document,e.attempt,e.custom!==void 0)}catch(s){t(w({exitCode:null,signal:null,timedOut:!1,spawnError:s,stderr:r.decode()},e.attempt,Date.now()));return}if(process.platform==="linux"){let s;try{if(!A())throw new Error("root launcher is required for delivery");const u=e.nodeId===null||e.nodeId===void 0?null:await R(e.nodeId),f=e.app??u?.grantee??(e.nodeId==null?"app:terminal":void 0);if(!f)throw new Error(`delivery origin ${e.nodeId} was deleted without a stored app`);const o=await O({...u?{nodeId:e.nodeId}:{},app:f,command:e.argv,cwd:e.cwd,env:{...y({targetCwd:e.cwd,targetProfileId:null,skipSpawnAllow:!0}),...e.custom?{CRTR_DELIVERY_ID:e.custom.deliveryId,CRTR_CAUSE_EVENT:e.custom.messageId}:{}},stdin:d,stdoutBytes:0,stderrBytes:E,stderrTail:!0});let a,p=!1;try{a=setTimeout(()=>{p=!0,o.stop().catch(i=>{console.error(`delivery process ${o.pid} could not be stopped:`,i)})},I),a.unref?.();const c=await o.completion;s={exitCode:c.exitCode,signal:c.signal,timedOut:p,stderr:c.stderr}}finally{a!==void 0&&clearTimeout(a)}}catch(u){s={exitCode:null,signal:null,timedOut:!1,spawnError:u,stderr:""}}t(w(s,e.attempt,Date.now()));return}let n;try{n=T(e.argv[0],e.argv.slice(1),{cwd:e.cwd,env:L(e.cwd,e.custom?{CRTR_DELIVERY_ID:e.custom.deliveryId,CRTR_CAUSE_EVENT:e.custom.messageId}:void 0),detached:!0,stdio:["pipe","pipe","pipe"]})}catch(s){t(w({exitCode:null,signal:null,timedOut:!1,spawnError:s,stderr:r.decode()},e.attempt,Date.now()));return}await new Promise(s=>{let u=!1,f=!1,o,a;const p=l(i=>{u||(u=!0,a!==void 0&&clearTimeout(a),!i.timedOut&&o!==void 0&&clearTimeout(o),n.stdin?.destroy(),n.stdout?.destroy(),n.stderr?.destroy(),t(w(i,e.attempt,Date.now())),s())},"finish");n.stdout?.on("data",()=>{}),n.stderr?.on("data",i=>r.take(i)),n.stdin?.on("error",()=>{}),n.on("error",i=>{p({exitCode:null,signal:null,timedOut:!1,spawnError:i,stderr:r.decode()})}),n.on("exit",(i,v)=>{p({exitCode:i,signal:v,timedOut:f,stderr:r.decode()})});const c=l(()=>{n.pid!==void 0&&(x(n.pid),o=setTimeout(()=>x(n.pid,"SIGKILL"),h),o.unref?.())},"killWithEscalation");a=setTimeout(()=>{f=!0,c()},I),a.unref?.(),n.stdin?.end(d,"utf8")})}l(H,"runDelivery");export{E as DELIVERY_STDERR_TAIL_BYTES,I as DELIVERY_TIMEOUT_MS,w as deliverySettlementForOutcome,H as runDelivery};
@@ -2,14 +2,14 @@
2
2
  export declare const TICK_LANES: readonly ["brokerSupervision", "controllerDeath", "nodeLifecycle", "nodeDeadline", "structuredRequests", "cronLane", "deliveryLane", "actionLane", "pendingReviewSubmit", "storageMaintenance", "storageDueWork", "pollRunObservers", "faultRetryBackstop", "bashDeadline"];
3
3
  export interface DueSource {
4
4
  /** Epoch ms of the earliest timed work this lane owes; `now` when work is due already; null when none. */
5
- nextDue(now: number): number | null;
5
+ nextDue(now: number): Promise<number | null>;
6
6
  }
7
7
  export declare function registerDueSource(lane: string, source: DueSource): void;
8
8
  export declare function declareBusyOnly(lane: string, reason: string): void;
9
9
  export declare function dueSourceLanes(): string[];
10
10
  export declare function busyOnlyLanes(): string[];
11
11
  /** The earliest due time over every source, and whether any source is due at `now`. A source that throws counts as due now: a lane that cannot answer must keep the sandbox awake, never let it sleep past work. */
12
- export declare function collectDue(now: number, onError?: (lane: string, error: unknown) => void): {
12
+ export declare function collectDue(now: number, onError?: (lane: string, error: unknown) => void): Promise<{
13
13
  dueNow: boolean;
14
14
  nextDueMs: number | null;
15
- };
15
+ }>;
@@ -1 +1 @@
1
- var f=Object.defineProperty;var r=(e,n)=>f(e,"name",{value:n,configurable:!0});const p=["brokerSupervision","controllerDeath","nodeLifecycle","nodeDeadline","structuredRequests","cronLane","deliveryLane","actionLane","pendingReviewSubmit","storageMaintenance","storageDueWork","pollRunObservers","faultRetryBackstop","bashDeadline"],u=new Map,c=new Map;function y(e,n){u.set(e,n)}r(y,"registerDueSource");function x(e,n){c.set(e,n)}r(x,"declareBusyOnly");function D(){return[...u.keys()]}r(D,"dueSourceLanes");function b(){return[...c.keys()]}r(b,"busyOnlyLanes");function L(e,n=()=>{}){let o=null,s=!1;for(const[l,i]of u){let t;try{t=i.nextDue(e)}catch(a){n(l,a),t=e}t===null||!Number.isFinite(t)||(t<=e&&(s=!0),(o===null||t<o)&&(o=t))}return{dueNow:s,nextDueMs:o}}r(L,"collectDue");export{p as TICK_LANES,b as busyOnlyLanes,L as collectDue,x as declareBusyOnly,D as dueSourceLanes,y as registerDueSource};
1
+ var f=Object.defineProperty;var r=(e,n)=>f(e,"name",{value:n,configurable:!0});const d=["brokerSupervision","controllerDeath","nodeLifecycle","nodeDeadline","structuredRequests","cronLane","deliveryLane","actionLane","pendingReviewSubmit","storageMaintenance","storageDueWork","pollRunObservers","faultRetryBackstop","bashDeadline"],u=new Map,c=new Map;function p(e,n){u.set(e,n)}r(p,"registerDueSource");function x(e,n){c.set(e,n)}r(x,"declareBusyOnly");function D(){return[...u.keys()]}r(D,"dueSourceLanes");function b(){return[...c.keys()]}r(b,"busyOnlyLanes");async function L(e,n=()=>{}){let o=null,s=!1;for(const[a,i]of u){let t;try{t=await i.nextDue(e)}catch(l){n(a,l),t=e}t===null||!Number.isFinite(t)||(t<=e&&(s=!0),(o===null||t<o)&&(o=t))}return{dueNow:s,nextDueMs:o}}r(L,"collectDue");export{d as TICK_LANES,b as busyOnlyLanes,L as collectDue,x as declareBusyOnly,D as dueSourceLanes,p as registerDueSource};