@north-light/cli 0.3.530 → 0.3.532

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 +508 -508
  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 +2 -2
  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 +13 -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 +13 -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
@@ -11,7 +11,7 @@ import { respawnPaneSync } from './placement.js';
11
11
  * explicit: an abrupt broker teardown fires NO clean `session_shutdown`, so the
12
12
  * general quit→done rule does NOT auto-resolve a force-killed descendant — we
13
13
  * mark it `canceled` here via the same `cancel` event the close cascade uses. */
14
- export declare function reapDescendants(rootId: string): string[];
14
+ export declare function reapDescendants(rootId: string): Promise<string[]>;
15
15
  /** Injectable host/viewer seam, so the ordinary source test drives relaunchRoot's pure
16
16
  * DB transitions without a real broker or tmux. Each field defaults to its
17
17
  * production verb. */
@@ -51,7 +51,7 @@ export interface ResetRootResult {
51
51
  * `--session <id>` wakes the right conversation. A `/new` on a child is NOT a
52
52
  * graph reset — a root's `/new` is handled by relaunchRoot, never here; a root
53
53
  * that reaches this is a no-op. */
54
- export declare function resetRoot(nodeId: string, newSessionId?: string, newSessionFile?: string | null): ResetRootResult;
54
+ export declare function resetRoot(nodeId: string, newSessionId?: string, newSessionFile?: string | null): Promise<ResetRootResult>;
55
55
  export type HandleNewSessionPath = 'reset-child' | 'noop';
56
56
  export interface HandleNewSessionResult {
57
57
  path: HandleNewSessionPath;
@@ -59,10 +59,10 @@ export interface HandleNewSessionResult {
59
59
  /** The child-side `/new` entry the stophook calls (the root side goes to
60
60
  * relaunchRoot directly). The broker already drove the engine-side new_session;
61
61
  * this only refreshes the child's session id on the SAME node id. */
62
- export declare function handleNewSession(nodeId: string, newSessionId: string, newSessionFile?: string | null): HandleNewSessionResult;
62
+ export declare function handleNewSession(nodeId: string, newSessionId: string, newSessionFile?: string | null): Promise<HandleNewSessionResult>;
63
63
  /** Resolve a cleanly-exiting node to `done`. Returns true iff it transitioned.
64
64
  * Guard: only a real quit, and only a node still active|idle with no pending
65
65
  * intent — so it never clobbers a node already routed by agent_end to done
66
66
  * (push final), refresh (yield), or idle-release. Pure/DB-only (no pi/tmux) so
67
67
  * the guard is unit-testable without a live pi. */
68
- export declare function markCleanExitDone(nodeId: string, reason: unknown): boolean;
68
+ export declare function markCleanExitDone(nodeId: string, reason: unknown): Promise<boolean>;
@@ -1 +1 @@
1
- var S=Object.defineProperty;var l=(e,t)=>S(e,"name",{value:t,configurable:!0});import{getNode as p,beginExecution as B,recordExecutionPid as N,abortExecution as k,bindSession as b,recordLaunch as g,fullName as x,liveExecutionForNode as F,closeFocusRow as R,view as O}from"../canvas/index.js";import{transition as a}from"./lifecycle.js";import{headlessBrokerHost as y,requestBrokerTeardown as V}from"./host.js";import{boundFleet as C}from"./fleet.js";import{tearDownNode as D,focusOf as P,registerViewerFocus as T,respawnPaneSync as I,windowOfPane as L,renameWindow as q}from"./placement.js";import{viewerSplitEnv as A,waitForBrokerViewSocket as H}from"./placement-tmux.js";import{buildLaunchSpecAsync as M,buildPiArgv as U}from"./launch.js";import{newNodeId as j,spawnNode as W,rootOfSpine as X}from"./nodes.js";import{appSpace as $}from"../layout.js";import{join as z}from"node:path";import{invokeBirthLifecycleHooks as G}from"./spawn.js";function J(e){const t=[];for(const r of O(e))try{a(r,"cancel",{reason:"closed"}),V(r),D(r),t.push(r)}catch{}return t}l(J,"reapDescendants");async function le(e,t={}){const r=t.launchBroker??y.launch,s=t.waitForViewSocket??H,m=t.respawnViewer??I,c=t.teardownBroker??y.teardown,o=p(e);if(o===null||o.parent!=null||o.status==="done")return null;const d=P(e),h=o.isolated?j():void 0,_=h?z($(o.grantee??"app:terminal").nodes,h):o.cwd,{launch:E}=await M(o.kind,"base",{lifecycle:"resident",hasManager:!1,model:o.model_override??void 0,modelIntent:o.launch?.modelIntent,modelExact:o.launch?.modelExact,cwd:_,profileId:o.profile_id}),n=await W({nodeId:h,kind:o.kind,mode:"base",lifecycle:"resident",cwd:_,name:o.kind,parent:null,replaces:e,profile_id:o.profile_id,launch:E,modelOverride:o.model_override??void 0});await G(n);const u=U(n,{});u.env={...u.env,CRTR_SUBTREE:X(n.node_id)};const f=B(n.node_id,{daemonEpoch:C().epoch()});u.env={...u.env,CRTR_EXECUTION_ID:f};let w;try{w=await r(n.node_id,u,{cwd:_,name:x(n),resuming:!1})}catch(i){throw k(f,{reason:"launch_failed"}),a(n.node_id,"crash"),i}if(w.pid==null)return k(f,{reason:"launch_failed"}),a(n.node_id,"crash"),null;if(g(n.node_id,new Date().toISOString()),N(f,n.node_id,w.pid)==="shutdown"){k(f,{reason:"superseded"});try{c(n.node_id)}catch{}return a(n.node_id,"crash"),null}let v=!1;try{v=await s(n.node_id,w.exited)}catch{}if(!v){const i=p(n.node_id);(i?.status==="active"||i?.status==="idle")&&a(n.node_id,"crash");try{c(n.node_id)}catch{}return null}if(J(e),a(e,"finish"),d?.pane!=null){R(d.focus_id),m({pane:d.pane,cwd:o.cwd,env:A(),command:`crtr surface attach to ${n.node_id}`});const i=L(d.pane);i!==null&&q(i,x(n)),T(n.node_id,d.pane,d.session,i)}return c(e),{newNodeId:n.node_id}}l(le,"relaunchRoot");function K(e,t,r){const s=p(e),m={reaped:[],detached:[],reset:!1};if(s===null||s.parent==null)return m;if(t!==void 0){const c=F(e);c!==null&&b(e,{executionId:c.executionId,sessionId:t,transcriptPath:r??null})}return m}l(K,"resetRoot");function se(e,t,r){return p(e)===null?{path:"noop"}:(K(e,t,r),{path:"reset-child"})}l(se,"handleNewSession");function ue(e,t){if(t!=="quit")return!1;const r=p(e);return r===null||r.status!=="active"&&r.status!=="idle"||r.intent!=null?!1:(a(e,"finish"),!0)}l(ue,"markCleanExitDone");export{se as handleNewSession,ue as markCleanExitDone,J as reapDescendants,le as relaunchRoot,K as resetRoot};
1
+ var S=Object.defineProperty;var s=(e,t)=>S(e,"name",{value:t,configurable:!0});import{getNode as f,beginExecution as B,recordExecutionPid as N,abortExecution as v,bindSession as b,recordLaunch as g,fullName as x,liveExecutionForNode as F,closeFocusRow as R,view as O}from"../canvas/index.js";import{transition as r}from"./lifecycle.js";import{headlessBrokerHost as y,requestBrokerTeardown as V}from"./host.js";import{boundFleet as C}from"./fleet.js";import{tearDownNode as D,focusOf as P,registerViewerFocus as T,respawnPaneSync as I,windowOfPane as L,renameWindow as q}from"./placement.js";import{viewerSplitEnv as A,waitForBrokerViewSocket as H}from"./placement-tmux.js";import{buildLaunchSpecAsync as M,buildPiArgv as U}from"./launch.js";import{newNodeId as j,spawnNode as W,rootOfSpine as X}from"./nodes.js";import{appSpace as $}from"../layout.js";import{join as z}from"node:path";import{invokeBirthLifecycleHooks as G}from"./spawn.js";async function J(e){const t=[];for(const i of await O(e))try{await r(i,"cancel",{reason:"closed"}),V(i),await D(i),t.push(i)}catch{}return t}s(J,"reapDescendants");async function se(e,t={}){const i=t.launchBroker??y.launch,l=t.waitForViewSocket??H,p=t.respawnViewer??I,c=t.teardownBroker??y.teardown,a=await f(e);if(a===null||a.parent!=null||a.status==="done")return null;const d=await P(e),h=a.isolated?await j():void 0,_=h?z($(a.grantee??"app:terminal").nodes,h):a.cwd,{launch:E}=await M(a.kind,"base",{lifecycle:"resident",hasManager:!1,model:a.model_override??void 0,modelIntent:a.launch?.modelIntent,modelExact:a.launch?.modelExact,cwd:_,profileId:a.profile_id}),n=await W({nodeId:h,kind:a.kind,mode:"base",lifecycle:"resident",cwd:_,name:a.kind,parent:null,replaces:e,profile_id:a.profile_id,launch:E,modelOverride:a.model_override??void 0});await G(n);const u=U(n,{});u.env={...u.env,CRTR_SUBTREE:await X(n.node_id)};const w=await B(n.node_id,{daemonEpoch:C().epoch()});u.env={...u.env,CRTR_EXECUTION_ID:w};let m;try{m=await i(n.node_id,u,{cwd:_,name:x(n),resuming:!1})}catch(o){throw await v(w,{reason:"launch_failed"}),await r(n.node_id,"crash"),o}if(m.pid==null)return await v(w,{reason:"launch_failed"}),await r(n.node_id,"crash"),null;if(await g(n.node_id,new Date().toISOString()),await N(w,n.node_id,m.pid)==="shutdown"){await v(w,{reason:"superseded"});try{c(n.node_id)}catch{}return await r(n.node_id,"crash"),null}let k=!1;try{k=await l(n.node_id,m.exited)}catch{}if(!k){const o=await f(n.node_id);(o?.status==="active"||o?.status==="idle")&&await r(n.node_id,"crash");try{c(n.node_id)}catch{}return null}if(await J(e),await r(e,"finish"),d?.pane!=null){await R(d.focus_id),p({pane:d.pane,cwd:a.cwd,env:A(),command:`crtr surface attach to ${n.node_id}`});const o=L(d.pane);o!==null&&q(o,x(n)),await T(n.node_id,d.pane,d.session,o)}return c(e),{newNodeId:n.node_id}}s(se,"relaunchRoot");async function K(e,t,i){const l=await f(e),p={reaped:[],detached:[],reset:!1};if(l===null||l.parent==null)return p;if(t!==void 0){const c=await F(e);c!==null&&await b(e,{executionId:c.executionId,sessionId:t,transcriptPath:i??null})}return p}s(K,"resetRoot");async function le(e,t,i){return await f(e)===null?{path:"noop"}:(await K(e,t,i),{path:"reset-child"})}s(le,"handleNewSession");async function ue(e,t){if(t!=="quit")return!1;const i=await f(e);return i===null||i.status!=="active"&&i.status!=="idle"||i.intent!=null?!1:(await r(e,"finish"),!0)}s(ue,"markCleanExitDone");export{le as handleNewSession,ue as markCleanExitDone,J as reapDescendants,se as relaunchRoot,K as resetRoot};
@@ -35,7 +35,7 @@ export declare function isDisconnected(meta: NodeMeta, isAlive: (pid: number | n
35
35
  /** Every disconnected node on the canvas — the set a revive-all WOULD relaunch.
36
36
  * This is the PREVIEW: it has no side effects, so the command can list the
37
37
  * candidates and gate on confirmation before any engine is launched. */
38
- export declare function listDisconnected(): NodeMeta[];
38
+ export declare function listDisconnected(): Promise<NodeMeta[]>;
39
39
  export interface ReviveAllResult {
40
40
  /** Node ids whose broker engine reviveAll relaunched (RESUME). */
41
41
  revived: string[];
@@ -54,4 +54,4 @@ export interface ReviveAllResult {
54
54
  * no-op), so this is a thin orchestrator over `listDisconnected`: revive each
55
55
  * with resume:true. One failing node never aborts the sweep — its error is
56
56
  * collected and the rest proceed. */
57
- export declare function reviveAll(include?: (meta: NodeMeta) => boolean): Promise<ReviveAllResult>;
57
+ export declare function reviveAll(include?: (meta: NodeMeta) => Promise<boolean>): Promise<ReviveAllResult>;
@@ -1 +1 @@
1
- var t=Object.defineProperty;var n=(e,r)=>t(e,"name",{value:r,configurable:!0});import{listNodes as s,getNode as u}from"../canvas/index.js";import{recordedPidLiveness as d}from"../canvas/pid.js";import{reviveNode as f}from"./revive.js";const l=["done","canceled"];function c(e){return e.frozen_at==null&&(e.final_report!=null||l.includes(e.status))}n(c,"hasNoNaturalCycle");function p(e,r){return!(e.kind==="human"||r(e.pi_pid)||e.pi_session_id==null&&e.pi_session_file==null||c(e))}n(p,"isDisconnected");function a(){const e=[];for(const r of s()){const o=u(r.node_id);o!==null&&p(o,i=>d(i,o.pi_pid_identity)==="alive")&&e.push(o)}return e}n(a,"listDisconnected");async function y(e=()=>!0){const r={revived:[],failed:[],frozen:[]};for(const o of a().filter(e))try{(await f(o.node_id,{resume:!0,recovery:!0,capacity:"freeze"})).outcome==="frozen"?r.frozen.push(o.node_id):r.revived.push(o.node_id)}catch(i){r.failed.push({node_id:o.node_id,error:i.message})}return r}n(y,"reviveAll");export{l as TERMINAL_BY_CHOICE,c as hasNoNaturalCycle,p as isDisconnected,a as listDisconnected,y as reviveAll};
1
+ var t=Object.defineProperty;var i=(e,r)=>t(e,"name",{value:r,configurable:!0});import{listNodes as s,getNode as u}from"../canvas/index.js";import{recordedPidLiveness as c}from"../canvas/pid.js";import{reviveNode as d}from"./revive.js";import{filterAsync as f}from"../async-array.js";const l=["done","canceled"];function a(e){return e.frozen_at==null&&(e.final_report!=null||l.includes(e.status))}i(a,"hasNoNaturalCycle");function p(e,r){return!(e.kind==="human"||r(e.pi_pid)||e.pi_session_id==null&&e.pi_session_file==null||a(e))}i(p,"isDisconnected");async function _(){const e=[];for(const r of await s()){const o=await u(r.node_id);o!==null&&p(o,n=>c(n,o.pi_pid_identity)==="alive")&&e.push(o)}return e}i(_,"listDisconnected");async function N(e=async()=>!0){const r={revived:[],failed:[],frozen:[]};for(const o of await f(await _(),e))try{(await d(o.node_id,{resume:!0,recovery:!0,capacity:"freeze"})).outcome==="frozen"?r.frozen.push(o.node_id):r.revived.push(o.node_id)}catch(n){r.failed.push({node_id:o.node_id,error:n.message})}return r}i(N,"reviveAll");export{l as TERMINAL_BY_CHOICE,a as hasNoNaturalCycle,p as isDisconnected,_ as listDisconnected,N as reviveAll};
@@ -21,16 +21,16 @@ import { headlessBrokerHost } from './host.js';
21
21
  * branch (`--crtr-new-cycle`) rather than continuing the existing leaf. Pure
22
22
  * so the decision is unit-testable without tmux or a real filesystem fixture
23
23
  * beyond a temp file. */
24
- export declare function resumeArgs(meta: NodeMeta, resume: boolean): {
24
+ export declare function resumeArgs(meta: NodeMeta, resume: boolean): Promise<{
25
25
  resumeSessionPath?: string;
26
26
  newCycle?: boolean;
27
- };
27
+ }>;
28
28
  /** Whether a fresh context window would have anything on disk to stand on: a
29
29
  * goal, a roadmap, or both. The negative is what makes a fresh cycle worse
30
30
  * than a resume — the new window would wake amnesiac, with no statement of
31
31
  * what it is for. Read by the parked-resident veto below and by the message
32
32
  * handler's explicit fresh-revive gate. */
33
- export declare function hasFreshGroundState(nodeId: string): boolean;
33
+ export declare function hasFreshGroundState(nodeId: string): Promise<boolean>;
34
34
  export interface ReviveResult {
35
35
  /** Always null — the broker engine is never placed in a tmux window. Kept on
36
36
  * the result for caller back-compat. */
@@ -50,7 +50,7 @@ export interface ReviveResult {
50
50
  * `beginBootFaultAttempt` at the exact clear-then-launch boundary below.
51
51
  * Present only when a fresh launch actually happened (absent on the
52
52
  * double-revive no-op, where nothing was cleared or relaunched). */
53
- faultExplanation?: () => string | null;
53
+ faultExplanation?: () => Promise<string | null>;
54
54
  /** What this call actually did. `already-live` means a broker was already
55
55
  * running for the node and nothing was launched; `frozen` means no slot was
56
56
  * free and the row is now waiting for one — the tick thaws it. */
@@ -1,3 +1,3 @@
1
- var Y=Object.defineProperty;var l=(e,r)=>Y(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as q}from"./unsandboxed.js";import{existsSync as B}from"node:fs";import{conversationIdFromPath as p,conversationStore as h,ConversationNotFoundError as O}from"../conversation-store/index.js";import{isAbsolute as Q}from"node:path";import{findNodeBySessionFile as Z,getNode as R,updateNode as E,beginExecution as I,recordExecutionPid as ee,abortExecution as S,endLiveExecution as re,unbindSession as T,recordLaunch as ie,setFrozen as ne,clearFrozen as te,fullName as D}from"../canvas/index.js";import{emitEvent as oe}from"../events/emit.js";import{cancelCronsOnWake as se}from"../canvas/crons.js";import{isParked as le,transition as x}from"./lifecycle.js";import{publishNotice as ce}from"./close.js";import{InputError as $}from"../io.js";import{buildPiArgv as v}from"./launch.js";import{buildReviveKickoff as ae,drainBearings as ue,hasRetainedReports as fe,readGoal as y,readYieldMessage as de,RUNTIME_RESTART_CONTINUATION as he}from"./kickoff.js";import{readRoadmap as z}from"./roadmap.js";import{encodeKickoffOrigin as pe,KICKOFF_ORIGIN_ENV as ve}from"./stamp/protocol.js";import{headlessBrokerHost as H}from"./host.js";import{appMemoryFull as me,appMemoryTooSmall as we,boundFleet as M,brokerCapReached as _e,brokerThresholdsForDaemon as U}from"./fleet.js";import{admitBrokerMemory as ke}from"./memory-admission.js";import{beginBootFaultAttempt as ye,clearFault as ge,hasAdmittedTurn as be}from"../canvas/recovery.js";import{clearNodeLedger as K,forkNodeLedger as Re,noticeChangedWhileDone as Ee}from"./ledger.js";import{forkSourceNode as Se,rootOfSpine as xe}from"./nodes.js";import{isReviewCompanionBound as $e}from"../review/companion.js";import{assertProfileActive as Ce}from"../profiles/manifest.js";import{isPidAlive as Ne}from"../canvas/pid.js";import{crtrHome as Fe,jobDir as Pe}from"../canvas/paths.js";import{contextDir as Ae,ensureNodeDirs as Be,nodeAgentDir as Oe}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as Te}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as De}from"../command-hooks/transport/exec-lifecycle.js";function ze(e,r){const i=e.pi_session_file,n=i?p(i):null;if(n===null)return{};try{const t=h().header(n);return r?{resumeSessionPath:t.path}:{resumeSessionPath:t.path,newCycle:!0}}catch(t){if(t instanceof O)return{};throw t}}l(ze,"resumeArgs");function G(e){const r=p(e);if(r===null)return!1;try{return h().header(r),!0}catch(i){if(i instanceof O)return!1;throw i}}l(G,"conversationExists");function He(e){const r=p(e);return r===null?!0:h().read(r).entries.some(i=>i.type==="message")}l(He,"sessionHasConversation");function Me(e){const r=p(e);if(r===null)return!0;const i=h().header(r).header.cwd;return typeof i!="string"||B(i)}l(Me,"sessionCwdExists");function Ue(e,r,i){const n=r.pi_session_file;if(!n||!G(n))return{};const t=Z(n);return t!==null&&t.node_id!==e&&Ne(t.pi_pid)?{}:Me(n)?ze(r,i):{}}l(Ue,"resumableSessionArgs");function Ke(e){return z(e)===null&&de(e)===null&&!fe(e)}l(Ke,"isUnstartedBirth");function _r(e){const r=y(e);if(r!==null&&r.trim()!=="")return!0;const i=z(e);return i!==null&&i.trim()!==""}l(_r,"hasFreshGroundState");async function kr(e,r){const i=await L(e,r,!0);if(i.parked)throw new Error(`reviveNode: internal parked decision for activating revive ${e}`);return i.result}l(kr,"reviveNode");async function yr(e,r,i){return L(e,{...r,viewerAttach:!0},i)}l(yr,"decideAttachRevive");async function L(e,r,i){let n=R(e);if(n===null)throw new Error(`reviveNode: unknown node ${e}`);if(n=R(e)??n,n.run_id&&R(n.run_id)?.deleting_at)throw new Error("run is deleting");if(n.final_report!==null)throw new Error(`reviveNode: refusing to revive ${e} \u2014 its finalization latch is set (final_report=${n.final_report}). A final landed between the caller's reopen-gate check and this revive; re-run with --reopen if this retask is still wanted.`);Ce(n.profile_id),q(n.grantee);const t=M();if(t.has(e))return x(e,n.intent==="refresh"?"refresh-launch":"revive"),{parked:!1,result:{window:null,session:n.tmux_session??null,resumed:!1,outcome:"already-live"}};if(t.isClaimed(e))return{parked:!1,result:{window:null,session:n.tmux_session??null,resumed:!1,outcome:"already-live"}};if(!i&&n.lifecycle==="resident"&&le(n))return{parked:!0};const c=t.reserveSlot(e);let s=null;if(c){try{s=await ke(e)}catch(u){throw t.releaseReservation(e),u}s.verdict!=="admitted"&&t.releaseReservation(e)}if(s?.verdict==="too_small")throw we(s);if(!c||s?.verdict==="denied"){if(r.capacity==="refuse")throw s?.verdict==="denied"?me(s):_e(U().automaticReviveCap,t.size());return n.frozen_at==null&&(ne(e,new Date().toISOString()),re(e,{reason:"frozen"}),oe({level:"info",event:"broker.frozen",node_id:e,fields:s?.verdict==="denied"?{reason:"app_memory",free_bytes:s.free_bytes,needed_bytes:s.needed_bytes}:{reason:"broker_cap",live_count:t.size(),hard_cap:U().automaticReviveCap}})),{parked:!1,result:{window:null,session:n.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await Ge(e,n,r)}}finally{t.releaseReservation(e)}}l(L,"decideRevive");async function Ge(e,r,i){if(!B(r.cwd)){const m=r.fork_from!=null?`Restore ${r.cwd}, then revive the fork normally with \`crtr node lifecycle revive ${e}\`.`:r.managed_worktree?.state==="open"?"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon recovery.":`Recreate ${r.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e}\`; durable node work resumes in a fresh conversation. Then retry \`crtr node lifecycle revive ${e}\`.`;throw new $({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:m})}r.host_kind!=="broker"&&(E(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!$e(e)&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(T(e),r.pi_session_id=null,r.pi_session_file=null);const t=r.fork_from!=null&&r.pi_session_id==null,c=r.fork_source_file;if(t&&(typeof c!="string"||!Q(c)))throw new $({error:"fork_source_invalid",message:`${e} cannot be revived \u2014 its resolved fork source file is missing or invalid.`,next:`Restore the node's fork source metadata, then retry \`crtr node lifecycle revive ${e}\`.`});const s=t&&typeof c=="string";if(s&&!G(c))throw new $({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${c}`,next:`Restore ${c}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const u=I(e,{daemonEpoch:M().epoch()});try{r.cycles=(r.cycles??0)+1,E(e,{cycles:r.cycles});const j=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,d=s?{}:Ue(e,r,j),w=d.resumeSessionPath!==void 0,C=w&&d.newCycle===!0,_=w&&!C,N=!w&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&Ke(e),g=_&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!be(e)&&!He(d.resumeSessionPath)?y(e)?.trim():void 0,F=g!==void 0&&g!=="",W=s||N||F,P=r.cycle_pending===!0||C;E(e,{cycle_pending:P}),r.cycle_pending=P,!s&&!w&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(T(e),r.pi_session_id=null,r.pi_session_file=null);let a,f=null;const b=l(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(s){const o=y(e),A=p(c);if(A===null)throw new Error(`invalid fork source ${c}`);const X=h().header(h().fork(A,e)).path;a=v(r,{resumeSessionPath:X,...o!=null&&o!==""?{prompt:o}:{}}),o!=null&&o!==""&&(f=b()),Re(e,Se(c)?.node_id??null)}else if(F)a=v(r,{...d,prompt:g}),f=b();else if(_)a=v(r,{...d,...i.wakeReason==="runtime-restart-abort"?{prompt:he}:{}}),i.wakeReason==="runtime-restart-abort"&&(f={type:"runtime",kind:"restart-continuation"});else if(N){const o=y(e)?.trim();a=v(r,o!==void 0&&o!==""?{prompt:o}:{}),o!==void 0&&o!==""&&(f=b()),K(e)}else{const o=ue(r,u);a=v(r,{...d,prompt:ae(r,o,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&o.unreadMessageIds?.length&&(a.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify(o.unreadMessageIds)),f=i.wakeReason!==void 0&&i.wakeReason!=="runtime-restart-abort"?{type:"runtime",kind:"wake",wake:i.wakeReason}:{type:"runtime",kind:"revive",cycle:r.cycles??0},K(e)}a.env={...a.env,CRTR_SUBTREE:xe(e)},f!==null&&(a.env[ve]=pe(f)),r.status==="done"&&r.last_settled_at!=null&&Ee(e,r.last_settled_at),x(e,r.intent==="refresh"?"refresh-launch":"revive"),ge(e,{preserveEpisode:!0});const J=ye(e);i.recovery!==!0&&i.viewerAttach!==!0&&se(e),Be(e,r.grantee);const V=Te(r.cwd,r.profile_id).plans.get("node:start")??[];await De(V,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:Oe(e),contextDir:Ae(e),jobDir:Pe(e)},runtime:{isBirth:W,canvasHome:Fe(),profile:r.profile_id??null}}),a.env={...a.env,CRTR_EXECUTION_ID:u};let k;try{if(k=await H.launch(e,a,{cwd:r.cwd,name:D(r),resuming:_}),k.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(o){try{x(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:o instanceof Error?o.message:String(o)}}}),ce(e,"notice.crash",`Child crashed \u2014 ${D(r)} (${e}) failed to relaunch and is now dead: ${o.message}
1
+ var Y=Object.defineProperty;var a=(e,r)=>Y(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as q}from"./unsandboxed.js";import{existsSync as B}from"node:fs";import{conversationIdFromPath as h,conversationStore as d,ConversationNotFoundError as O}from"../conversation-store/index.js";import{isAbsolute as Q}from"node:path";import{findNodeBySessionFile as Z,getNode as R,updateNode as E,beginExecution as I,recordExecutionPid as ee,abortExecution as S,endLiveExecution as re,unbindSession as T,recordLaunch as ie,setFrozen as te,clearFrozen as ne,fullName as D}from"../canvas/index.js";import{emitEvent as oe}from"../events/emit.js";import{cancelCronsOnWake as se}from"../canvas/crons.js";import{isParked as ae,transition as x}from"./lifecycle.js";import{publishNotice as le}from"./close.js";import{InputError as $}from"../io.js";import{buildPiArgv as p}from"./launch.js";import{buildReviveKickoff as ce,drainBearings as ue,hasRetainedReports as fe,readGoal as k,readYieldMessage as we,RUNTIME_RESTART_CONTINUATION as de}from"./kickoff.js";import{readRoadmap as z}from"./roadmap.js";import{encodeKickoffOrigin as he,KICKOFF_ORIGIN_ENV as pe}from"./stamp/protocol.js";import{headlessBrokerHost as H}from"./host.js";import{appMemoryFull as ve,appMemoryTooSmall as me,boundFleet as M,brokerCapReached as _e,brokerThresholdsForDaemon as U}from"./fleet.js";import{admitBrokerMemory as ye}from"./memory-admission.js";import{beginBootFaultAttempt as ke,clearFault as ge,hasAdmittedTurn as be}from"../canvas/recovery.js";import{clearNodeLedger as K,forkNodeLedger as Re,noticeChangedWhileDone as Ee}from"./ledger.js";import{forkSourceNode as Se,rootOfSpine as xe}from"./nodes.js";import{isReviewCompanionBound as $e}from"../review/companion.js";import{assertProfileActive as Ce}from"../profiles/manifest.js";import{isPidAlive as Ne}from"../canvas/pid.js";import{crtrHome as Fe,jobDir as Pe}from"../canvas/paths.js";import{contextDir as Ae,ensureNodeDirs as Be,nodeAgentDir as Oe}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as Te}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as De}from"../command-hooks/transport/exec-lifecycle.js";async function ze(e,r){const i=e.pi_session_file,t=i?h(i):null;if(t===null)return{};try{const n=await d().header(t);return r?{resumeSessionPath:n.path}:{resumeSessionPath:n.path,newCycle:!0}}catch(n){if(n instanceof O)return{};throw n}}a(ze,"resumeArgs");async function G(e){const r=h(e);if(r===null)return!1;try{return await d().header(r),!0}catch(i){if(i instanceof O)return!1;throw i}}a(G,"conversationExists");async function He(e){const r=h(e);return r===null?!0:(await d().read(r)).entries.some(i=>i.type==="message")}a(He,"sessionHasConversation");async function Me(e){const r=h(e);if(r===null)return!0;const i=(await d().header(r)).header.cwd;return typeof i!="string"||B(i)}a(Me,"sessionCwdExists");async function Ue(e,r,i){const t=r.pi_session_file;if(!t||!await G(t))return{};const n=await Z(t);return n!==null&&n.node_id!==e&&Ne(n.pi_pid)?{}:await Me(t)?await ze(r,i):{}}a(Ue,"resumableSessionArgs");async function Ke(e){return await z(e)===null&&await we(e)===null&&!await fe(e)}a(Ke,"isUnstartedBirth");async function _r(e){const r=await k(e);if(r!==null&&r.trim()!=="")return!0;const i=await z(e);return i!==null&&i.trim()!==""}a(_r,"hasFreshGroundState");async function yr(e,r){const i=await L(e,r,!0);if(i.parked)throw new Error(`reviveNode: internal parked decision for activating revive ${e}`);return i.result}a(yr,"reviveNode");async function kr(e,r,i){return L(e,{...r,viewerAttach:!0},i)}a(kr,"decideAttachRevive");async function L(e,r,i){let t=await R(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await R(e)??t,t.run_id&&(await R(t.run_id))?.deleting_at)throw new Error("run is deleting");if(t.final_report!==null)throw new Error(`reviveNode: refusing to revive ${e} \u2014 its finalization latch is set (final_report=${t.final_report}). A final landed between the caller's reopen-gate check and this revive; re-run with --reopen if this retask is still wanted.`);Ce(t.profile_id),q(t.grantee);const n=M();if(n.has(e))return await x(e,t.intent==="refresh"?"refresh-launch":"revive"),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(n.isClaimed(e))return{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(!i&&t.lifecycle==="resident"&&ae(t))return{parked:!0};const l=n.reserveSlot(e);let s=null;if(l){try{s=await ye(e)}catch(u){throw n.releaseReservation(e),u}s.verdict!=="admitted"&&n.releaseReservation(e)}if(s?.verdict==="too_small")throw me(s);if(!l||s?.verdict==="denied"){if(r.capacity==="refuse")throw s?.verdict==="denied"?ve(s):_e(U().automaticReviveCap,n.size());return t.frozen_at==null&&(await te(e,new Date().toISOString()),await re(e,{reason:"frozen"}),oe({level:"info",event:"broker.frozen",node_id:e,fields:s?.verdict==="denied"?{reason:"app_memory",free_bytes:s.free_bytes,needed_bytes:s.needed_bytes}:{reason:"broker_cap",live_count:n.size(),hard_cap:U().automaticReviveCap}})),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await Ge(e,t,r)}}finally{n.releaseReservation(e)}}a(L,"decideRevive");async function Ge(e,r,i){if(!B(r.cwd)){const v=r.fork_from!=null?`Restore ${r.cwd}, then revive the fork normally with \`crtr node lifecycle revive ${e}\`.`:r.managed_worktree?.state==="open"?"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon recovery.":`Recreate ${r.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e}\`; durable node work resumes in a fresh conversation. Then retry \`crtr node lifecycle revive ${e}\`.`;throw new $({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:v})}r.host_kind!=="broker"&&(await E(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await $e(e)&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await T(e),r.pi_session_id=null,r.pi_session_file=null);const n=r.fork_from!=null&&r.pi_session_id==null,l=r.fork_source_file;if(n&&(typeof l!="string"||!Q(l)))throw new $({error:"fork_source_invalid",message:`${e} cannot be revived \u2014 its resolved fork source file is missing or invalid.`,next:`Restore the node's fork source metadata, then retry \`crtr node lifecycle revive ${e}\`.`});const s=n&&typeof l=="string";if(s&&!await G(l))throw new $({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${l}`,next:`Restore ${l}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const u=await I(e,{daemonEpoch:M().epoch()});try{r.cycles=(r.cycles??0)+1,await E(e,{cycles:r.cycles});const j=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,w=s?{}:await Ue(e,r,j),m=w.resumeSessionPath!==void 0,C=m&&w.newCycle===!0,_=m&&!C,N=!m&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await Ke(e),g=_&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await be(e)&&!await He(w.resumeSessionPath)?(await k(e))?.trim():void 0,F=g!==void 0&&g!=="",W=s||N||F,P=r.cycle_pending===!0||C;await E(e,{cycle_pending:P}),r.cycle_pending=P,!s&&!m&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await T(e),r.pi_session_id=null,r.pi_session_file=null);let c,f=null;const b=a(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(s){const o=await k(e),A=h(l);if(A===null)throw new Error(`invalid fork source ${l}`);const X=(await d().header(await d().fork(A,e))).path;c=p(r,{resumeSessionPath:X,...o!=null&&o!==""?{prompt:o}:{}}),o!=null&&o!==""&&(f=b()),await Re(e,(await Se(l))?.node_id??null)}else if(F)c=p(r,{...w,prompt:g}),f=b();else if(_)c=p(r,{...w,...i.wakeReason==="runtime-restart-abort"?{prompt:de}:{}}),i.wakeReason==="runtime-restart-abort"&&(f={type:"runtime",kind:"restart-continuation"});else if(N){const o=(await k(e))?.trim();c=p(r,o!==void 0&&o!==""?{prompt:o}:{}),o!==void 0&&o!==""&&(f=b()),await K(e)}else{const o=await ue(r,u);c=p(r,{...w,prompt:await ce(r,o,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&o.unreadMessageIds?.length&&(c.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify(o.unreadMessageIds)),f=i.wakeReason!==void 0&&i.wakeReason!=="runtime-restart-abort"?{type:"runtime",kind:"wake",wake:i.wakeReason}:{type:"runtime",kind:"revive",cycle:r.cycles??0},await K(e)}c.env={...c.env,CRTR_SUBTREE:await xe(e)},f!==null&&(c.env[pe]=he(f)),r.status==="done"&&r.last_settled_at!=null&&await Ee(e,r.last_settled_at),await x(e,r.intent==="refresh"?"refresh-launch":"revive"),await ge(e,{preserveEpisode:!0});const J=await ke(e);i.recovery!==!0&&i.viewerAttach!==!0&&await se(e),await Be(e,r.grantee);const V=Te(r.cwd,r.profile_id).plans.get("node:start")??[];await De(V,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await Oe(e),contextDir:await Ae(e),jobDir:Pe(e)},runtime:{isBirth:W,canvasHome:Fe(),profile:r.profile_id??null}}),c.env={...c.env,CRTR_EXECUTION_ID:u};let y;try{if(y=await H.launch(e,c,{cwd:r.cwd,name:D(r),resuming:_}),y.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(o){try{await x(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:o instanceof Error?o.message:String(o)}}}),await le(e,"notice.crash",`Child crashed \u2014 ${D(r)} (${e}) failed to relaunch and is now dead: ${o.message}
2
2
 
3
- It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw S(u,{reason:"launch_failed"}),new Error(`[broker] refusing to revive ${e}: ${o.message}`)}if(ie(e,new Date().toISOString()),ee(u,e,k.pid)==="shutdown")throw S(u,{reason:"superseded"}),H.teardown(e),new Error(`[broker] refusing to revive ${e}: execution was superseded during launch`);return te(e),{window:null,session:r.tmux_session??null,resumed:_,launch:k,faultExplanation:J.explanation,outcome:"launched"}}catch(m){throw S(u,{reason:"launch_failed"}),m}}l(Ge,"launchRevive");export{yr as decideAttachRevive,_r as hasFreshGroundState,ze as resumeArgs,kr as reviveNode};
3
+ It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw await S(u,{reason:"launch_failed"}),new Error(`[broker] refusing to revive ${e}: ${o.message}`)}if(await ie(e,new Date().toISOString()),await ee(u,e,y.pid)==="shutdown")throw await S(u,{reason:"superseded"}),H.teardown(e),new Error(`[broker] refusing to revive ${e}: execution was superseded during launch`);return await ne(e),{window:null,session:r.tmux_session??null,resumed:_,launch:y,faultExplanation:J.explanation,outcome:"launched"}}catch(v){throw await S(u,{reason:"launch_failed"}),v}}a(Ge,"launchRevive");export{kr as decideAttachRevive,_r as hasFreshGroundState,ze as resumeArgs,yr as reviveNode};
@@ -1,4 +1,4 @@
1
- import type { DatabaseSync } from 'node:sqlite';
1
+ import { type CanvasDb } from '../canvas/db.js';
2
2
  export declare const ROADMAP_NAME = "roadmap";
3
3
  /** Fallback preview when the roadmap is seeded without a goal. */
4
4
  export declare const ROADMAP_PREVIEW = "To understand this node's long-term task and current plan, read this.";
@@ -6,19 +6,19 @@ export declare const ROADMAP_PREVIEW = "To understand this node's long-term task
6
6
  export declare function roadmapPreview(goal?: string): string;
7
7
  /** How a node addresses its own roadmap in `crtr canvas read` / `crtr doc edit`. */
8
8
  export declare function roadmapRef(nodeId: string): string;
9
- export declare function hasRoadmap(nodeId: string): boolean;
9
+ export declare function hasRoadmap(nodeId: string): Promise<boolean>;
10
10
  /** The roadmap's newest head body, or null when the node has none. */
11
- export declare function readRoadmap(nodeId: string): string | null;
11
+ export declare function readRoadmap(nodeId: string): Promise<string | null>;
12
12
  /** Seed a fresh, EXTREMELY BAREBONES roadmap document — the section skeleton
13
13
  * with one-line prompts — authored by the node. The owner fleshes it out as
14
14
  * its next act with `crtr doc edit roadmap`. Leaves an existing roadmap
15
15
  * untouched and returns null; otherwise returns the seeded body. */
16
- export declare function seedRoadmap(db: DatabaseSync, nodeId: string, opts?: {
16
+ export declare function seedRoadmap(db: CanvasDb, nodeId: string, opts?: {
17
17
  goal?: string;
18
18
  exitCriteria?: string;
19
- }): string | null;
19
+ }): Promise<string | null>;
20
20
  /** `seedRoadmap` in its own canvas write; true when it wrote one. */
21
21
  export declare function ensureRoadmap(nodeId: string, opts?: {
22
22
  goal?: string;
23
23
  exitCriteria?: string;
24
- }): boolean;
24
+ }): Promise<boolean>;
@@ -1,15 +1,15 @@
1
- var l=Object.defineProperty;var r=(e,n)=>l(e,"name",{value:n,configurable:!0});import{openDb as u,withCanvasWrite as d}from"../canvas/db.js";import{get as s}from"../graph/bodies.js";import{heads as m,writeDocument as p}from"../graph/documents.js";import{asRuntimeWriter as c}from"../graph/spaces/own-memory.js";import{getById as f,liveDocumentNamed as h,nodeObject as g}from"../graph/objects.js";import{readerForNode as w}from"../graph/reader.js";const i="roadmap",x="To understand this node's long-term task and current plan, read this.";function R(e){return e?.split(`
2
- `).map(t=>t.trim()).find(t=>t!=="")??x}r(R,"roadmapPreview");function P(e){return`${e}/${i}`}r(P,"roadmapRef");function a(e,n){const t=f(e,n);return t===null||t.type!=="node"?null:h(e,t.rowid,i)}r(a,"roadmapObject");function $(e){return a(u(),e)!==null}r($,"hasRoadmap");function M(e){const n=u(),t=a(n,e);if(t===null)return null;const o=m(n,t)[0];if(o===void 0)return null;try{return s(o.body_hash)}catch{return null}}r(M,"readRoadmap");function y(e){return`# Roadmap
1
+ var l=Object.defineProperty;var r=(t,e)=>l(t,"name",{value:e,configurable:!0});import{openDb as u,withCanvasWrite as s}from"../canvas/db.js";import{get as c}from"../graph/bodies.js";import{heads as d,writeDocument as m}from"../graph/documents.js";import{asRuntimeWriter as p}from"../graph/spaces/own-memory.js";import{getById as f,liveDocumentNamed as w,nodeObject as h}from"../graph/objects.js";import{readerForNode as y}from"../graph/reader.js";const o="roadmap",g="To understand this node's long-term task and current plan, read this.";function x(t){return t?.split(`
2
+ `).map(n=>n.trim()).find(n=>n!=="")??g}r(x,"roadmapPreview");function P(t){return`${t}/${o}`}r(P,"roadmapRef");async function i(t,e){const n=await f(t,e);return n===null||n.type!=="node"?null:await w(t,n.rowid,o)}r(i,"roadmapObject");async function $(t){return await i(await u(),t)!==null}r($,"hasRoadmap");async function M(t){const e=await u(),n=await i(e,t);if(n===null)return null;const a=(await d(e,n))[0];if(a===void 0)return null;try{return c(a.body_hash)}catch{return null}}r(M,"readRoadmap");function R(t){return`# Roadmap
3
3
 
4
4
  ## Goal
5
- ${e.goal?.trim()||"(the goal you now own)"}
5
+ ${t.goal?.trim()||"(the goal you now own)"}
6
6
 
7
7
  ## Exit criteria
8
- ${e.exitCriteria?.trim()||'(what "done" looks like)'}
8
+ ${t.exitCriteria?.trim()||'(what "done" looks like)'}
9
9
 
10
10
  ## Where things stand
11
11
  (present state at your level: settled, in flight, remaining)
12
12
 
13
13
  ## Working set
14
14
  (links to the documents the work depends on now, one per line)
15
- `}r(y,"scaffold");function k(e,n,t={}){if(a(e,n)!==null)return null;const o=y(t);return p(e,c(w(e,n,()=>[])),{owner:g(e,n),name:i,kind:"knowledge",preview:R(t.goal),privacy:"public",rules:[{on:"boot",deliver:"content"}]},o),o}r(k,"seedRoadmap");function N(e,n={}){return d(t=>k(t,e,n)!==null)}r(N,"ensureRoadmap");export{i as ROADMAP_NAME,x as ROADMAP_PREVIEW,N as ensureRoadmap,$ as hasRoadmap,M as readRoadmap,R as roadmapPreview,P as roadmapRef,k as seedRoadmap};
15
+ `}r(R,"scaffold");async function k(t,e,n={}){if(await i(t,e)!==null)return null;const a=R(n);return await m(t,p(await y(t,e,async()=>[])),{owner:await h(t,e),name:o,kind:"knowledge",preview:x(n.goal),privacy:"public",rules:[{on:"boot",deliver:"content"}]},a),a}r(k,"seedRoadmap");async function N(t,e={}){return await s(async n=>await k(n,t,e)!==null)}r(N,"ensureRoadmap");export{o as ROADMAP_NAME,g as ROADMAP_PREVIEW,N as ensureRoadmap,$ as hasRoadmap,M as readRoadmap,x as roadmapPreview,P as roadmapRef,k as seedRoadmap};
@@ -4,4 +4,4 @@ export interface HumanForkCoordinates {
4
4
  leafId: string;
5
5
  }
6
6
  /** Fork the captured root-to-leaf branch without opening or mutating its live source. */
7
- export declare function materializeSessionBranch(coordinates: HumanForkCoordinates): string;
7
+ export declare function materializeSessionBranch(coordinates: HumanForkCoordinates): Promise<string>;
@@ -1 +1 @@
1
- var n=Object.defineProperty;var s=(e,r)=>n(e,"name",{value:r,configurable:!0});import{conversationIdFromPath as i,conversationStore as t}from"../conversation-store/index.js";function c(e){if(e.sourceSessionId===""||e.leafId==="")throw new Error("session branch coordinates require source session and leaf ids");const r=i(e.sourceFile);if(r===null||r!==e.sourceSessionId)throw new Error("source session id does not match captured coordinates");const o=t();if(o.header(r).header.id!==e.sourceSessionId)throw new Error("source session id does not match captured coordinates");return o.header(o.fork(r,void 0,e.leafId)).path}s(c,"materializeSessionBranch");export{c as materializeSessionBranch};
1
+ var n=Object.defineProperty;var s=(e,r)=>n(e,"name",{value:r,configurable:!0});import{conversationIdFromPath as i,conversationStore as a}from"../conversation-store/index.js";async function c(e){if(e.sourceSessionId===""||e.leafId==="")throw new Error("session branch coordinates require source session and leaf ids");const r=i(e.sourceFile);if(r===null||r!==e.sourceSessionId)throw new Error("source session id does not match captured coordinates");const o=a();if((await o.header(r)).header.id!==e.sourceSessionId)throw new Error("source session id does not match captured coordinates");return(await o.header(await o.fork(r,void 0,e.leafId))).path}s(c,"materializeSessionBranch");export{c as materializeSessionBranch};
@@ -1 +1 @@
1
- var T=Object.defineProperty;var c=(t,e)=>T(t,"name",{value:e,configurable:!0});import{readFile as D,rename as N,unlink as C,writeFile as A}from"node:fs/promises";import{resolve as M}from"node:path";import{conversationStore as p,ConversationNotFoundError as F}from"../conversation-store/index.js";const S=1024;function E(t){if(t.length<=S)return t;const e=S/2;return`${t.slice(0,e)} \u2026 ${t.slice(-e)}`}c(E,"compactSessionSearchText");const w=1,P=2e3;function g(t){return typeof t=="number"&&Number.isFinite(t)&&t>=0}c(g,"isFiniteNonNeg");function b(t){return t===void 0||typeof t=="string"}c(b,"isOptionalString");function x(t){if(typeof t!="object"||t===null)return!1;const e=t;return typeof e.path=="string"&&typeof e.id=="string"&&typeof e.cwd=="string"&&typeof e.created=="string"&&typeof e.modified=="string"&&g(e.messageCount)&&typeof e.firstMessage=="string"&&typeof e.allMessagesText=="string"&&b(e.name)&&b(e.parentSessionPath)}c(x,"isValidWireInfo");function O(t){if(typeof t!="object"||t===null)return!1;const e=t;return g(e.mtimeMs)&&g(e.size)&&x(e.info)}c(O,"isValidEntry");function _(t){const e=t.content;return typeof e=="string"?e:Array.isArray(e)?e.filter(i=>i.type==="text").map(i=>i.text).join(" "):""}c(_,"extractTextContent");function k(t){const e=t.message;if(!e||!("content"in e))return;const i=e.role;if(i!=="user"&&i!=="assistant")return;const s=e.timestamp;if(typeof s=="number")return s;const n=new Date(t.timestamp).getTime();return Number.isNaN(n)?void 0:n}c(k,"messageActivityTime");function v(t){try{const e=t.header;let i=0,s="";const n=[];let a,h;for(const f of p().read(t.conversation_id).entries){if(f.type==="session_info"&&(a=f.name?.trim()||void 0),f.type!=="message")continue;i++;const y=k(f);typeof y=="number"&&(h=Math.max(h??0,y));const u=f.message;if(!u||!("content"in u))continue;const m=u.role;if(m!=="user"&&m!=="assistant")continue;const d=_(u);d&&(n.push(d),!s&&m==="user"&&(s=d))}const r=typeof e.cwd=="string"?e.cwd:"",o=typeof e.timestamp=="string"?new Date(e.timestamp).getTime():NaN,l=typeof h=="number"&&h>0?new Date(h):Number.isNaN(o)?new Date(t.mtime):new Date(o);return{path:t.path,id:e.id,cwd:r,name:a,parentSessionPath:e.parentSession,created:new Date(e.timestamp).toISOString(),modified:l.toISOString(),messageCount:i,firstMessage:s||"(no messages)",allMessagesText:E(n.join(" "))}}catch(e){if(e instanceof F)return null;throw e}}c(v,"buildWireSessionInfo");class H{static{c(this,"SessionListCache")}cacheFile;cache=new Map;inflightDir=new Map;loadPromise=null;buildChain=Promise.resolve();persisting=!1;persistAgain=!1;persistTimer=null;constructor(e){this.cacheFile=e}listDir(e){const i=M(e),s=this.inflightDir.get(i);if(s)return s;const n=Promise.resolve().then(()=>this.buildDir(i));this.inflightDir.set(i,n);const a=c(()=>{this.inflightDir.get(i)===n&&this.inflightDir.delete(i)},"clear");return n.then(a,a),n}buildDir(e){const i=p().list().filter(s=>s.header.cwd===e);return this.build(i,s=>this.cache.get(s)?.info.cwd===e)}async listAll(){return this.build(p().list(),()=>!0)}build(e,i){const s=this.buildChain.then(()=>this.buildLocked(e,i));return this.buildChain=s.then(()=>{},()=>{}),s}async buildLocked(e,i){await this.ensureLoaded();const s=new Set(e.map(({path:r})=>r));let n=!1;for(const r of this.cache.keys())!s.has(r)&&i(r)&&(this.cache.delete(r),n=!0);const a=new Array(e.length);for(const[r,o]of e.entries()){const l=this.cache.get(o.path);if(l&&l.mtimeMs===o.mtime&&l.size===o.size){a[r]=l.info;continue}const f=v(o);if(n=!0,!f){this.cache.delete(o.path);continue}this.cache.set(o.path,{mtimeMs:o.mtime,size:o.size,info:f}),a[r]=f}n&&this.schedulePersist();const h=a.filter(r=>r!==void 0);return h.sort((r,o)=>new Date(o.modified).getTime()-new Date(r.modified).getTime()),h}ensureLoaded(){return this.loadPromise||(this.loadPromise=this.loadFromDisk()),this.loadPromise}async loadFromDisk(){try{const e=JSON.parse(await D(this.cacheFile,"utf8"));if(e?.version!==w||typeof e.entries!="object")return;for(const[i,s]of Object.entries(e.entries)){if(!O(s)){this.cache.clear();return}this.cache.set(i,s)}}catch{this.cache.clear()}}schedulePersist(){this.persistTimer||(this.persistTimer=setTimeout(()=>{this.persistTimer=null,this.persist()},P),this.persistTimer.unref?.())}async persist(){if(this.persisting){this.persistAgain=!0;return}this.persisting=!0;const e=`${this.cacheFile}.${process.pid}.tmp`;try{const i={};for(const[n,a]of this.cache)i[n]=a;await A(e,JSON.stringify({version:w,entries:i})),await N(e,this.cacheFile)}catch{await C(e).catch(()=>{})}finally{this.persisting=!1,this.persistAgain&&(this.persistAgain=!1,this.persist())}}}export{H as SessionListCache,E as compactSessionSearchText};
1
+ var T=Object.defineProperty;var c=(t,e)=>T(t,"name",{value:e,configurable:!0});import{readFile as D,rename as N,unlink as C,writeFile as A}from"node:fs/promises";import{resolve as M}from"node:path";import{conversationStore as p,ConversationNotFoundError as F}from"../conversation-store/index.js";const w=1024;function E(t){if(t.length<=w)return t;const e=w/2;return`${t.slice(0,e)} \u2026 ${t.slice(-e)}`}c(E,"compactSessionSearchText");const S=1,P=2e3;function g(t){return typeof t=="number"&&Number.isFinite(t)&&t>=0}c(g,"isFiniteNonNeg");function b(t){return t===void 0||typeof t=="string"}c(b,"isOptionalString");function x(t){if(typeof t!="object"||t===null)return!1;const e=t;return typeof e.path=="string"&&typeof e.id=="string"&&typeof e.cwd=="string"&&typeof e.created=="string"&&typeof e.modified=="string"&&g(e.messageCount)&&typeof e.firstMessage=="string"&&typeof e.allMessagesText=="string"&&b(e.name)&&b(e.parentSessionPath)}c(x,"isValidWireInfo");function O(t){if(typeof t!="object"||t===null)return!1;const e=t;return g(e.mtimeMs)&&g(e.size)&&x(e.info)}c(O,"isValidEntry");function _(t){const e=t.content;return typeof e=="string"?e:Array.isArray(e)?e.filter(i=>i.type==="text").map(i=>i.text).join(" "):""}c(_,"extractTextContent");function k(t){const e=t.message;if(!e||!("content"in e))return;const i=e.role;if(i!=="user"&&i!=="assistant")return;const s=e.timestamp;if(typeof s=="number")return s;const n=new Date(t.timestamp).getTime();return Number.isNaN(n)?void 0:n}c(k,"messageActivityTime");async function v(t){try{const e=t.header;let i=0,s="";const n=[];let a,h;for(const f of(await p().read(t.conversation_id)).entries){if(f.type==="session_info"&&(a=f.name?.trim()||void 0),f.type!=="message")continue;i++;const y=k(f);typeof y=="number"&&(h=Math.max(h??0,y));const u=f.message;if(!u||!("content"in u))continue;const m=u.role;if(m!=="user"&&m!=="assistant")continue;const d=_(u);d&&(n.push(d),!s&&m==="user"&&(s=d))}const r=typeof e.cwd=="string"?e.cwd:"",o=typeof e.timestamp=="string"?new Date(e.timestamp).getTime():NaN,l=typeof h=="number"&&h>0?new Date(h):Number.isNaN(o)?new Date(t.mtime):new Date(o);return{path:t.path,id:e.id,cwd:r,name:a,parentSessionPath:e.parentSession,created:new Date(e.timestamp).toISOString(),modified:l.toISOString(),messageCount:i,firstMessage:s||"(no messages)",allMessagesText:E(n.join(" "))}}catch(e){if(e instanceof F)return null;throw e}}c(v,"buildWireSessionInfo");class H{static{c(this,"SessionListCache")}cacheFile;cache=new Map;inflightDir=new Map;loadPromise=null;buildChain=Promise.resolve();persisting=!1;persistAgain=!1;persistTimer=null;constructor(e){this.cacheFile=e}listDir(e){const i=M(e),s=this.inflightDir.get(i);if(s)return s;const n=Promise.resolve().then(()=>this.buildDir(i));this.inflightDir.set(i,n);const a=c(()=>{this.inflightDir.get(i)===n&&this.inflightDir.delete(i)},"clear");return n.then(a,a),n}async buildDir(e){const i=(await p().list()).filter(s=>s.header.cwd===e);return this.build(i,s=>this.cache.get(s)?.info.cwd===e)}async listAll(){return this.build(await p().list(),()=>!0)}build(e,i){const s=this.buildChain.then(()=>this.buildLocked(e,i));return this.buildChain=s.then(()=>{},()=>{}),s}async buildLocked(e,i){await this.ensureLoaded();const s=new Set(e.map(({path:r})=>r));let n=!1;for(const r of this.cache.keys())!s.has(r)&&i(r)&&(this.cache.delete(r),n=!0);const a=new Array(e.length);for(const[r,o]of e.entries()){const l=this.cache.get(o.path);if(l&&l.mtimeMs===o.mtime&&l.size===o.size){a[r]=l.info;continue}const f=await v(o);if(n=!0,!f){this.cache.delete(o.path);continue}this.cache.set(o.path,{mtimeMs:o.mtime,size:o.size,info:f}),a[r]=f}n&&this.schedulePersist();const h=a.filter(r=>r!==void 0);return h.sort((r,o)=>new Date(o.modified).getTime()-new Date(r.modified).getTime()),h}ensureLoaded(){return this.loadPromise||(this.loadPromise=this.loadFromDisk()),this.loadPromise}async loadFromDisk(){try{const e=JSON.parse(await D(this.cacheFile,"utf8"));if(e?.version!==S||typeof e.entries!="object")return;for(const[i,s]of Object.entries(e.entries)){if(!O(s)){this.cache.clear();return}this.cache.set(i,s)}}catch{this.cache.clear()}}schedulePersist(){this.persistTimer||(this.persistTimer=setTimeout(()=>{this.persistTimer=null,this.persist()},P),this.persistTimer.unref?.())}async persist(){if(this.persisting){this.persistAgain=!0;return}this.persisting=!0;const e=`${this.cacheFile}.${process.pid}.tmp`;try{const i={};for(const[n,a]of this.cache)i[n]=a;await A(e,JSON.stringify({version:S,entries:i})),await N(e,this.cacheFile)}catch{await C(e).catch(()=>{})}finally{this.persisting=!1,this.persistAgain&&(this.persistAgain=!1,this.persist())}}}export{H as SessionListCache,E as compactSessionSearchText};
@@ -1 +1 @@
1
- var i=Object.defineProperty;var n=(t,e)=>i(t,"name",{value:e,configurable:!0});import{getNode as r}from"../canvas/index.js";import{deliverCustomMessageLive as a}from"./deliver-live.js";import{appendSituationalContext as l,formatSituationalProse as u,situationalContextEnvelope as s,SITUATIONAL_CONTEXT_CUSTOM_TYPE as m}from"./situational-context.js";async function C(t,e){if(l(t,u(e)),r(t)===null)throw new Error(`setSituationalContextLive: unknown node ${t}`);const o=s(t);o!==null&&await a(t,{customType:m,content:o,deliverAs:"nextTurn"})}n(C,"setSituationalContextLive");export{C as setSituationalContextLive};
1
+ var i=Object.defineProperty;var n=(t,e)=>i(t,"name",{value:e,configurable:!0});import{getNode as a}from"../canvas/index.js";import{deliverCustomMessageLive as r}from"./deliver-live.js";import{appendSituationalContext as l,formatSituationalProse as u,situationalContextEnvelope as s,SITUATIONAL_CONTEXT_CUSTOM_TYPE as m}from"./situational-context.js";async function C(t,e){if(l(t,u(e)),await a(t)===null)throw new Error(`setSituationalContextLive: unknown node ${t}`);const o=s(t);o!==null&&await r(t,{customType:m,content:o,deliverAs:"nextTurn"})}n(C,"setSituationalContextLive");export{C as setSituationalContextLive};
@@ -98,7 +98,7 @@ export interface SpawnChildOpts {
98
98
  * relative path is made absolute; a bare/partial uuid is resolved against pi's
99
99
  * sessions store. Throws when a known node has no captured session file, or when
100
100
  * a uuid resolves to zero or multiple sessions. */
101
- export declare function resolveForkSource(value: string): string;
101
+ export declare function resolveForkSource(value: string): Promise<string>;
102
102
  /** Resolve the profile a spawned child runs under: an explicit `--profile`
103
103
  * operand (id, name, or closest match) resolved through `resolveProfileOperand`, else INHERIT
104
104
  * the spawner's current `profile_id` (null when the spawner has none). `--root`
@@ -112,7 +112,7 @@ export declare function resolveProfileId(explicit: string | null | undefined, sp
112
112
  }): Promise<string | null>;
113
113
  /** Under an app-paid grant (RT-RTE-24) the node's model is the app rung resolver's choice, never the owner's ladder: the
114
114
  * recipe records the rung's catalog model and the intent `app/<strength>`. A user-paid grant leaves the recipe as built. */
115
- export declare function appPaidLaunch(launch: LaunchSpec, grantId: string | null | undefined, requested: string | undefined): LaunchSpec;
115
+ export declare function appPaidLaunch(launch: LaunchSpec, grantId: string | null | undefined, requested: string | undefined): Promise<LaunchSpec>;
116
116
  /** Reject a permanently invalid launch recipe against the registry that will
117
117
  * serve it. Registered-but-unauthenticated/cooling requests intentionally pass
118
118
  * this authoring check so broker policy for transient availability is unchanged. */
@@ -1,3 +1,3 @@
1
- var ae=Object.defineProperty;var a=(e,o)=>ae(e,"name",{value:o,configurable:!0});import{accessSync as se,constants as le}from"node:fs";import{isAbsolute as ce,resolve as fe,join as ue}from"node:path";import{appSpace as me}from"../layout.js";import{ApiError as q}from"../../api/errors.js";import{spawnNode as he,forkSourceNode as we,currentNodeContext as pe,rootOfSpine as ke,newNodeId as _e,preflightNodeId as ve}from"./nodes.js";import{resolveProfileOperand as ge}from"../profiles/manifest.js";import{selectProfileForCwd as ye,selectProfileForCwdReadOnly as be}from"../profiles/select.js";import{buildLaunchSpecAsync as Y,buildPiArgv as xe}from"./launch.js";import{createManagedWorktreeAsync as Ce,rollbackManagedWorktreeAsync as Ee}from"../worktree-mutation-async.js";import{usage as u,brokerLaunchFailed as I}from"../errors.js";import{writeGoal as $e}from"./kickoff.js";import{appendSituationalContext as Fe,formatSituationalProse as Oe}from"./situational-context.js";import{ensureRoadmap as Re}from"./roadmap.js";import{buildWakeBearings as Se}from"./bearings.js";import{encodeKickoffOrigin as Ie,KICKOFF_ORIGIN_ENV as Ne}from"./stamp/protocol.js";import{beginExecution as Pe,crtrHome as De,getNode as f,fullName as J,jobDir as Te,recordExecutionPid as Be,abortExecution as B,setFrozen as Le}from"../canvas/index.js";import{contextDir as L,nodeAgentDir as A}from"../canvas/node-agent-paths.js";import{copyTreeBeneath as Ae}from"../spaces/open-beneath.js";import{conversationIdFromPath as N,conversationStore as x}from"../conversation-store/index.js";import{appMemoryTooSmall as Me,boundFleet as je,brokerThresholdsForDaemon as We}from"./fleet.js";import{admitBrokerMemory as He}from"./memory-admission.js";import{emitEvent as Ke}from"../events/emit.js";import{openViewerWindow as ze,focusOf as Ge,windowOfPane as Ue}from"./placement.js";import{waitForBrokerViewSocket as Ve}from"./placement-tmux.js";import{transition as w}from"./lifecycle.js";import{beginBootFaultAttempt as Xe}from"../canvas/recovery.js";import{headlessBrokerHost as M}from"./host.js";import{ensureDaemon as qe}from"../../daemon/manage.js";import{readConfig as Ye}from"../config.js";import{modelRequestFromConfig as Je,unregisteredConcreteModel as Qe}from"../model-routes.js";import{openModelRegistry as Ze}from"./model-registry.js";import{MODEL_SPEC_NEXT as en}from"./model-selection.js";import{forkNodeLedger as nn}from"./ledger.js";import{appRungForGrant as on}from"../llm/app-rungs.js";import{APP_FAMILY as j}from"../model-routes.js";import{discoverLifecycleHookRegistry as rn}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as tn}from"../command-hooks/transport/exec-lifecycle.js";function p(e){return{detail:{schema:"crtr.node-outcome-detail/v1",message:e instanceof Error?e.message:String(e)}}}a(p,"launchFailureOutcome");async function dn(e,o,d){try{return await M.launch(e,o,d)}catch(r){try{w(e,"crash",{reason:"launch_failed",outcome:p(r)})}catch{}const t=r.message;throw I(t.startsWith("[broker]")?t:`[broker] refusing to launch ${e}: ${t}`,"Inspect the cause above, fix the launch recipe or environment, then retry.")}}a(dn,"launchBrokerOrCrash");function an(e,o){try{w(e,"crash",{reason:"launch_failed",outcome:p(o)})}catch{}try{M.teardown(e)}catch{}}a(an,"crashAndTearDown");function sn(e){const o=x().list().map(({conversation_id:t,path:s})=>({id:t,path:s})),d=o.filter(t=>t.id===e),r=d.length>0?d:o.filter(t=>t.id.startsWith(e));if(r.length===0)throw u(`--fork-from '${e}': no pi session with that id found.`,{next:"Pass a live node id, a real session uuid/prefix, or an absolute .jsonl session path."});if(r.length>1)throw u(`--fork-from '${e}': ambiguous \u2014 ${r.length} sessions match that id prefix; pass the full id or the .jsonl path.`,{next:"Pass the full session uuid or an absolute .jsonl path to disambiguate."});return r[0].path}a(sn,"resolveSessionUuid");function Q(e){const o=e.trim();if(o==="")throw u("--fork-from requires a node id, session file, or session uuid.",{next:"Pass a live node id, an absolute .jsonl session path, or a session uuid/prefix."});if(o.includes("/")||o.endsWith(".jsonl")){const r=N(ce(o)?o:fe(process.cwd(),o));if(r===null)throw u(`--fork-from '${o}': invalid conversation path.`,{next:"Pass a conversation file path or id."});return x().header(r).path}const d=f(o);if(d!==null){const r=d.pi_session_file;if(r==null||r==="")throw u(`node ${o} has no pi session yet \u2014 it has not captured a session FILE to fork from (the broker forks a .jsonl path, not a bare id).`,{next:"Pick a node that has captured a session, or drop --fork-from."});const t=N(r);if(t===null)throw u(`node ${o} has no valid conversation id.`,{next:"Pick a node with a captured conversation."});return x().header(t).path}return sn(o)}a(Q,"resolveForkSource");async function ln(e,o,d,r={}){return e===null?null:e!==void 0&&e!==""?ge(e).profileId:o!==null?f(o)?.profile_id??null:r.readOnlySelection===!0?be(d):ye(d)}a(ln,"resolveProfileId");function Z(e){const o=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return Je(e.model,o,e.modelExact===!0)}a(Z,"requestFromLaunch");function ee(e,o,d){const r=d??(e.modelIntent?`${e.modelIntent.family}/${e.modelIntent.strength}`:e.model),t=on(o,r,e.modelExact===!0);if(t===null)return e;const{CRTR_MODEL_INTENT:s,...l}=e.env??{};return{...e,model:t.model,modelIntent:{family:j,strength:t.strength},modelExact:void 0,env:{...l,CRTR_MODEL_INTENT:`${j}/${t.strength}`}}}a(ee,"appPaidLaunch");async function ne(e,o,d){if(e===void 0||e.kind==="logical"&&e.family!==j)return;const r=Qe(e.kind==="logical"?{kind:"concrete",spec:e.spec}:e,d??await Ze(),o);if(r!==void 0)throw u(`model '${r.request.spec}' is not registered in this daemon.`,{received:r.request.spec,next:en})}a(ne,"assertLaunchModelRegistered");function cn(e,o,d){const r=e??o??null;if(!d&&r===null)throw new Error("spawnChild requires a calling node (CRTR_NODE_ID) or an explicit parent");return r}a(cn,"resolveSpawner");async function oe(e,o,d){try{qe()}catch{}const r=pe(),t=e.root===!0,s=cn(e.parent,r.nodeId??null,t),l=e.mode??"base",k=e.rootLifecycle??(t?"resident":"terminal"),re=t&&k==="resident",P=s===null?null:f(s),ie=e.creator===void 0||e.creator===null?null:f(e.creator);e.nodeId!==void 0&&ve(e.nodeId);const _=e.forkFrom!==void 0?Q(e.forkFrom):void 0,W=_===void 0?null:we(_),D=[P,ie,W].some(c=>c?.isolated===!0||c?.run_id!=null&&f(c.run_id)?.isolated===!0);if(D&&e.isolated===!1)throw new q(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});const $=D||e.isolated===!0;if($&&e.worktree===!0)throw new q(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const F=e.worktree===!0,v=$||F?e.nodeId??_e():e.nodeId,O=$?e.run!==void 0&&t&&!D?e.cwd:ue(me(e.run?.grantee??P?.grantee??"app:terminal").nodes,v):e.cwd,C=await ln(e.profile,s,O),H=e.run?.grant_id??P?.grant_id??null,K=ee((await Y(e.kind,l,{lifecycle:k,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:O,profileId:C})).launch,H,e.model);await ne(Z(K),{cwd:O,profileId:C});const z=W?.node_id??null;let g,R=O;try{F&&(g=await Ce(e.worktreeCwd??e.cwd,v,e.worktreeBase),R=g.path);const c=F?ee((await Y(e.kind,l,{lifecycle:k,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:R,profileId:C})).launch,H,e.model):K;F&&await ne(Z(c),{cwd:R,profileId:C});const n=await he({kind:e.kind,mode:l,lifecycle:k,cwd:R,name:e.name??e.kind,description:e.description,parent:t?null:s,creator:e.creator,...e.actor===void 0?{}:{actor:e.actor},forkSourceNode:z,spawnedBy:t?s??void 0:void 0,profile_id:C,...e.scopes===void 0?{}:{scopes:e.scopes},isolated:$,...e.run===void 0?{}:{run:e.run},...e.withinCreate===void 0?{}:{withinCreate:e.withinCreate},forkFrom:e.forkFrom,forkSourceFile:_,modelOverride:e.model===void 0?void 0:c.model,...g!==void 0?{managedWorktree:g}:{},...v!==void 0?{nodeId:v}:{},...e.reviewBinding===void 0?{}:{reviewBinding:e.reviewBinding},...e.deadlineAt===void 0?{}:{deadlineAt:e.deadlineAt},...e.outcomeDelivery===void 0?{}:{outcomeDelivery:e.outcomeDelivery},launch:c});if(d?.(n.node_id),e.forkFrom!==void 0)try{nn(n.node_id,z??null)}catch(i){throw w(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}if($e(n.node_id,e.prompt),e.situationalContext!==void 0&&Fe(n.node_id,Oe(e.situationalContext)),o!==void 0)try{o(n.node_id)}catch(i){throw w(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}const T=e.prompt!=="",te=`${T&&e.wakeOrigin!==void 0?`${Se(e.wakeOrigin)}
1
+ var de=Object.defineProperty;var d=(e,o)=>de(e,"name",{value:o,configurable:!0});import{accessSync as se,constants as ce}from"node:fs";import{isAbsolute as le,resolve as fe,join as ue}from"node:path";import{appSpace as me}from"../layout.js";import{ApiError as q}from"../../api/errors.js";import{spawnNode as we,forkSourceNode as he,currentNodeContext as pe,rootOfSpine as ke,newNodeId as _e,preflightNodeId as ve}from"./nodes.js";import{resolveProfileOperand as ye}from"../profiles/manifest.js";import{selectProfileForCwd as ge,selectProfileForCwdReadOnly as be}from"../profiles/select.js";import{buildLaunchSpecAsync as Y,buildPiArgv as xe}from"./launch.js";import{createManagedWorktreeAsync as Ce,rollbackManagedWorktreeAsync as Ee}from"../worktree-mutation-async.js";import{usage as u,brokerLaunchFailed as I}from"../errors.js";import{writeGoal as $e}from"./kickoff.js";import{appendSituationalContext as Fe,formatSituationalProse as Oe}from"./situational-context.js";import{ensureRoadmap as Re}from"./roadmap.js";import{buildWakeBearings as Se}from"./bearings.js";import{encodeKickoffOrigin as Ie,KICKOFF_ORIGIN_ENV as Ne}from"./stamp/protocol.js";import{beginExecution as Pe,crtrHome as De,getNode as f,fullName as J,jobDir as Te,recordExecutionPid as Be,abortExecution as B,setFrozen as Le}from"../canvas/index.js";import{contextDir as L,nodeAgentDir as A}from"../canvas/node-agent-paths.js";import{copyTreeBeneath as Ae}from"../spaces/open-beneath.js";import{conversationIdFromPath as N,conversationStore as x}from"../conversation-store/index.js";import{appMemoryTooSmall as Me,boundFleet as je,brokerThresholdsForDaemon as We}from"./fleet.js";import{admitBrokerMemory as He}from"./memory-admission.js";import{emitEvent as Ke}from"../events/emit.js";import{openViewerWindow as ze,focusOf as Ge,windowOfPane as Ue}from"./placement.js";import{waitForBrokerViewSocket as Ve}from"./placement-tmux.js";import{transition as h}from"./lifecycle.js";import{beginBootFaultAttempt as Xe}from"../canvas/recovery.js";import{headlessBrokerHost as M}from"./host.js";import{ensureDaemon as qe}from"../../daemon/manage.js";import{readConfig as Ye}from"../config.js";import{modelRequestFromConfig as Je,unregisteredConcreteModel as Qe}from"../model-routes.js";import{openModelRegistry as Ze}from"./model-registry.js";import{MODEL_SPEC_NEXT as en}from"./model-selection.js";import{forkNodeLedger as nn}from"./ledger.js";import{appRungForGrant as on}from"../llm/app-rungs.js";import{APP_FAMILY as j}from"../model-routes.js";import{discoverLifecycleHookRegistry as rn}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as tn}from"../command-hooks/transport/exec-lifecycle.js";import{someAsync as an}from"../async-array.js";function p(e){return{detail:{schema:"crtr.node-outcome-detail/v1",message:e instanceof Error?e.message:String(e)}}}d(p,"launchFailureOutcome");async function dn(e,o,a){try{return await M.launch(e,o,a)}catch(r){try{await h(e,"crash",{reason:"launch_failed",outcome:p(r)})}catch{}const t=r.message;throw I(t.startsWith("[broker]")?t:`[broker] refusing to launch ${e}: ${t}`,"Inspect the cause above, fix the launch recipe or environment, then retry.")}}d(dn,"launchBrokerOrCrash");async function sn(e,o){try{await h(e,"crash",{reason:"launch_failed",outcome:p(o)})}catch{}try{M.teardown(e)}catch{}}d(sn,"crashAndTearDown");async function cn(e){const o=(await x().list()).map(({conversation_id:t,path:s})=>({id:t,path:s})),a=o.filter(t=>t.id===e),r=a.length>0?a:o.filter(t=>t.id.startsWith(e));if(r.length===0)throw u(`--fork-from '${e}': no pi session with that id found.`,{next:"Pass a live node id, a real session uuid/prefix, or an absolute .jsonl session path."});if(r.length>1)throw u(`--fork-from '${e}': ambiguous \u2014 ${r.length} sessions match that id prefix; pass the full id or the .jsonl path.`,{next:"Pass the full session uuid or an absolute .jsonl path to disambiguate."});return r[0].path}d(cn,"resolveSessionUuid");async function Q(e){const o=e.trim();if(o==="")throw u("--fork-from requires a node id, session file, or session uuid.",{next:"Pass a live node id, an absolute .jsonl session path, or a session uuid/prefix."});if(o.includes("/")||o.endsWith(".jsonl")){const r=N(le(o)?o:fe(process.cwd(),o));if(r===null)throw u(`--fork-from '${o}': invalid conversation path.`,{next:"Pass a conversation file path or id."});return(await x().header(r)).path}const a=await f(o);if(a!==null){const r=a.pi_session_file;if(r==null||r==="")throw u(`node ${o} has no pi session yet \u2014 it has not captured a session FILE to fork from (the broker forks a .jsonl path, not a bare id).`,{next:"Pick a node that has captured a session, or drop --fork-from."});const t=N(r);if(t===null)throw u(`node ${o} has no valid conversation id.`,{next:"Pick a node with a captured conversation."});return(await x().header(t)).path}return await cn(o)}d(Q,"resolveForkSource");async function ln(e,o,a,r={}){return e===null?null:e!==void 0&&e!==""?ye(e).profileId:o!==null?(await f(o))?.profile_id??null:r.readOnlySelection===!0?be(a):ge(a)}d(ln,"resolveProfileId");function Z(e){const o=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return Je(e.model,o,e.modelExact===!0)}d(Z,"requestFromLaunch");async function ee(e,o,a){const r=a??(e.modelIntent?`${e.modelIntent.family}/${e.modelIntent.strength}`:e.model),t=await on(o,r,e.modelExact===!0);if(t===null)return e;const{CRTR_MODEL_INTENT:s,...c}=e.env??{};return{...e,model:t.model,modelIntent:{family:j,strength:t.strength},modelExact:void 0,env:{...c,CRTR_MODEL_INTENT:`${j}/${t.strength}`}}}d(ee,"appPaidLaunch");async function ne(e,o,a){if(e===void 0||e.kind==="logical"&&e.family!==j)return;const r=Qe(e.kind==="logical"?{kind:"concrete",spec:e.spec}:e,a??await Ze(),o);if(r!==void 0)throw u(`model '${r.request.spec}' is not registered in this daemon.`,{received:r.request.spec,next:en})}d(ne,"assertLaunchModelRegistered");function fn(e,o,a){const r=e??o??null;if(!a&&r===null)throw new Error("spawnChild requires a calling node (CRTR_NODE_ID) or an explicit parent");return r}d(fn,"resolveSpawner");async function oe(e,o,a){try{qe()}catch{}const r=pe(),t=e.root===!0,s=fn(e.parent,r.nodeId??null,t),c=e.mode??"base",k=e.rootLifecycle??(t?"resident":"terminal"),re=t&&k==="resident",P=s===null?null:await f(s),ie=e.creator===void 0||e.creator===null?null:await f(e.creator);e.nodeId!==void 0&&await ve(e.nodeId);const _=e.forkFrom!==void 0?await Q(e.forkFrom):void 0,W=_===void 0?null:await he(_),D=await an([P,ie,W],async l=>l?.isolated===!0||l?.run_id!=null&&(await f(l.run_id))?.isolated===!0);if(D&&e.isolated===!1)throw new q(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});const $=D||e.isolated===!0;if($&&e.worktree===!0)throw new q(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const F=e.worktree===!0,v=$||F?e.nodeId??await _e():e.nodeId,O=$?e.run!==void 0&&t&&!D?e.cwd:ue(me(e.run?.grantee??P?.grantee??"app:terminal").nodes,v):e.cwd,C=await ln(e.profile,s,O),H=e.run?.grant_id??P?.grant_id??null,K=await ee((await Y(e.kind,c,{lifecycle:k,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:O,profileId:C})).launch,H,e.model);await ne(Z(K),{cwd:O,profileId:C});const z=W?.node_id??null;let y,R=O;try{F&&(y=await Ce(e.worktreeCwd??e.cwd,v,e.worktreeBase),R=y.path);const l=F?await ee((await Y(e.kind,c,{lifecycle:k,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:R,profileId:C})).launch,H,e.model):K;F&&await ne(Z(l),{cwd:R,profileId:C});const n=await we({kind:e.kind,mode:c,lifecycle:k,cwd:R,name:e.name??e.kind,description:e.description,parent:t?null:s,creator:e.creator,...e.actor===void 0?{}:{actor:e.actor},forkSourceNode:z,spawnedBy:t?s??void 0:void 0,profile_id:C,...e.scopes===void 0?{}:{scopes:e.scopes},isolated:$,...e.run===void 0?{}:{run:e.run},...e.withinCreate===void 0?{}:{withinCreate:e.withinCreate},forkFrom:e.forkFrom,forkSourceFile:_,modelOverride:e.model===void 0?void 0:l.model,...y!==void 0?{managedWorktree:y}:{},...v!==void 0?{nodeId:v}:{},...e.reviewBinding===void 0?{}:{reviewBinding:e.reviewBinding},...e.deadlineAt===void 0?{}:{deadlineAt:e.deadlineAt},...e.outcomeDelivery===void 0?{}:{outcomeDelivery:e.outcomeDelivery},launch:l});if(a?.(n.node_id),e.forkFrom!==void 0)try{await nn(n.node_id,z??null)}catch(i){throw await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}if(await $e(n.node_id,e.prompt),e.situationalContext!==void 0&&Fe(n.node_id,Oe(e.situationalContext)),o!==void 0)try{o(n.node_id)}catch(i){throw await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}const T=e.prompt!=="",te=`${T&&e.wakeOrigin!==void 0?`${Se(e.wakeOrigin)}
2
2
 
3
- `:""}${e.prompt}`;l==="orchestrator"&&Re(n.node_id,{goal:e.prompt.trim()}),await fn(n);let G;if(_!==void 0)try{const i=N(_);if(i===null)throw new Error(`invalid fork source ${_}`);const h=x().fork(i,n.node_id);G=x().header(h).path}catch(i){throw w(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}const y=xe(n,{prompt:te,resumeSessionPath:G});if(y.env={...y.env,CRTR_SUBTREE:ke(n.node_id)},T){const i=e.wakeOrigin!==void 0?{type:"runtime",kind:"wake",wake:e.wakeOrigin}:{type:"runtime",kind:"kickoff",...n.spawned_by!=null&&n.spawned_by!==""?{spawnedBy:n.spawned_by}:{}};y.env[Ne]=Ie(i)}const b=je(),U=b.reserveSlot(n.node_id),m=U?await He(n.node_id):null;if(m?.verdict==="too_small"){b.releaseReservation(n.node_id);const i=Me(m);throw w(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}if(!U||m?.verdict==="denied")return m?.verdict==="denied"&&b.releaseReservation(n.node_id),Le(n.node_id,new Date().toISOString()),Ke({level:"info",event:"broker.frozen",node_id:n.node_id,fields:m?.verdict==="denied"?{reason:"app_memory",free_bytes:m.free_bytes,needed_bytes:m.needed_bytes}:{reason:"broker_cap",live_count:b.size(),hard_cap:We().automaticReviveCap}}),{node:f(n.node_id),frozen:!0,window:null,session:null};const de=Xe(n.node_id),E=Pe(n.node_id,{daemonEpoch:b.epoch()});y.env={...y.env,CRTR_EXECUTION_ID:E};let S;try{S=await dn(n.node_id,y,{cwd:n.cwd,name:J(n),resuming:!1})}catch(i){throw B(E,{reason:"launch_failed"}),i}finally{b.releaseReservation(n.node_id)}if(S.pid===null){const i=new Error(`broker host returned no pid for ${n.node_id}`);throw B(E,{reason:"launch_failed"}),w(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),I(`failed to launch the broker engine for ${n.node_id} (${n.name}) \u2014 the node was not started.`,`Inspect canonical event diagnostics with \`crtr sys logs --node ${n.node_id}\`, then verify the pi engine can start in this environment.`)}if(Be(E,n.node_id,S.pid)==="shutdown")throw B(E,{reason:"superseded"}),M.teardown(n.node_id),I(`broker execution was superseded for ${n.node_id}`,"Retry spawning the node.");if(re&&e.readiness==="await"&&!await Ve(n.node_id,S.exited)){const i=de.explanation();throw an(n.node_id,new Error(i??`broker view socket never bound for ${n.node_id}`)),I(i!==null?`the root broker ${n.node_id} could not start \u2014 ${i}`:`the root broker ${n.node_id} never bound its view socket \u2014 it was not started.`,i!==null?"Resolve the cause named above, then retry.":`The broker engine exited before binding its view socket. Inspect canonical event diagnostics with \`crtr sys logs --node ${n.node_id}\`, then retry.`)}let V=null,X=null;if(!t&&s!==null&&Ye("user").auto_open_child_viewers)try{const i=Ge(s);if(i!==null&&i.pane!==null&&i.pane!==""){const h=ze(n.node_id,i.session??"",{name:J(n),cwd:e.cwd,besidePane:i.pane,waitForBroker:!0,initialWhip:T});h!==null&&h.pane!==null&&h.pane!==""&&(X=h.session,V=Ue(h.pane))}}catch{}return{node:f(n.node_id),frozen:!1,window:V,session:X}}catch(c){throw g!==void 0&&v!==void 0&&f(v)===null&&await Ee(g),c}}a(oe,"spawnChildPrepared");async function Zn(e){return oe(e)}a(Zn,"spawnChild");async function fn(e){const o=rn(e.cwd,e.profile_id).plans.get("node:start")??[];await tn(o,{node:{id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,cwd:e.cwd,nodeDir:A(e.node_id),contextDir:L(e.node_id),jobDir:Te(e.node_id)},runtime:{isBirth:!0,canvasHome:De(),profile:e.profile_id??null}})}a(fn,"invokeBirthLifecycleHooks");const un=new Set(["initial-prompt.md","yield-message.md","result.json","jobs"]);async function eo(e,o,d){const r=f(e);if(r===null)throw u(`unknown node: ${e}`,{received:e,next:"List nodes and pass the id of a node with a captured pi session."});const t=Q(e),s=L(e);try{x().header(N(t)),se(s,le.R_OK)}catch(l){throw new Error(`cannot fork ${e}: its conversation or context is unreadable \u2014 ${l.message}`)}return oe({kind:r.kind,mode:"base",cwd:r.cwd,prompt:"",root:!0,readiness:"await",forkFrom:e,...d===void 0?{}:{actor:d},profile:r.profile_id,model:r.model_override??void 0,...o===void 0?{}:{scopes:o}},l=>{const k=L(l);Ae(A(e),s,A(l),k,un)})}a(eo,"forkNode");export{ee as appPaidLaunch,ne as assertLaunchModelRegistered,eo as forkNode,fn as invokeBirthLifecycleHooks,Q as resolveForkSource,ln as resolveProfileId,cn as resolveSpawner,Zn as spawnChild,oe as spawnChildPrepared};
3
+ `:""}${e.prompt}`;c==="orchestrator"&&await Re(n.node_id,{goal:e.prompt.trim()}),await un(n);let G;if(_!==void 0)try{const i=N(_);if(i===null)throw new Error(`invalid fork source ${_}`);const w=await x().fork(i,n.node_id);G=(await x().header(w)).path}catch(i){throw await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}const g=xe(n,{prompt:te,resumeSessionPath:G});if(g.env={...g.env,CRTR_SUBTREE:await ke(n.node_id)},T){const i=e.wakeOrigin!==void 0?{type:"runtime",kind:"wake",wake:e.wakeOrigin}:{type:"runtime",kind:"kickoff",...n.spawned_by!=null&&n.spawned_by!==""?{spawnedBy:n.spawned_by}:{}};g.env[Ne]=Ie(i)}const b=je(),U=b.reserveSlot(n.node_id),m=U?await He(n.node_id):null;if(m?.verdict==="too_small"){b.releaseReservation(n.node_id);const i=Me(m);throw await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),i}if(!U||m?.verdict==="denied")return m?.verdict==="denied"&&b.releaseReservation(n.node_id),await Le(n.node_id,new Date().toISOString()),Ke({level:"info",event:"broker.frozen",node_id:n.node_id,fields:m?.verdict==="denied"?{reason:"app_memory",free_bytes:m.free_bytes,needed_bytes:m.needed_bytes}:{reason:"broker_cap",live_count:b.size(),hard_cap:We().automaticReviveCap}}),{node:await f(n.node_id),frozen:!0,window:null,session:null};const ae=await Xe(n.node_id),E=await Pe(n.node_id,{daemonEpoch:b.epoch()});g.env={...g.env,CRTR_EXECUTION_ID:E};let S;try{S=await dn(n.node_id,g,{cwd:n.cwd,name:J(n),resuming:!1})}catch(i){throw await B(E,{reason:"launch_failed"}),i}finally{b.releaseReservation(n.node_id)}if(S.pid===null){const i=new Error(`broker host returned no pid for ${n.node_id}`);throw await B(E,{reason:"launch_failed"}),await h(n.node_id,"crash",{reason:"launch_failed",outcome:p(i)}),I(`failed to launch the broker engine for ${n.node_id} (${n.name}) \u2014 the node was not started.`,`Inspect canonical event diagnostics with \`crtr sys logs --node ${n.node_id}\`, then verify the pi engine can start in this environment.`)}if(await Be(E,n.node_id,S.pid)==="shutdown")throw await B(E,{reason:"superseded"}),M.teardown(n.node_id),I(`broker execution was superseded for ${n.node_id}`,"Retry spawning the node.");if(re&&e.readiness==="await"&&!await Ve(n.node_id,S.exited)){const i=await ae.explanation();throw await sn(n.node_id,new Error(i??`broker view socket never bound for ${n.node_id}`)),I(i!==null?`the root broker ${n.node_id} could not start \u2014 ${i}`:`the root broker ${n.node_id} never bound its view socket \u2014 it was not started.`,i!==null?"Resolve the cause named above, then retry.":`The broker engine exited before binding its view socket. Inspect canonical event diagnostics with \`crtr sys logs --node ${n.node_id}\`, then retry.`)}let V=null,X=null;if(!t&&s!==null&&Ye("user").auto_open_child_viewers)try{const i=await Ge(s);if(i!==null&&i.pane!==null&&i.pane!==""){const w=await ze(n.node_id,i.session??"",{name:J(n),cwd:e.cwd,besidePane:i.pane,waitForBroker:!0,initialWhip:T});w!==null&&w.pane!==null&&w.pane!==""&&(X=w.session,V=Ue(w.pane))}}catch{}return{node:await f(n.node_id),frozen:!1,window:V,session:X}}catch(l){throw y!==void 0&&v!==void 0&&await f(v)===null&&await Ee(y),l}}d(oe,"spawnChildPrepared");async function no(e){return oe(e)}d(no,"spawnChild");async function un(e){const o=rn(e.cwd,e.profile_id).plans.get("node:start")??[];await tn(o,{node:{id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,cwd:e.cwd,nodeDir:await A(e.node_id),contextDir:await L(e.node_id),jobDir:Te(e.node_id)},runtime:{isBirth:!0,canvasHome:De(),profile:e.profile_id??null}})}d(un,"invokeBirthLifecycleHooks");const mn=new Set(["initial-prompt.md","yield-message.md","result.json","jobs"]);async function oo(e,o,a){const r=await f(e);if(r===null)throw u(`unknown node: ${e}`,{received:e,next:"List nodes and pass the id of a node with a captured pi session."});const t=await Q(e),s=await L(e);try{await x().header(N(t)),se(s,ce.R_OK)}catch(c){throw new Error(`cannot fork ${e}: its conversation or context is unreadable \u2014 ${c.message}`)}return oe({kind:r.kind,mode:"base",cwd:r.cwd,prompt:"",root:!0,readiness:"await",forkFrom:e,...a===void 0?{}:{actor:a},profile:r.profile_id,model:r.model_override??void 0,...o===void 0?{}:{scopes:o}},async c=>{const k=await L(c);Ae(await A(e),s,await A(c),k,mn)})}d(oo,"forkNode");export{ee as appPaidLaunch,ne as assertLaunchModelRegistered,oo as forkNode,un as invokeBirthLifecycleHooks,Q as resolveForkSource,ln as resolveProfileId,fn as resolveSpawner,no as spawnChild,oe as spawnChildPrepared};
@@ -11,7 +11,7 @@ export declare function isAppRunRoot(node: Pick<NodeMeta, 'node_id' | 'parent' |
11
11
  /** Whether a live app run root that stops now would be reprompted with its
12
12
  * armed schema: the run is still `running`, not `idle`, between its turn's end
13
13
  * and the reprompt's turn (D2-RES-10). Reads only; counts nothing. */
14
- export declare function runSchemaRepromptPending(node: NodeMeta): boolean;
14
+ export declare function runSchemaRepromptPending(node: NodeMeta): Promise<boolean>;
15
15
  export { STALL_REPROMPT } from '../../shared/generated-context.js';
16
16
  export interface StopSignals {
17
17
  /** Did the node call `push --final` (finish) this turn? */
@@ -28,4 +28,4 @@ export type StopAction = {
28
28
  /** Decide what to do when a node stops. crtrd supplies every current-canvas
29
29
  * fact; the broker contributes only whether its Pi-owned background job registry
30
30
  * is still running work. */
31
- export declare function evaluateStop(nodeId: string, signals: StopSignals, backgroundJobsRunning?: boolean): StopAction;
31
+ export declare function evaluateStop(nodeId: string, signals: StopSignals, backgroundJobsRunning?: boolean): Promise<StopAction>;
@@ -1,8 +1,8 @@
1
- var _=Object.defineProperty;var r=(t,e)=>_(t,"name",{value:e,configurable:!0});import{hasActiveLiveSubscription as S,hasPendingCronWake as v,getNode as c}from"../canvas/index.js";import{hasLiveControllerWait as w,hasLiveObjectWait as O}from"../canvas/waits.js";import{contextDir as m}from"../canvas/node-agent-paths.js";import{activeBackgroundBashJobs as f}from"../bash-jobs.js";import{hasOpenReplyBearingRequestByRequester as L}from"../human/requests.js";import{formatCard as o,formatStructuredOutputReprompt as b,STALL_REPROMPT as A}from"../../shared/generated-context.js";import{readOutputRequest as d,readSchemaReprompts as N,writeSchemaReprompts as q}from"./structured-output.js";import{openDb as x}from"../canvas/db.js";import{prepared as y}from"../sqlite-statements.js";const h=3;function g(t){return t.parent==null&&t.run_id===t.node_id&&t.metadata_json!=null}r(g,"isAppRunRoot");function R(t){const e=N(t);return e.count===0?e:y(x(),`SELECT 1 FROM deliveries d JOIN messages m ON m.message_id = d.message_id
2
- WHERE d.destination_id = ? AND d.wake = 1 AND m.kind IN ('message', 'completed') AND d.created_at > ? LIMIT 1`).get(t,e.at)!==void 0?{count:0,at:e.at}:e}r(R,"effectiveSchemaReprompts");function E(t){const{count:e}=R(t);return e>=h?!1:(q(t,{count:e+1,at:Date.now()}),!0)}r(E,"takeRunSchemaReprompt");function U(t){return t.pi_pid!=null&&g(t)&&d(t.node_id).state==="valid"&&R(t.node_id).count<h&&u(t.node_id,f(m(t.node_id)).length>0)===null}r(U,"runSchemaRepromptPending");import{STALL_REPROMPT as z}from"../../shared/generated-context.js";function P(t,e){return o("stop-guard",{},b(JSON.stringify(e,null,2),t))}r(P,"formatValidStructuredOutputReprompt");function T(t){return o("stop-guard",{},`Structured-output request file is invalid and cannot be used: ${t}
1
+ var g=Object.defineProperty;var a=(t,e)=>g(t,"name",{value:e,configurable:!0});import{hasActiveLiveSubscription as _,hasPendingCronWake as v,getNode as p}from"../canvas/index.js";import{hasLiveControllerWait as S,hasLiveObjectWait as y}from"../canvas/waits.js";import{contextDir as m}from"../canvas/node-agent-paths.js";import{activeBackgroundBashJobs as f}from"../bash-jobs.js";import{hasOpenReplyBearingRequestByRequester as O}from"../human/requests.js";import{formatCard as o,formatStructuredOutputReprompt as L,STALL_REPROMPT as A}from"../../shared/generated-context.js";import{readOutputRequest as d,readSchemaReprompts as N,writeSchemaReprompts as q}from"./structured-output.js";import{openDb as x}from"../canvas/db.js";const h=3;function w(t){return t.parent==null&&t.run_id===t.node_id&&t.metadata_json!=null}a(w,"isAppRunRoot");async function R(t){const e=N(t);return e.count===0?e:await(await x()).prepare(`SELECT 1 FROM deliveries d JOIN messages m ON m.message_id = d.message_id
2
+ WHERE d.destination_id = ? AND d.wake = 1 AND m.kind IN ('message', 'completed') AND d.created_at > ? LIMIT 1`).get(t,e.at)!==void 0?{count:0,at:e.at}:e}a(R,"effectiveSchemaReprompts");async function E(t){const{count:e}=await R(t);return e>=h?!1:(q(t,{count:e+1,at:Date.now()}),!0)}a(E,"takeRunSchemaReprompt");async function H(t){return t.pi_pid!=null&&w(t)&&d(t.node_id).state==="valid"&&(await R(t.node_id)).count<h&&await s(t.node_id,f(await m(t.node_id)).length>0)===null}a(H,"runSchemaRepromptPending");import{STALL_REPROMPT as Y}from"../../shared/generated-context.js";function P(t,e){return o("stop-guard",{},L(JSON.stringify(e,null,2),t))}a(P,"formatValidStructuredOutputReprompt");function T(t){return o("stop-guard",{},`Structured-output request file is invalid and cannot be used: ${t}
3
3
 
4
4
  You have two options:
5
5
  1. Remove the invalid file (the output-schema.json in your node directory has been corrupted)
6
6
  2. Fix the corruption if you know the original request schema
7
7
 
8
- After resolving the file, call the \`submit_result\` tool again (with \`decline\` when the schema cannot be honestly satisfied). If this is unexpected, escalate to the user using \`crtr human send\`.`)}r(T,"formatInvalidStructuredOutputReprompt");function u(t,e){return v(t)?"scheduled":S(t)||w(t)||O(t)||L(t)||e?"awaiting":null}r(u,"wakeCapableWait");function V(t,e,i=f(m(t)).length>0){if(e.pushedFinal)return{action:"allow",reason:"finished"};const a=d(t);if(a.state==="valid"){const l=u(t,i);if(l!==null)return{action:"allow",reason:l};const p=c(t);return p!==null&&g(p)&&!E(t)?{action:"allow",reason:"dormant"}:{action:"reprompt",reason:"stalled",message:P(a.request.request_id,a.request.schema)}}if(a.state==="invalid")return{action:"reprompt",reason:"stalled",message:T(a.error)};const n=c(t);if(n!==null&&(n.final_report!=null||n.status==="done"||n.status==="dead"||n.status==="canceled"))return{action:"allow",reason:"finished"};if(n!==null&&n.lifecycle==="resident")return{action:"allow",reason:"dormant"};const s=u(t,i);return s!==null?{action:"allow",reason:s}:{action:"reprompt",reason:"stalled",message:o("stop-guard",{},A)}}r(V,"evaluateStop");export{h as RUN_SCHEMA_REPROMPT_LIMIT,z as STALL_REPROMPT,V as evaluateStop,g as isAppRunRoot,U as runSchemaRepromptPending};
8
+ After resolving the file, call the \`submit_result\` tool again (with \`decline\` when the schema cannot be honestly satisfied). If this is unexpected, escalate to the user using \`crtr human send\`.`)}a(T,"formatInvalidStructuredOutputReprompt");async function s(t,e){return await v(t)?"scheduled":await _(t)||await S(t)||await y(t)||await O(t)||e?"awaiting":null}a(s,"wakeCapableWait");async function J(t,e,i){if(i??=f(await m(t)).length>0,e.pushedFinal)return{action:"allow",reason:"finished"};const n=d(t);if(n.state==="valid"){const l=await s(t,i);if(l!==null)return{action:"allow",reason:l};const c=await p(t);return c!==null&&w(c)&&!await E(t)?{action:"allow",reason:"dormant"}:{action:"reprompt",reason:"stalled",message:P(n.request.request_id,n.request.schema)}}if(n.state==="invalid")return{action:"reprompt",reason:"stalled",message:T(n.error)};const r=await p(t);if(r!==null&&(r.final_report!=null||r.status==="done"||r.status==="dead"||r.status==="canceled"))return{action:"allow",reason:"finished"};if(r!==null&&r.lifecycle==="resident")return{action:"allow",reason:"dormant"};const u=await s(t,i);return u!==null?{action:"allow",reason:u}:{action:"reprompt",reason:"stalled",message:o("stop-guard",{},A)}}a(J,"evaluateStop");export{h as RUN_SCHEMA_REPROMPT_LIMIT,Y as STALL_REPROMPT,J as evaluateStop,w as isAppRunRoot,H as runSchemaRepromptPending};
@@ -52,7 +52,7 @@ export declare function resumeWarmClaim(request: WarmRequest, nodeId: string, be
52
52
  * alone (`unregisterWarmSpare` returns false) and never torn down under its
53
53
  * new owner. Only after winning the marker is the broker killed and the row +
54
54
  * dir deleted. Never throws: a failed reap is retried on the next sweep. */
55
- export declare function reapStaleSpares(): string[];
55
+ export declare function reapStaleSpares(): Promise<string[]>;
56
56
  /** Bring the pool for `request` back to depth 1, in the background. Never
57
57
  * throws and never blocks a caller: a failed mint just means the next create
58
58
  * for this key is cold again. */
@@ -62,4 +62,4 @@ export declare function refillWarmPool(request: WarmRequest): void;
62
62
  * recipe: it supplies the cwd, and everything else a claim reshapes live.
63
63
  * Fire-and-forget — returns as soon as the mints are scheduled, never blocking
64
64
  * the daemon's work lane. */
65
- export declare function prewarmRecentRecipes(): void;
65
+ export declare function prewarmRecentRecipes(): Promise<void>;
@@ -1 +1 @@
1
- var S=Object.defineProperty;var a=(e,r)=>S(e,"name",{value:r,configurable:!0});import{createHash as _}from"node:crypto";import{claimWarmSpare as x,deleteNode as N,getNode as u,listNodes as $,listWarmSpares as C,registerWarmSpare as R,unregisterWarmSpare as W,updateNode as b,warmSpareCount as w}from"../canvas/index.js";import{recordedPidLiveness as P}from"../canvas/pid.js";import{nowIso as h}from"../fs-utils.js";import{admitNodeCreate as L}from"../command-hooks/lifecycle-create.js";import{spawnChildPrepared as M}from"./spawn.js";import{buildLaunchSpecAsync as A}from"./launch.js";import{setModelLive as E}from"./model-swap.js";import{setSituationalContextLive as O}from"./situational-live.js";import{deliverBearingsLive as I}from"./deliver-live.js";import{closeNode as y}from"./close.js";function g(){return process.env.CRTR_WARM_POOL!=="0"}a(g,"warmPoolEnabled");function T(e,r,o){const t=Object.entries(o.env??{}).sort(([s],[i])=>s<i?-1:s>i?1:0),n=JSON.stringify([e,r,o.tools??[],o.extensions??[],o.systemPrompt??null,t]);return _("sha256").update(n).digest("hex").slice(0,32)}a(T,"warmRecipeKey");async function d(e){const{launch:r}=await A(e.kind,e.mode,{lifecycle:"resident",hasManager:!1,...e.model!==null?{model:e.model}:{},cwd:e.cwd,profileId:e.profileId});return{key:T(e.cwd,e.profileId,r),launch:r,request:e}}a(d,"resolveRecipe");async function Z(e,r={},o){const t=await d(e);if(w(t.key)===0)return null;const n=h(),s=await L({kind:e.kind,mode:e.mode,cwd:e.cwd,profile:e.profileId,root:!0,parentId:null,requestingNodeId:e.creator,lifecycle:"resident",replaces:null},e.creator===null?"app:terminal":(()=>{const l=u(e.creator);if(!l?.grantee)throw new Error("warm node creator has no app");return l.grantee})());let i;try{i=x(t.key,n,r)}finally{s()}return i===null?null:v(i,t,n,o)}a(Z,"claimWarmNode");async function q(e,r,o){return v(r,await d(e),h(),o)}a(q,"resumeWarmClaim");async function v(e,r,o,t){const{request:n}=r,i=u(e)?.launch?.model;b(e,{created:o,kind:n.kind,mode:n.mode,name:n.name??n.kind,creator:n.creator,launch:r.launch,persona_ack:{kind:n.kind,mode:n.mode,lifecycle:"resident"},...n.model!==null?{model_override:n.model}:{}});try{t?.(e)}catch(c){return m(e,"birth preparation",c)}try{await I(e)}catch(c){return m(e,"bearings delivery",c)}const l=r.launch.model;if(l!==void 0&&l!==i)try{await E(e,l,r.launch.modelIntent)}catch(c){return m(e,"model swap",c)}if(n.situationalContext!==null)try{await O(e,n.situationalContext)}catch(c){return m(e,"situational-context delivery",c)}return e}a(v,"completeWarmClaim");function m(e,r,o){console.error(`[warm-pool] ${r} failed on claim; closing the spare: ${o.message}`);try{y(e)}catch{}return null}a(m,"abandonSpare");const D=3600*1e3;function ee(){const e=[];let r;try{r=C()}catch(t){return console.error(`[warm-pool] spare scan failed: ${t.message}`),e}const o=Date.now()-D;for(const t of r){if(f.has(t.node_id))continue;const n=Date.parse(t.created),s=Number.isNaN(n)||n<o,i=P(t.pi_pid,t.pi_pid_identity),l=(t.status==="active"||t.status==="idle")&&i==="alive";if(!(l&&!s)&&!(i==="indeterminate"&&!s))try{if(!W(t.node_id))continue;if(l)try{y(t.node_id)}catch{}N(t.node_id),e.push(t.node_id)}catch(c){console.error(`[warm-pool] reap failed for ${t.node_id}: ${c.message}`)}}return e}a(ee,"reapStaleSpares");const p=new Set,f=new Set;function re(e){if(g())try{d({...e,model:null,situationalContext:null}).then(k).catch(r=>console.error(`[warm-pool] recipe resolution failed: ${r.message}`))}catch(r){console.error(`[warm-pool] recipe resolution failed: ${r.message}`)}}a(re,"refillWarmPool");function k(e){const{key:r,request:o}=e;p.has(r)||w(r)>0||(p.add(r),(async()=>{let t=null;try{await M({kind:o.kind,mode:o.mode,cwd:o.cwd,prompt:"",root:!0,readiness:"await",profile:o.profileId},n=>{t=n,f.add(n),R(n,r)})}catch(n){console.error(`[warm-pool] mint failed for ${o.kind}: ${n.message}`)}finally{t!==null&&f.delete(t),p.delete(r)}})())}a(k,"mint");const j=2;function oe(){if(!g())return;let e;try{const r=new Set;e=[];for(const o of $({status:["active","idle"]}).reverse()){if(o.parent!==null||o.kind==="human")continue;const t=o.profile_id??null;if(!r.has(t??"")&&(r.add(t??""),e.push({cwd:o.cwd,profileId:t}),e.length>=j))break}}catch(r){console.error(`[warm-pool] prewarm scan failed: ${r.message}`);return}for(const r of e)try{d({kind:"general",mode:"base",cwd:r.cwd,profileId:r.profileId,model:null,situationalContext:null,name:null,creator:null}).then(k).catch(o=>console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${o.message}`))}catch(o){console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${o.message}`)}}a(oe,"prewarmRecentRecipes");export{Z as claimWarmNode,oe as prewarmRecentRecipes,ee as reapStaleSpares,re as refillWarmPool,q as resumeWarmClaim,g as warmPoolEnabled};
1
+ var S=Object.defineProperty;var n=(e,r)=>S(e,"name",{value:r,configurable:!0});import{createHash as _}from"node:crypto";import{claimWarmSpare as x,deleteNode as N,getNode as u,listNodes as $,listWarmSpares as C,registerWarmSpare as R,unregisterWarmSpare as W,updateNode as b,warmSpareCount as w}from"../canvas/index.js";import{recordedPidLiveness as P}from"../canvas/pid.js";import{nowIso as y}from"../fs-utils.js";import{admitNodeCreate as L}from"../command-hooks/lifecycle-create.js";import{spawnChildPrepared as M}from"./spawn.js";import{buildLaunchSpecAsync as A}from"./launch.js";import{setModelLive as E}from"./model-swap.js";import{setSituationalContextLive as O}from"./situational-live.js";import{deliverBearingsLive as I}from"./deliver-live.js";import{closeNode as h}from"./close.js";function g(){return process.env.CRTR_WARM_POOL!=="0"}n(g,"warmPoolEnabled");function T(e,r,t){const a=Object.entries(t.env??{}).sort(([s],[i])=>s<i?-1:s>i?1:0),o=JSON.stringify([e,r,t.tools??[],t.extensions??[],t.systemPrompt??null,a]);return _("sha256").update(o).digest("hex").slice(0,32)}n(T,"warmRecipeKey");async function d(e){const{launch:r}=await A(e.kind,e.mode,{lifecycle:"resident",hasManager:!1,...e.model!==null?{model:e.model}:{},cwd:e.cwd,profileId:e.profileId});return{key:T(e.cwd,e.profileId,r),launch:r,request:e}}n(d,"resolveRecipe");async function Z(e,r={},t){const a=await d(e);if(await w(a.key)===0)return null;const o=y(),s=await L({kind:e.kind,mode:e.mode,cwd:e.cwd,profile:e.profileId,root:!0,parentId:null,requestingNodeId:e.creator,lifecycle:"resident",replaces:null},e.creator===null?"app:terminal":await(async()=>{const l=await u(e.creator);if(!l?.grantee)throw new Error("warm node creator has no app");return l.grantee})());let i;try{i=await x(a.key,o,r)}finally{s()}return i===null?null:v(i,a,o,t)}n(Z,"claimWarmNode");async function q(e,r,t){return v(r,await d(e),y(),t)}n(q,"resumeWarmClaim");async function v(e,r,t,a){const{request:o}=r,i=(await u(e))?.launch?.model;await b(e,{created:t,kind:o.kind,mode:o.mode,name:o.name??o.kind,creator:o.creator,launch:r.launch,persona_ack:{kind:o.kind,mode:o.mode,lifecycle:"resident"},...o.model!==null?{model_override:o.model}:{}});try{a?.(e)}catch(c){return await m(e,"birth preparation",c)}try{await I(e)}catch(c){return await m(e,"bearings delivery",c)}const l=r.launch.model;if(l!==void 0&&l!==i)try{await E(e,l,r.launch.modelIntent)}catch(c){return await m(e,"model swap",c)}if(o.situationalContext!==null)try{await O(e,o.situationalContext)}catch(c){return await m(e,"situational-context delivery",c)}return e}n(v,"completeWarmClaim");async function m(e,r,t){console.error(`[warm-pool] ${r} failed on claim; closing the spare: ${t.message}`);try{await h(e)}catch{}return null}n(m,"abandonSpare");const D=3600*1e3;async function ee(){const e=[];let r;try{r=await C()}catch(a){return console.error(`[warm-pool] spare scan failed: ${a.message}`),e}const t=Date.now()-D;for(const a of r){if(f.has(a.node_id))continue;const o=Date.parse(a.created),s=Number.isNaN(o)||o<t,i=P(a.pi_pid,a.pi_pid_identity),l=(a.status==="active"||a.status==="idle")&&i==="alive";if(!(l&&!s)&&!(i==="indeterminate"&&!s))try{if(!await W(a.node_id))continue;if(l)try{await h(a.node_id)}catch{}await N(a.node_id),e.push(a.node_id)}catch(c){console.error(`[warm-pool] reap failed for ${a.node_id}: ${c.message}`)}}return e}n(ee,"reapStaleSpares");const p=new Set,f=new Set;function re(e){if(g())try{d({...e,model:null,situationalContext:null}).then(k).catch(r=>console.error(`[warm-pool] recipe resolution failed: ${r.message}`))}catch(r){console.error(`[warm-pool] recipe resolution failed: ${r.message}`)}}n(re,"refillWarmPool");async function k(e){const{key:r,request:t}=e;p.has(r)||await w(r)>0||(p.add(r),(async()=>{let a=null;try{await M({kind:t.kind,mode:t.mode,cwd:t.cwd,prompt:"",root:!0,readiness:"await",profile:t.profileId},async o=>{a=o,f.add(o),await R(o,r)})}catch(o){console.error(`[warm-pool] mint failed for ${t.kind}: ${o.message}`)}finally{a!==null&&f.delete(a),p.delete(r)}})())}n(k,"mint");const j=2;async function te(){if(!g())return;let e;try{const r=new Set;e=[];for(const t of(await $({status:["active","idle"]})).reverse()){if(t.parent!==null||t.kind==="human")continue;const a=t.profile_id??null;if(!r.has(a??"")&&(r.add(a??""),e.push({cwd:t.cwd,profileId:a}),e.length>=j))break}}catch(r){console.error(`[warm-pool] prewarm scan failed: ${r.message}`);return}for(const r of e)try{d({kind:"general",mode:"base",cwd:r.cwd,profileId:r.profileId,model:null,situationalContext:null,name:null,creator:null}).then(k).catch(t=>console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${t.message}`))}catch(t){console.error(`[warm-pool] prewarm failed for ${r.cwd}: ${t.message}`)}}n(te,"prewarmRecentRecipes");export{Z as claimWarmNode,te as prewarmRecentRecipes,ee as reapStaleSpares,re as refillWarmPool,q as resumeWarmClaim,g as warmPoolEnabled};
@@ -37,5 +37,5 @@ export declare function mountAllowed(mount: LaunchSpec['mounts'][number], allowe
37
37
  /** Whether a spec compiled earlier is still within the node's current
38
38
  * permissions. A launch whose grant generation moved while the launcher was
39
39
  * starting it checks this before registering the sandbox (runtime spec §15). */
40
- export declare function launchStillGranted(node: Pick<LaunchNode, 'app' | 'sub' | 'grantId' | 'scopes'>, spec: Pick<LaunchSpec, 'mounts'>): boolean;
41
- export declare function compileLaunch(node: LaunchNode): LaunchSpec;
40
+ export declare function launchStillGranted(node: Pick<LaunchNode, 'app' | 'sub' | 'grantId' | 'scopes'>, spec: Pick<LaunchSpec, 'mounts'>): Promise<boolean>;
41
+ export declare function compileLaunch(node: LaunchNode): Promise<LaunchSpec>;
@@ -1 +1 @@
1
- var W=Object.defineProperty;var l=(t,o)=>W(t,"name",{value:o,configurable:!0});import{lstatSync as y}from"node:fs";import{join as c,relative as f,sep as a}from"node:path";import{appSpace as m,appsRoot as S,runtimeRoot as h,socketDir as w,userFilesRoot as R}from"../layout.js";import{nodeAgentDir as I,nodeRunDir as k}from"../canvas/paths.js";import{uidForApp as A}from"./users.js";import{permissionsForRun as E}from"./permissions.js";function x(t){const o=[];for(const e of t.otherFiles){const s=e.holder==="user"?R():m(e.holder).files;o.push({source:e.path==="."?s:c(s,e.path),writable:e.writable})}for(const e of t.otherNodes)o.push({source:m(e).nodes,writable:!1});return o}l(x,"grantedMounts");function d(t,o){const e=f(t,o);return e===""||e!==".."&&!e.startsWith(`..${a}`)&&!e.startsWith(a)}l(d,"beneath");function M(t,o){return d(R(),o)||d(S(),o)&&!d(m(t).root,o)}l(M,"isGrantedSource");function j(t,o){return o.some(e=>d(e.source,t.source)&&(e.writable||!t.writable))}l(j,"mountAllowed");function z(t,o){try{const e=x(E(t.app,t.sub,t.grantId,t.scopes));return o.mounts.every(s=>!M(t.app,s.source)||j(s,e))}catch{return!1}}l(z,"launchStillGranted");function B(t){const o=m(t.app),e=E(t.app,t.sub,t.grantId,t.scopes);if(t.isolated&&t.withoutNode&&t.folder===void 0)throw new Error("isolated launch requires a node");const s=t.folder??(t.isolated?I(t.nodeId,t.app):void 0);if(s&&t.cwd!==void 0&&!d(s,t.cwd))throw new Error("isolated cwd must be inside the node folder");const p=new Map,i=l((r,n,u=!1,F=!1)=>{if(u)try{y(r)}catch(b){if(b.code!=="ENOENT")throw b;F&&t.auditMissing(r);return}p.set(r,n||(p.get(r)??!1))},"add");for(const r of["/usr","/bin","/lib","/lib64","/opt/crouter","/etc/passwd","/etc/group","/etc/resolv.conf","/etc/hosts","/etc/ssl","/etc/ca-certificates"])i(r,!1,!0);t.withoutNode||i(I(t.nodeId,t.app),!0),t.folder!==void 0&&i(t.folder,!0),t.cron?.anchorDir!==void 0&&i(t.cron.anchorDir,!0),t.isolated||i(o.home,!0),t.isolated||i(o.files,!0),i(o.cache,!0,!0),(!t.withoutNode||t.cron!==void 0)&&i(k(t.nodeId),!0),t.cron===void 0&&(i(c(w(),"api.sock"),!0),i(c(w(),"store.sock"),!0));for(const r of x(e))i(r.source,r.writable,!0,!0);if(t.pluginRoot!==void 0){const r=l(u=>t.pluginRoot===u||f(u,t.pluginRoot)!==".."&&!f(u,t.pluginRoot).startsWith(`..${a}`),"within"),n=c(h(),"plugins");if([...p].some(([u])=>r(u))){if(p.get(t.pluginRoot)===!0)throw new Error("hook root cannot also be writable");i(t.pluginRoot,!1)}else if(r(n)&&t.pluginRoot!==n)i(t.pluginRoot,!1);else if(r("/opt/crouter"))i(t.pluginRoot,!1);else throw new Error("hook root is not readable with this app\u2019s mounts")}const D=t.cwd??s??o.files,g=[...p].sort(([r],[n])=>r.split(a).length-n.split(a).length||r.localeCompare(n)),N=c(h(),"nodes",t.nodeId,"job","broker.log"),v=process.platform!=="linux"?[k(t.nodeId),c(w(),"api.sock"),c(w(),"store.sock")]:[];if(g.some(([r])=>r!==t.pluginRoot&&!v.includes(r)&&(r===h()||!f(h(),r).startsWith("..")&&!f(h(),r).startsWith(a))))throw new Error("runtime records cannot be mounted");return{nodeId:t.nodeId,uid:A(t.app),mounts:g.map(([r,n])=>({source:r,writable:n})),cwd:D,env:t.env,command:t.command,log:N,...t.isolated?{network:"none"}:{}}}l(B,"compileLaunch");export{B as compileLaunch,x as grantedMounts,M as isGrantedSource,z as launchStillGranted,j as mountAllowed};
1
+ var F=Object.defineProperty;var a=(t,o)=>F(t,"name",{value:o,configurable:!0});import{lstatSync as W}from"node:fs";import{join as u,relative as f,sep as c}from"node:path";import{appSpace as d,appsRoot as S,runtimeRoot as h,socketDir as m,userFilesRoot as R}from"../layout.js";import{nodeAgentDir as I,nodeRunDir as k}from"../canvas/paths.js";import{uidForApp as A}from"./users.js";import{permissionsForRun as E}from"./permissions.js";function x(t){const o=[];for(const e of t.otherFiles){const s=e.holder==="user"?R():d(e.holder).files;o.push({source:e.path==="."?s:u(s,e.path),writable:e.writable})}for(const e of t.otherNodes)o.push({source:d(e).nodes,writable:!1});return o}a(x,"grantedMounts");function w(t,o){const e=f(t,o);return e===""||e!==".."&&!e.startsWith(`..${c}`)&&!e.startsWith(c)}a(w,"beneath");function M(t,o){return w(R(),o)||w(S(),o)&&!w(d(t).root,o)}a(M,"isGrantedSource");function j(t,o){return o.some(e=>w(e.source,t.source)&&(e.writable||!t.writable))}a(j,"mountAllowed");async function z(t,o){try{const e=x(await E(t.app,t.sub,t.grantId,t.scopes));return o.mounts.every(s=>!M(t.app,s.source)||j(s,e))}catch{return!1}}a(z,"launchStillGranted");async function B(t){const o=d(t.app),e=await E(t.app,t.sub,t.grantId,t.scopes);if(t.isolated&&t.withoutNode&&t.folder===void 0)throw new Error("isolated launch requires a node");const s=t.folder??(t.isolated?I(t.nodeId,t.app):void 0);if(s&&t.cwd!==void 0&&!w(s,t.cwd))throw new Error("isolated cwd must be inside the node folder");const p=new Map,i=a((r,n,l=!1,v=!1)=>{if(l)try{W(r)}catch(b){if(b.code!=="ENOENT")throw b;v&&t.auditMissing(r);return}p.set(r,n||(p.get(r)??!1))},"add");for(const r of["/usr","/bin","/lib","/lib64","/opt/crouter","/etc/passwd","/etc/group","/etc/resolv.conf","/etc/hosts","/etc/ssl","/etc/ca-certificates"])i(r,!1,!0);t.withoutNode||i(I(t.nodeId,t.app),!0),t.folder!==void 0&&i(t.folder,!0),t.cron?.anchorDir!==void 0&&i(t.cron.anchorDir,!0),t.isolated||i(o.home,!0),t.isolated||i(o.files,!0),i(o.cache,!0,!0),(!t.withoutNode||t.cron!==void 0)&&i(k(t.nodeId),!0),t.cron===void 0&&(i(u(m(),"api.sock"),!0),i(u(m(),"store.sock"),!0));for(const r of x(e))i(r.source,r.writable,!0,!0);if(t.pluginRoot!==void 0){const r=a(l=>t.pluginRoot===l||f(l,t.pluginRoot)!==".."&&!f(l,t.pluginRoot).startsWith(`..${c}`),"within"),n=u(h(),"plugins");if([...p].some(([l])=>r(l))){if(p.get(t.pluginRoot)===!0)throw new Error("hook root cannot also be writable");i(t.pluginRoot,!1)}else if(r(n)&&t.pluginRoot!==n)i(t.pluginRoot,!1);else if(r("/opt/crouter"))i(t.pluginRoot,!1);else throw new Error("hook root is not readable with this app\u2019s mounts")}const y=t.cwd??s??o.files,g=[...p].sort(([r],[n])=>r.split(c).length-n.split(c).length||r.localeCompare(n)),D=u(h(),"nodes",t.nodeId,"job","broker.log"),N=process.platform!=="linux"?[k(t.nodeId),u(m(),"api.sock"),u(m(),"store.sock")]:[];if(g.some(([r])=>r!==t.pluginRoot&&!N.includes(r)&&(r===h()||!f(h(),r).startsWith("..")&&!f(h(),r).startsWith(c))))throw new Error("runtime records cannot be mounted");return{nodeId:t.nodeId,uid:await A(t.app),mounts:g.map(([r,n])=>({source:r,writable:n})),cwd:y,env:t.env,command:t.command,log:D,...t.isolated?{network:"none"}:{}}}a(B,"compileLaunch");export{B as compileLaunch,x as grantedMounts,M as isGrantedSource,z as launchStillGranted,j as mountAllowed};
@@ -10,7 +10,7 @@ export interface RunPermissions {
10
10
  otherNodes: string[];
11
11
  }
12
12
  /** Only the active mirror and the launched scope list determine a run's mounts. */
13
- export declare function permissionsForRun(app: string, sub: string, grantId: string | null, launched: string[] | null): RunPermissions;
13
+ export declare function permissionsForRun(app: string, sub: string, grantId: string | null, launched: string[] | null): Promise<RunPermissions>;
14
14
  /** The same computation over a given grant record, e.g. the mirror before a sync replaced it. */
15
15
  export declare function permissionsForGrant(app: string, sub: string, grant: ActiveGrant | null, launched: string[] | null): RunPermissions;
16
16
  /** A project is available only through an actual file mount, never a symlink or an ancestor of it. */
@@ -1 +1 @@
1
- var v=Object.defineProperty;var f=(r,i)=>v(r,"name",{value:i,configurable:!0});import{parseScope as A}from"@north-light/identity";import{coveredByAny as u}from"../../shared/env.js";import{activeGrant as F,grantFor as S}from"../grants/mirror.js";import{appSpace as w,userFilesRoot as j}from"../layout.js";import{contains as h}from"./file-root.js";import{join as E,resolve as l}from"node:path";import{lstatSync as z,realpathSync as y}from"node:fs";function g(r,i,o,e){return R(r,i,o?F(o):S(r,i),e)}f(g,"permissionsForRun");function R(r,i,o,e){if(!o||o.grantee!==r||o.sub!==i)throw new Error(`no active grant for ${r}`);if(e!==null&&!Array.isArray(e))throw new Error("invalid launched scopes");const t=[],n=[];let c=e===null;const d=e??o.resolved;for(const s of d){if(typeof s!="string")throw new Error("invalid launched scope");A(s);const $=s===`crtr:memory:read:${r}`||s===`crtr:memory:rw:${r}`||s.startsWith(`crtr:memory:read:${r}:`)||s.startsWith(`crtr:memory:rw:${r}:`);if(e!==null&&!$&&!u(o.resolved,s))throw new Error(`launched scope not in grant: ${s}`);const m=/^crtr:files:(read|rw):(user|app:[A-Za-z0-9_-]{1,64}):(.+)$/.exec(s);if(m){const[,x,p,b]=m;if(p===r)throw new Error(`own-app files cannot narrow a run: ${s}`);t.push({holder:p,path:b,writable:x==="rw"})}const a=/^crtr:objects:read:(app:[A-Za-z0-9_-]{1,64})$/.exec(s);a&&a[1]!==r&&n.push(a[1])}return{app:r,ownNodes:c,otherFiles:t,otherNodes:n}}f(R,"permissionsForGrant");function Z(r,i){const o=l(r);for(const e of i){const t=l(e);if(h(t,o))try{if(y(o)!==o||y(t)!==t)continue;let n=o;for(;h(t,n)&&!z(n).isSymbolicLink();){if(n===t)return!0;n=l(n,"..")}}catch{}}return!1}f(Z,"readableProject");function q(r,i,o,e){const t=[w(i).files];for(const n of e??o){if(e!==null&&!u(o,n))continue;const c=/^crtr:files:(?:read|rw):(user|app:[A-Za-z0-9_-]{1,64}):(.+)$/.exec(n);c&&t.push(E(c[1]==="user"?j():w(c[1]).files,c[2]==="."?"":c[2]))}return Z(r,t)}f(q,"readableProjectForScopes");import{fileRoot as H}from"./file-root.js";export{H as fileRoot,R as permissionsForGrant,g as permissionsForRun,Z as readableProject,q as readableProjectForScopes};
1
+ var v=Object.defineProperty;var f=(r,i)=>v(r,"name",{value:i,configurable:!0});import{parseScope as A}from"@north-light/identity";import{coveredByAny as u}from"../../shared/env.js";import{activeGrant as F,grantFor as S}from"../grants/mirror.js";import{appSpace as w,userFilesRoot as j}from"../layout.js";import{contains as h}from"./file-root.js";import{join as E,resolve as l}from"node:path";import{lstatSync as z,realpathSync as y}from"node:fs";async function g(r,i,o,e){return R(r,i,o?await F(o):await S(r,i),e)}f(g,"permissionsForRun");function R(r,i,o,e){if(!o||o.grantee!==r||o.sub!==i)throw new Error(`no active grant for ${r}`);if(e!==null&&!Array.isArray(e))throw new Error("invalid launched scopes");const t=[],n=[];let c=e===null;const d=e??o.resolved;for(const s of d){if(typeof s!="string")throw new Error("invalid launched scope");A(s);const $=s===`crtr:memory:read:${r}`||s===`crtr:memory:rw:${r}`||s.startsWith(`crtr:memory:read:${r}:`)||s.startsWith(`crtr:memory:rw:${r}:`);if(e!==null&&!$&&!u(o.resolved,s))throw new Error(`launched scope not in grant: ${s}`);const m=/^crtr:files:(read|rw):(user|app:[A-Za-z0-9_-]{1,64}):(.+)$/.exec(s);if(m){const[,x,p,b]=m;if(p===r)throw new Error(`own-app files cannot narrow a run: ${s}`);t.push({holder:p,path:b,writable:x==="rw"})}const a=/^crtr:objects:read:(app:[A-Za-z0-9_-]{1,64})$/.exec(s);a&&a[1]!==r&&n.push(a[1])}return{app:r,ownNodes:c,otherFiles:t,otherNodes:n}}f(R,"permissionsForGrant");function Z(r,i){const o=l(r);for(const e of i){const t=l(e);if(h(t,o))try{if(y(o)!==o||y(t)!==t)continue;let n=o;for(;h(t,n)&&!z(n).isSymbolicLink();){if(n===t)return!0;n=l(n,"..")}}catch{}}return!1}f(Z,"readableProject");function q(r,i,o,e){const t=[w(i).files];for(const n of e??o){if(e!==null&&!u(o,n))continue;const c=/^crtr:files:(?:read|rw):(user|app:[A-Za-z0-9_-]{1,64}):(.+)$/.exec(n);c&&t.push(E(c[1]==="user"?j():w(c[1]).files,c[2]==="."?"":c[2]))}return Z(r,t)}f(q,"readableProjectForScopes");import{fileRoot as H}from"./file-root.js";export{H as fileRoot,R as permissionsForGrant,g as permissionsForRun,Z as readableProject,q as readableProjectForScopes};
@@ -53,7 +53,7 @@ export declare function cwdIsMounted(app: string, cwd: string, nodeId?: string,
53
53
  sub: string;
54
54
  grantId: string | null;
55
55
  scopes: string[] | null;
56
- }): boolean;
56
+ }): Promise<boolean>;
57
57
  export declare function stopAppProcess(pid: number, signal?: 'SIGTERM' | 'SIGKILL', nodeId?: string): Promise<void>;
58
58
  /** A node-backed isolated process always starts in its own agent folder.
59
59
  * Callers validate explicitly requested cwd separately (e.g. hook execution). */