@north-light/cli 0.3.529 → 0.3.531

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. package/dist/api/dto/lifecycle.d.ts +3 -1
  2. package/dist/api/dto/messages.d.ts +5 -3
  3. package/dist/builtin-memory/crouter-plugin/bundles-and-memory.md +1 -1
  4. package/dist/builtin-memory/crouter-plugin/commands.md +1 -1
  5. package/dist/clients/attach/session/connection.js +1 -1
  6. package/dist/clients/attach/session/reconnect.js +1 -1
  7. package/dist/clients/attach/viewer.js +508 -508
  8. package/dist/commands/node/message.js +1 -1
  9. package/dist/commands/sys/join.js +1 -1
  10. package/dist/core/async-array.d.ts +7 -0
  11. package/dist/core/async-array.js +1 -0
  12. package/dist/core/audit.d.ts +1 -1
  13. package/dist/core/audit.js +2 -2
  14. package/dist/core/canvas/attention.d.ts +4 -4
  15. package/dist/core/canvas/attention.js +1 -1
  16. package/dist/core/canvas/boot.d.ts +4 -4
  17. package/dist/core/canvas/boot.js +1 -1
  18. package/dist/core/canvas/canvas.d.ts +59 -59
  19. package/dist/core/canvas/canvas.js +19 -19
  20. package/dist/core/canvas/context-strip.js +2 -2
  21. package/dist/core/canvas/crons.d.ts +27 -27
  22. package/dist/core/canvas/crons.js +11 -11
  23. package/dist/core/canvas/daemon-actions.d.ts +10 -10
  24. package/dist/core/canvas/daemon-actions.js +8 -8
  25. package/dist/core/canvas/daemon-owner.d.ts +3 -3
  26. package/dist/core/canvas/daemon-owner.js +2 -2
  27. package/dist/core/canvas/db.d.ts +19 -30
  28. package/dist/core/canvas/db.js +3 -2
  29. package/dist/core/canvas/deliveries.d.ts +16 -16
  30. package/dist/core/canvas/deliveries.js +24 -24
  31. package/dist/core/canvas/executions.d.ts +8 -8
  32. package/dist/core/canvas/executions.js +1 -1
  33. package/dist/core/canvas/focuses.d.ts +8 -8
  34. package/dist/core/canvas/focuses.js +1 -1
  35. package/dist/core/canvas/history.d.ts +3 -3
  36. package/dist/core/canvas/history.js +9 -9
  37. package/dist/core/canvas/install-id.d.ts +1 -1
  38. package/dist/core/canvas/install-id.js +1 -1
  39. package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +1 -1
  40. package/dist/core/canvas/managed-worktree-sweep-candidates.js +2 -2
  41. package/dist/core/canvas/memory-reads.d.ts +6 -6
  42. package/dist/core/canvas/memory-reads.js +1 -1
  43. package/dist/core/canvas/nav-model.d.ts +13 -13
  44. package/dist/core/canvas/nav-model.js +1 -1
  45. package/dist/core/canvas/node-agent-paths.d.ts +6 -6
  46. package/dist/core/canvas/node-agent-paths.js +1 -1
  47. package/dist/core/canvas/node-tokens.d.ts +7 -7
  48. package/dist/core/canvas/node-tokens.js +3 -3
  49. package/dist/core/canvas/outcome-actions.d.ts +5 -5
  50. package/dist/core/canvas/outcome-actions.js +3 -3
  51. package/dist/core/canvas/recovery.d.ts +26 -26
  52. package/dist/core/canvas/recovery.js +2 -2
  53. package/dist/core/canvas/render-source.d.ts +1 -1
  54. package/dist/core/canvas/render-source.js +1 -1
  55. package/dist/core/canvas/sessions.d.ts +10 -10
  56. package/dist/core/canvas/sessions.js +4 -4
  57. package/dist/core/canvas/source.js +1 -1
  58. package/dist/core/canvas/structured-requests.d.ts +15 -15
  59. package/dist/core/canvas/structured-requests.js +5 -5
  60. package/dist/core/canvas/tree.d.ts +9 -9
  61. package/dist/core/canvas/tree.js +5 -5
  62. package/dist/core/canvas/waits.d.ts +13 -13
  63. package/dist/core/canvas/waits.js +6 -6
  64. package/dist/core/canvas/worktrees.d.ts +15 -15
  65. package/dist/core/canvas/worktrees.js +1 -1
  66. package/dist/core/command-hooks/lifecycle-catalog.d.ts +4 -4
  67. package/dist/core/command-hooks/lifecycle-catalog.js +1 -1
  68. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  69. package/dist/core/command-plugins/bundle.d.ts +1 -1
  70. package/dist/core/command-plugins/bundle.js +1 -1
  71. package/dist/core/conversation-store/file-store.d.ts +7 -7
  72. package/dist/core/conversation-store/file-store.js +9 -9
  73. package/dist/core/conversation-store/index.d.ts +16 -14
  74. package/dist/core/conversation-store/index.js +1 -1
  75. package/dist/core/conversation-store/listener.js +5 -5
  76. package/dist/core/conversation-store/patch.d.ts +3 -1
  77. package/dist/core/conversation-store/patch.js +1 -1
  78. package/dist/core/directory/join.d.ts +1 -1
  79. package/dist/core/feed/feed.js +3 -3
  80. package/dist/core/feed/inbox.d.ts +2 -2
  81. package/dist/core/feed/inbox.js +1 -1
  82. package/dist/core/feed/messages.d.ts +11 -12
  83. package/dist/core/feed/messages.js +5 -5
  84. package/dist/core/feed/reports.d.ts +4 -4
  85. package/dist/core/feed/reports.js +2 -2
  86. package/dist/core/grants/cover.d.ts +1 -1
  87. package/dist/core/grants/cover.js +1 -1
  88. package/dist/core/grants/local.d.ts +1 -1
  89. package/dist/core/grants/local.js +1 -1
  90. package/dist/core/grants/mirror.d.ts +19 -19
  91. package/dist/core/grants/mirror.js +2 -2
  92. package/dist/core/grants/on-sync.d.ts +1 -1
  93. package/dist/core/grants/on-sync.js +1 -1
  94. package/dist/core/grants/remove.js +1 -1
  95. package/dist/core/grants/sync.js +1 -1
  96. package/dist/core/graph/access.d.ts +17 -17
  97. package/dist/core/graph/access.js +3 -3
  98. package/dist/core/graph/custom.d.ts +16 -16
  99. package/dist/core/graph/custom.js +9 -9
  100. package/dist/core/graph/deletion.d.ts +3 -7
  101. package/dist/core/graph/deletion.js +4 -4
  102. package/dist/core/graph/documents.d.ts +24 -27
  103. package/dist/core/graph/documents.js +7 -7
  104. package/dist/core/graph/edges.d.ts +13 -13
  105. package/dist/core/graph/edges.js +1 -1
  106. package/dist/core/graph/events.d.ts +7 -9
  107. package/dist/core/graph/events.js +8 -8
  108. package/dist/core/graph/exposures.d.ts +6 -6
  109. package/dist/core/graph/exposures.js +4 -4
  110. package/dist/core/graph/jobs.d.ts +6 -8
  111. package/dist/core/graph/jobs.js +2 -2
  112. package/dist/core/graph/kinds/action.js +1 -1
  113. package/dist/core/graph/kinds/custom.js +2 -2
  114. package/dist/core/graph/kinds/document.d.ts +1 -0
  115. package/dist/core/graph/kinds/document.js +4 -4
  116. package/dist/core/graph/kinds/dto.d.ts +2 -2
  117. package/dist/core/graph/kinds/dto.js +1 -1
  118. package/dist/core/graph/kinds/job.js +2 -2
  119. package/dist/core/graph/kinds/kind.d.ts +6 -8
  120. package/dist/core/graph/kinds/kind.js +1 -1
  121. package/dist/core/graph/kinds/node.js +5 -5
  122. package/dist/core/graph/kinds/owner.js +2 -2
  123. package/dist/core/graph/kinds/registry.d.ts +6 -9
  124. package/dist/core/graph/kinds/registry.js +1 -1
  125. package/dist/core/graph/names.d.ts +6 -6
  126. package/dist/core/graph/names.js +3 -3
  127. package/dist/core/graph/object-waits.d.ts +4 -7
  128. package/dist/core/graph/object-waits.js +1 -1
  129. package/dist/core/graph/objects.d.ts +14 -14
  130. package/dist/core/graph/objects.js +9 -9
  131. package/dist/core/graph/package-docs.d.ts +2 -7
  132. package/dist/core/graph/package-docs.js +5 -5
  133. package/dist/core/graph/package-kinds.d.ts +2 -5
  134. package/dist/core/graph/package-kinds.js +1 -1
  135. package/dist/core/graph/package-reconcile.d.ts +2 -5
  136. package/dist/core/graph/package-reconcile.js +1 -1
  137. package/dist/core/graph/reader.d.ts +18 -18
  138. package/dist/core/graph/reader.js +3 -3
  139. package/dist/core/graph/receivers.d.ts +4 -4
  140. package/dist/core/graph/receivers.js +5 -5
  141. package/dist/core/graph/repo-sync/exchange.d.ts +3 -7
  142. package/dist/core/graph/repo-sync/exchange.js +2 -2
  143. package/dist/core/graph/repo-sync/repos.d.ts +7 -5
  144. package/dist/core/graph/repo-sync/repos.js +3 -3
  145. package/dist/core/graph/repo-sync/sync.d.ts +3 -6
  146. package/dist/core/graph/repo-sync/sync.js +2 -2
  147. package/dist/core/graph/rules.d.ts +5 -5
  148. package/dist/core/graph/rules.js +3 -3
  149. package/dist/core/graph/spaces/app.js +1 -1
  150. package/dist/core/graph/spaces/index.d.ts +4 -5
  151. package/dist/core/graph/spaces/index.js +1 -1
  152. package/dist/core/graph/spaces/own-memory.d.ts +4 -4
  153. package/dist/core/graph/spaces/own-memory.js +1 -1
  154. package/dist/core/graph/spaces/person.js +3 -3
  155. package/dist/core/graph/spaces/repo.d.ts +1 -1
  156. package/dist/core/graph/spaces/repo.js +1 -1
  157. package/dist/core/graph/watches.d.ts +15 -15
  158. package/dist/core/graph/watches.js +10 -10
  159. package/dist/core/human/feedback-companion.d.ts +2 -2
  160. package/dist/core/human/feedback-companion.js +1 -1
  161. package/dist/core/human/feedback.d.ts +3 -3
  162. package/dist/core/human/feedback.js +1 -1
  163. package/dist/core/human/requests.d.ts +34 -33
  164. package/dist/core/human/requests.js +20 -20
  165. package/dist/core/human/scan.d.ts +2 -2
  166. package/dist/core/human/scan.js +1 -1
  167. package/dist/core/human/tickets.d.ts +9 -9
  168. package/dist/core/human/tickets.js +1 -1
  169. package/dist/core/llm/app-rungs.d.ts +1 -1
  170. package/dist/core/llm/app-rungs.js +1 -1
  171. package/dist/core/llm/run.js +1 -1
  172. package/dist/core/peer/directory.d.ts +1 -1
  173. package/dist/core/peer/directory.js +1 -1
  174. package/dist/core/peer/envelope.d.ts +3 -3
  175. package/dist/core/peer/envelope.js +1 -1
  176. package/dist/core/peer/home.d.ts +7 -7
  177. package/dist/core/peer/home.js +2 -2
  178. package/dist/core/peer/ingest.d.ts +6 -6
  179. package/dist/core/peer/ingest.js +1 -1
  180. package/dist/core/peer/outbox-store.d.ts +14 -14
  181. package/dist/core/peer/outbox-store.js +5 -5
  182. package/dist/core/peer/receiver.d.ts +2 -2
  183. package/dist/core/peer/receiver.js +1 -1
  184. package/dist/core/peer/stubs.d.ts +10 -10
  185. package/dist/core/peer/stubs.js +1 -1
  186. package/dist/core/providers/approval.d.ts +2 -2
  187. package/dist/core/providers/approval.js +2 -2
  188. package/dist/core/providers/audit.d.ts +3 -3
  189. package/dist/core/providers/audit.js +2 -2
  190. package/dist/core/providers/bundles.js +2 -2
  191. package/dist/core/providers/call.d.ts +2 -2
  192. package/dist/core/providers/call.js +1 -1
  193. package/dist/core/providers/files.d.ts +1 -1
  194. package/dist/core/providers/files.js +1 -1
  195. package/dist/core/providers/mint.js +1 -1
  196. package/dist/core/providers/receipts.d.ts +1 -1
  197. package/dist/core/providers/receipts.js +2 -2
  198. package/dist/core/review/birth.js +1 -1
  199. package/dist/core/review/comments.d.ts +19 -19
  200. package/dist/core/review/comments.js +5 -5
  201. package/dist/core/review/companion.d.ts +1 -1
  202. package/dist/core/review/companion.js +1 -1
  203. package/dist/core/review/document.d.ts +3 -3
  204. package/dist/core/review/document.js +2 -2
  205. package/dist/core/review/fork.js +2 -2
  206. package/dist/core/review/realize.js +1 -1
  207. package/dist/core/review/remap.d.ts +2 -2
  208. package/dist/core/review/remap.js +4 -4
  209. package/dist/core/review/stage.d.ts +1 -1
  210. package/dist/core/review/stage.js +1 -1
  211. package/dist/core/review/store.d.ts +21 -21
  212. package/dist/core/review/store.js +1 -1
  213. package/dist/core/runs/activity.d.ts +1 -1
  214. package/dist/core/runs/activity.js +5 -5
  215. package/dist/core/runs/confinement.d.ts +7 -7
  216. package/dist/core/runs/confinement.js +2 -2
  217. package/dist/core/runs/events.d.ts +12 -12
  218. package/dist/core/runs/events.js +4 -4
  219. package/dist/core/runs/operations.d.ts +11 -11
  220. package/dist/core/runs/operations.js +5 -5
  221. package/dist/core/runs/questions.d.ts +10 -10
  222. package/dist/core/runs/questions.js +3 -3
  223. package/dist/core/runtime/auth-reload.js +1 -1
  224. package/dist/core/runtime/bearings.d.ts +5 -5
  225. package/dist/core/runtime/bearings.js +6 -6
  226. package/dist/core/runtime/broker-inventory.js +1 -1
  227. package/dist/core/runtime/broker-request.js +1 -1
  228. package/dist/core/runtime/broker.js +1 -1
  229. package/dist/core/runtime/close.d.ts +3 -3
  230. package/dist/core/runtime/close.js +1 -1
  231. package/dist/core/runtime/deliver-live.js +1 -1
  232. package/dist/core/runtime/fleet.d.ts +2 -2
  233. package/dist/core/runtime/host.d.ts +3 -3
  234. package/dist/core/runtime/host.js +3 -3
  235. package/dist/core/runtime/kickoff.d.ts +12 -12
  236. package/dist/core/runtime/kickoff.js +17 -17
  237. package/dist/core/runtime/launch-target.d.ts +1 -1
  238. package/dist/core/runtime/launch-target.js +1 -1
  239. package/dist/core/runtime/ledger.d.ts +3 -3
  240. package/dist/core/runtime/ledger.js +3 -3
  241. package/dist/core/runtime/lifecycle.d.ts +1 -1
  242. package/dist/core/runtime/lifecycle.js +2 -2
  243. package/dist/core/runtime/memory-admission.js +1 -1
  244. package/dist/core/runtime/model-swap.d.ts +2 -2
  245. package/dist/core/runtime/model-swap.js +1 -1
  246. package/dist/core/runtime/node-read.d.ts +1 -1
  247. package/dist/core/runtime/node-read.js +2 -2
  248. package/dist/core/runtime/nodes.d.ts +6 -6
  249. package/dist/core/runtime/nodes.js +1 -1
  250. package/dist/core/runtime/outcome-document.d.ts +1 -1
  251. package/dist/core/runtime/outcome-document.js +1 -1
  252. package/dist/core/runtime/persona.d.ts +3 -3
  253. package/dist/core/runtime/persona.js +2 -2
  254. package/dist/core/runtime/placement.d.ts +11 -11
  255. package/dist/core/runtime/placement.js +1 -1
  256. package/dist/core/runtime/promote.d.ts +3 -3
  257. package/dist/core/runtime/promote.js +1 -1
  258. package/dist/core/runtime/recycle.js +1 -1
  259. package/dist/core/runtime/reopen.d.ts +21 -10
  260. package/dist/core/runtime/reopen.js +1 -1
  261. package/dist/core/runtime/reset.d.ts +4 -4
  262. package/dist/core/runtime/reset.js +1 -1
  263. package/dist/core/runtime/revive-all.d.ts +2 -2
  264. package/dist/core/runtime/revive-all.js +1 -1
  265. package/dist/core/runtime/revive.d.ts +4 -4
  266. package/dist/core/runtime/revive.js +2 -2
  267. package/dist/core/runtime/roadmap.d.ts +6 -6
  268. package/dist/core/runtime/roadmap.js +5 -5
  269. package/dist/core/runtime/session-branch.d.ts +1 -1
  270. package/dist/core/runtime/session-branch.js +1 -1
  271. package/dist/core/runtime/session-list-cache.js +1 -1
  272. package/dist/core/runtime/situational-live.js +1 -1
  273. package/dist/core/runtime/spawn.d.ts +2 -2
  274. package/dist/core/runtime/spawn.js +2 -2
  275. package/dist/core/runtime/stop-guard.d.ts +2 -2
  276. package/dist/core/runtime/stop-guard.js +3 -3
  277. package/dist/core/runtime/warm-pool.d.ts +2 -2
  278. package/dist/core/runtime/warm-pool.js +1 -1
  279. package/dist/core/spaces/mounts.d.ts +2 -2
  280. package/dist/core/spaces/mounts.js +1 -1
  281. package/dist/core/spaces/permissions.d.ts +1 -1
  282. package/dist/core/spaces/permissions.js +1 -1
  283. package/dist/core/spaces/process.d.ts +1 -1
  284. package/dist/core/spaces/process.js +1 -1
  285. package/dist/core/spaces/space.js +1 -1
  286. package/dist/core/spaces/stop.d.ts +3 -3
  287. package/dist/core/spaces/stop.js +2 -2
  288. package/dist/core/spaces/users.d.ts +6 -6
  289. package/dist/core/spaces/users.js +1 -1
  290. package/dist/core/storage/attachments.d.ts +2 -2
  291. package/dist/core/storage/attachments.js +1 -1
  292. package/dist/core/storage/shares.d.ts +2 -2
  293. package/dist/core/storage/shares.js +1 -1
  294. package/dist/core/storage/tables.d.ts +21 -21
  295. package/dist/core/storage/tables.js +3 -3
  296. package/dist/core/substrate/delivery/corpus.d.ts +5 -8
  297. package/dist/core/substrate/delivery/corpus.js +3 -3
  298. package/dist/core/substrate/delivery/deliver.d.ts +10 -15
  299. package/dist/core/substrate/delivery/deliver.js +3 -3
  300. package/dist/core/substrate/delivery/plan.d.ts +2 -12
  301. package/dist/core/substrate/delivery/plan.js +3 -3
  302. package/dist/core/substrate/delivery/render-boot.d.ts +4 -4
  303. package/dist/core/substrate/delivery/render-boot.js +18 -18
  304. package/dist/core/substrate/delivery/render-event.d.ts +7 -14
  305. package/dist/core/substrate/delivery/render-event.js +4 -4
  306. package/dist/core/substrate/subject.d.ts +2 -2
  307. package/dist/core/substrate/subject.js +1 -1
  308. package/dist/core/usage/ledger.d.ts +6 -6
  309. package/dist/core/usage/ledger.js +4 -4
  310. package/dist/core/worktree-close.js +4 -4
  311. package/dist/core/worktree-mutation-async.js +7 -7
  312. package/dist/core/worktree-quarantine.js +1 -1
  313. package/dist/core/worktree-sweep.d.ts +1 -1
  314. package/dist/core/worktree-sweep.js +6 -6
  315. package/dist/core/worktree.d.ts +5 -5
  316. package/dist/core/worktree.js +13 -13
  317. package/dist/daemon/analytics/compute.d.ts +2 -2
  318. package/dist/daemon/analytics/compute.js +1 -1
  319. package/dist/daemon/api/app-listener.d.ts +4 -4
  320. package/dist/daemon/api/app-listener.js +13 -13
  321. package/dist/daemon/api/bridge.js +5 -5
  322. package/dist/daemon/api/document-listener.js +6 -6
  323. package/dist/daemon/api/handlers/analytics.js +1 -1
  324. package/dist/daemon/api/handlers/attach.js +1 -1
  325. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  326. package/dist/daemon/api/handlers/bash.js +1 -1
  327. package/dist/daemon/api/handlers/broker-ops.d.ts +1 -1
  328. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  329. package/dist/daemon/api/handlers/broker-recovery.d.ts +1 -1
  330. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  331. package/dist/daemon/api/handlers/broker-signals.d.ts +2 -2
  332. package/dist/daemon/api/handlers/broker-signals.js +2 -2
  333. package/dist/daemon/api/handlers/canvas.d.ts +1 -1
  334. package/dist/daemon/api/handlers/canvas.js +4 -4
  335. package/dist/daemon/api/handlers/chat-inventory.js +1 -1
  336. package/dist/daemon/api/handlers/crons.js +1 -1
  337. package/dist/daemon/api/handlers/custom-objects.d.ts +4 -4
  338. package/dist/daemon/api/handlers/custom-objects.js +3 -3
  339. package/dist/daemon/api/handlers/delivery-retry.js +1 -1
  340. package/dist/daemon/api/handlers/delivery.js +1 -1
  341. package/dist/daemon/api/handlers/docs.d.ts +4 -4
  342. package/dist/daemon/api/handlers/docs.js +1 -1
  343. package/dist/daemon/api/handlers/feedback-comments.js +3 -3
  344. package/dist/daemon/api/handlers/files.js +1 -1
  345. package/dist/daemon/api/handlers/focus.js +1 -1
  346. package/dist/daemon/api/handlers/health.js +3 -3
  347. package/dist/daemon/api/handlers/hook-exec.js +1 -1
  348. package/dist/daemon/api/handlers/human-requests.js +1 -1
  349. package/dist/daemon/api/handlers/inbox-page.d.ts +1 -1
  350. package/dist/daemon/api/handlers/inbox-page.js +1 -1
  351. package/dist/daemon/api/handlers/inbox.d.ts +1 -1
  352. package/dist/daemon/api/handlers/inbox.js +1 -1
  353. package/dist/daemon/api/handlers/llm.d.ts +1 -1
  354. package/dist/daemon/api/handlers/llm.js +3 -3
  355. package/dist/daemon/api/handlers/memory-reads.js +1 -1
  356. package/dist/daemon/api/handlers/memory.d.ts +5 -5
  357. package/dist/daemon/api/handlers/memory.js +5 -5
  358. package/dist/daemon/api/handlers/messages.js +2 -2
  359. package/dist/daemon/api/handlers/node-events.d.ts +2 -2
  360. package/dist/daemon/api/handlers/node-events.js +3 -3
  361. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  362. package/dist/daemon/api/handlers/node-records.js +2 -2
  363. package/dist/daemon/api/handlers/nodes.d.ts +1 -1
  364. package/dist/daemon/api/handlers/nodes.js +1 -1
  365. package/dist/daemon/api/handlers/objects.js +3 -3
  366. package/dist/daemon/api/handlers/package-docs.js +1 -1
  367. package/dist/daemon/api/handlers/plugin-app-token.d.ts +1 -1
  368. package/dist/daemon/api/handlers/plugin-app-token.js +1 -1
  369. package/dist/daemon/api/handlers/profiles.d.ts +3 -3
  370. package/dist/daemon/api/handlers/profiles.js +1 -1
  371. package/dist/daemon/api/handlers/providers.d.ts +1 -1
  372. package/dist/daemon/api/handlers/providers.js +1 -1
  373. package/dist/daemon/api/handlers/questions.js +1 -1
  374. package/dist/daemon/api/handlers/reports.d.ts +1 -1
  375. package/dist/daemon/api/handlers/reports.js +5 -5
  376. package/dist/daemon/api/handlers/review-comments.js +1 -1
  377. package/dist/daemon/api/handlers/reviews.js +1 -1
  378. package/dist/daemon/api/handlers/runs.js +1 -1
  379. package/dist/daemon/api/handlers/structured-requests.js +1 -1
  380. package/dist/daemon/api/handlers/subscriptions.js +1 -1
  381. package/dist/daemon/api/handlers/transfer.js +1 -1
  382. package/dist/daemon/api/map.d.ts +3 -3
  383. package/dist/daemon/api/map.js +1 -1
  384. package/dist/daemon/api/principal.d.ts +1 -1
  385. package/dist/daemon/api/principal.js +1 -1
  386. package/dist/daemon/api/reader.d.ts +5 -5
  387. package/dist/daemon/api/reader.js +1 -1
  388. package/dist/daemon/api/router.d.ts +5 -5
  389. package/dist/daemon/api/router.js +1 -1
  390. package/dist/daemon/api/server.js +1 -1
  391. package/dist/daemon/broker-signals/bus.d.ts +1 -1
  392. package/dist/daemon/broker-signals/bus.js +1 -1
  393. package/dist/daemon/companion-retire.js +1 -1
  394. package/dist/daemon/cron/armed-context.d.ts +2 -2
  395. package/dist/daemon/cron/armed-context.js +1 -1
  396. package/dist/daemon/cron/authority.d.ts +2 -2
  397. package/dist/daemon/cron/authority.js +1 -1
  398. package/dist/daemon/cron/disposition.js +1 -1
  399. package/dist/daemon/cron/ended.d.ts +1 -1
  400. package/dist/daemon/cron/ended.js +2 -2
  401. package/dist/daemon/cron/escalation.js +3 -3
  402. package/dist/daemon/cron/folders.d.ts +1 -1
  403. package/dist/daemon/cron/folders.js +1 -1
  404. package/dist/daemon/cron/held.d.ts +1 -1
  405. package/dist/daemon/cron/held.js +1 -1
  406. package/dist/daemon/cron/lease-recovery.d.ts +1 -1
  407. package/dist/daemon/cron/lease-recovery.js +1 -1
  408. package/dist/daemon/cron/passes.d.ts +2 -2
  409. package/dist/daemon/cron/passes.js +1 -1
  410. package/dist/daemon/cron/run-socket.d.ts +1 -1
  411. package/dist/daemon/cron/run-socket.js +1 -1
  412. package/dist/daemon/cron/settle.js +1 -1
  413. package/dist/daemon/cron/sinks.d.ts +1 -1
  414. package/dist/daemon/cron/sinks.js +2 -2
  415. package/dist/daemon/cron-run.d.ts +12 -3
  416. package/dist/daemon/cron-run.js +2 -2
  417. package/dist/daemon/crtrd.js +6 -6
  418. package/dist/daemon/delivery/run-delivery.js +1 -1
  419. package/dist/daemon/due-sources.d.ts +3 -3
  420. package/dist/daemon/due-sources.js +1 -1
  421. package/dist/daemon/due.d.ts +3 -3
  422. package/dist/daemon/due.js +7 -7
  423. package/dist/daemon/fleet.d.ts +2 -2
  424. package/dist/daemon/fleet.js +11 -11
  425. package/dist/daemon/human/finish.js +3 -3
  426. package/dist/daemon/human/settle.d.ts +1 -1
  427. package/dist/daemon/human/settle.js +1 -1
  428. package/dist/daemon/human/sweep.js +1 -1
  429. package/dist/daemon/joined-owner.d.ts +3 -3
  430. package/dist/daemon/joined-owner.js +1 -1
  431. package/dist/daemon/messaging/node-message.js +1 -1
  432. package/dist/daemon/park-activity.d.ts +2 -2
  433. package/dist/daemon/park-activity.js +1 -1
  434. package/dist/daemon/peer/authority.js +1 -1
  435. package/dist/daemon/peer/forward.d.ts +6 -6
  436. package/dist/daemon/peer/forward.js +1 -1
  437. package/dist/daemon/peer/handlers.js +1 -1
  438. package/dist/daemon/peer/ingress.d.ts +4 -4
  439. package/dist/daemon/peer/ingress.js +1 -1
  440. package/dist/daemon/peer/outbox.d.ts +2 -2
  441. package/dist/daemon/peer/outbox.js +1 -1
  442. package/dist/daemon/peer/relay-service.js +1 -1
  443. package/dist/daemon/plugin-objects/read-leaf.d.ts +2 -2
  444. package/dist/daemon/plugin-objects/read-leaf.js +2 -2
  445. package/dist/daemon/profile-delete.js +1 -1
  446. package/dist/daemon/readiness.d.ts +2 -2
  447. package/dist/daemon/readiness.js +1 -1
  448. package/dist/daemon/reconcilers/action-lane.d.ts +1 -1
  449. package/dist/daemon/reconcilers/action-lane.js +1 -1
  450. package/dist/daemon/reconcilers/bash-deadline.js +2 -2
  451. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  452. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  453. package/dist/daemon/reconcilers/controller-death.d.ts +1 -1
  454. package/dist/daemon/reconcilers/controller-death.js +1 -1
  455. package/dist/daemon/reconcilers/cron-lane.d.ts +1 -1
  456. package/dist/daemon/reconcilers/cron-lane.js +1 -1
  457. package/dist/daemon/reconcilers/delivery-lane.d.ts +1 -1
  458. package/dist/daemon/reconcilers/delivery-lane.js +2 -2
  459. package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +3 -3
  460. package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
  461. package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +2 -2
  462. package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
  463. package/dist/daemon/reconcilers/live-obligation.d.ts +6 -6
  464. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  465. package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
  466. package/dist/daemon/reconcilers/node-deadline.d.ts +1 -1
  467. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  468. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  469. package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.d.ts +3 -3
  470. package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.js +1 -1
  471. package/dist/daemon/reconcilers/node-lifecycle/terminating.js +1 -1
  472. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  473. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.d.ts +1 -1
  474. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  475. package/dist/daemon/reconcilers/pending-review-submit.d.ts +1 -1
  476. package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
  477. package/dist/daemon/reconcilers/storage-due-work.js +1 -1
  478. package/dist/daemon/reconcilers/storage-maintenance.d.ts +1 -1
  479. package/dist/daemon/reconcilers/storage-maintenance.js +2 -2
  480. package/dist/daemon/reconcilers/structured-request-lane.d.ts +1 -1
  481. package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
  482. package/dist/daemon/review/comment-notify.js +2 -2
  483. package/dist/daemon/review/companion.d.ts +3 -3
  484. package/dist/daemon/review/companion.js +1 -1
  485. package/dist/daemon/review/finish.js +1 -1
  486. package/dist/daemon/review/sweep.js +1 -1
  487. package/dist/daemon/run-notices.d.ts +4 -4
  488. package/dist/daemon/run-notices.js +1 -1
  489. package/dist/daemon/runs/append-section.d.ts +2 -2
  490. package/dist/daemon/runs/append-section.js +2 -2
  491. package/dist/daemon/runs/observer.d.ts +2 -2
  492. package/dist/daemon/runs/observer.js +2 -2
  493. package/dist/daemon/structured-requests/boot.d.ts +1 -1
  494. package/dist/daemon/structured-requests/boot.js +1 -1
  495. package/dist/daemon/structured-requests/effects.js +1 -1
  496. package/dist/daemon/structured-requests/sidecar.d.ts +1 -1
  497. package/dist/daemon/structured-requests/sidecar.js +1 -1
  498. package/dist/launcher/run.js +1 -1
  499. package/dist/migrations/004-canvas-documents/apply.d.ts +3 -3
  500. package/dist/migrations/004-canvas-documents/apply.js +1 -1
  501. package/dist/migrations/004-canvas-documents/index.d.ts +2 -2
  502. package/dist/migrations/004-canvas-documents/index.js +2 -2
  503. package/dist/migrations/activation.js +2 -2
  504. package/docs/plugin/bundles-and-memory.md +1 -1
  505. package/docs/plugin/commands.md +1 -1
  506. package/docs/public-api.md +11 -0
  507. package/package.json +4 -3
  508. package/packages/crouter-identity/package.json +1 -1
  509. package/runtime.lock.json +12 -12
@@ -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). */
@@ -1 +1 @@
1
- var C=Object.defineProperty;var i=(e,r)=>C(e,"name",{value:r,configurable:!0});import{existsSync as v}from"node:fs";import{assertGranteeRunsHere as $}from"../runtime/unsandboxed.js";import{randomUUID as N}from"node:crypto";import{join as h}from"node:path";import{getNode as R}from"../canvas/canvas.js";import{nodeAgentDir as O,nodeHome as k,nodeRunDir as H}from"../canvas/paths.js";import{appSpace as K}from"../layout.js";import{activeGrant as w,activeGrantForApp as _,grantFor as I,grantsGeneration as S}from"../grants/mirror.js";import{readConfig as B}from"../config.js";import{emitEvent as G}from"../events/emit.js";import{ensureAppSpace as F}from"./space.js";import{compileLaunch as T,launchStillGranted as M}from"./mounts.js";import{pinSandboxRuntimeHome as j}from"./runtime-home.js";import{sandboxCacheEnv as q}from"./cache-env.js";import{launcherRequest as b}from"../../launcher/client.js";import{LAUNCHER_SOCKET as y}from"../../launcher/spec.js";function U(e){return`cron-${e}`}i(U,"cronLaunchId");function ce(){if(process.platform!=="linux")return!1;if(v(y))return!0;throw new Error("root launcher socket is unavailable; refusing an unsandboxed app process")}i(ce,"appProcessSandboxed");function fe(){return A??(process.platform==="linux"&&v(y))}i(fe,"appProcessesSandboxed");let A;function le(e){A=e}i(le,"__setAppProcessesSandboxedForTest");function me(e,r,n,o=!1,t,d){const u=n===void 0?null:R(n),s=d!==void 0?d.grantId?w(d.grantId):I(e,d.sub):u?null:_(e);if(d!==void 0?!s&&!(d.grantId===null&&e==="app:terminal"):!u&&!s)throw new Error(`no active grant for ${e}`);return T({nodeId:n??"proc-cwd-check",app:e,...d!==void 0?{sub:d.sub,grantId:s?.id??null,scopes:d.scopes}:{sub:u?u.sub??"user:local":s.sub,grantId:u?u.grant_id??null:s.id,scopes:u?.scopes??null},command:["true"],env:{},...n===void 0?{withoutNode:!0}:{},...t===void 0?{}:{folder:t},isolated:u?.isolated===!0||o,auditMissing:i(()=>{},"auditMissing")}).mounts.some(({source:c})=>r===c||r.startsWith(c==="/"?"/":`${c}/`))}i(me,"cwdIsMounted");async function D(e,r="SIGKILL",n){if(!("ok"in await b({operation:"stop",pid:e,signal:r,...n===void 0?{}:{nodeId:n}})))throw new Error("launcher did not stop process")}i(D,"stopAppProcess");function W(e,r,n,o,t){return o?t??O(e,r):n}i(W,"appProcessCwd");async function pe(e){if(e.cron!==void 0&&(e.nodeId!==void 0||e.principal===void 0))throw new Error("a cron launch has a stored principal and no node");const r=e.nodeId===void 0?null:R(e.nodeId);if(e.nodeId!==void 0&&!r)throw new Error(`missing node ${e.nodeId}`);const n=r?.grantee??e.app??"app:terminal";if($(n),e.app!==void 0&&e.app!==n)throw new Error("app does not match node");const o=e.principal;let t=null;if(o!==void 0){if(t=o.grantId?w(o.grantId):I(n,o.sub),!(t===null&&o.grantId===null&&n==="app:terminal"&&!B("user").runtime?.issuer)&&(!t||t.grantee!==n||t.sub!==o.sub))throw new Error(`no active grant for ${n}`)}else if(r){if(n!=="app:terminal"&&!(r.grant_id?w(r.grant_id):I(n,r.sub??"user:local")))throw new Error(`no active grant for ${n}`)}else if(t=_(n),!t)throw new Error(`no active grant for ${n}`);await F(n);const d=e.cron===void 0?e.nodeId??`proc-${N()}`:U(e.cron.executionId),u=r?.isolated===!0||e.isolated===!0;if(u&&!r&&e.folder===void 0)throw new Error("isolated process requires a live node");const s=K(n),m=W(d,n,e.cwd,u,e.folder),c=r?k(d,n,u):u&&e.folder!==void 0?h(e.folder,"home"):s.home,L=j(Object.fromEntries(Object.entries({...e.env,...process.platform==="linux"?q(n):{},HOME:c,PI_CODING_AGENT_DIR:h(c,".pi","agent"),PWD:m,...e.nodeId===void 0&&e.cron===void 0?{}:{CRTR_API_SOCKET:h(H(d),"cli.sock")}}).filter(a=>a[1]!==void 0))),E=o!==void 0?{nodeId:d,app:n,sub:o.sub,grantId:t?.id??null,scopes:o.scopes}:{nodeId:d,app:n,sub:r?r.sub??"user:local":t.sub,grantId:r?r.grant_id??null:t.id,scopes:r?.scopes??null},P=i(()=>{const a=T({...E,command:e.command,env:L,...e.nodeId===void 0?{withoutNode:!0}:{},isolated:u,cwd:m,...e.folder===void 0?{}:{folder:e.folder},...e.cron===void 0?{}:{cron:e.cron.anchorDir===void 0?{}:{anchorDir:e.cron.anchorDir}},...e.pluginRoot===void 0?{}:{pluginRoot:e.pluginRoot},auditMissing:i(g=>G({level:"warn",event:"process.mount.missing",...e.nodeId===void 0?{}:{node_id:e.nodeId},fields:{source:g}}),"auditMissing")});if(e.pluginRoot!==void 0&&(a.pluginRoot=e.pluginRoot),e.capture===!1){if(e.nodeId===void 0||e.stdin!==void 0)throw new Error("uncaptured process requires a node and no stdin")}else a.capture={stdoutBytes:e.stdoutBytes??256*1024,stderrBytes:e.stderrBytes??256*1024,...e.stderrTail?{stderrTail:!0}:{},...e.stdin===void 0?{}:{stdin:e.stdin}};return a},"compile");let f;for(let a=0;a<2&&f===void 0;a++){const g=S(),x=P(),l=await b({operation:"launch",spec:x});if(!("pid"in l))throw new Error("launcher did not return a process id");if(S()===g||M(E,x)){f=l.pid;break}G({level:"info",event:"process.launch.regranted",...e.nodeId===void 0?{}:{node_id:e.nodeId},fields:{pid:l.pid}}),await D(l.pid,"SIGKILL").catch(()=>{})}if(f===void 0)throw new Error("grant changed during every launch attempt");const p=f;return{pid:p,get completion(){return b({operation:"wait",pid:p}).then(a=>{if(!("result"in a))throw new Error("launcher did not return process completion");return a.result})},stop:i((a="SIGKILL")=>D(p,a,e.cron===void 0?e.nodeId:d),"stop")}}i(pe,"launchAppProcess");export{le as __setAppProcessesSandboxedForTest,W as appProcessCwd,ce as appProcessSandboxed,fe as appProcessesSandboxed,U as cronLaunchId,me as cwdIsMounted,pe as launchAppProcess,D as stopAppProcess};
1
+ var C=Object.defineProperty;var u=(e,r)=>C(e,"name",{value:r,configurable:!0});import{existsSync as v}from"node:fs";import{assertGranteeRunsHere as $}from"../runtime/unsandboxed.js";import{randomUUID as N}from"node:crypto";import{join as g}from"node:path";import{getNode as R}from"../canvas/canvas.js";import{nodeAgentDir as O,nodeHome as k,nodeRunDir as H}from"../canvas/paths.js";import{appSpace as K}from"../layout.js";import{activeGrant as h,activeGrantForApp as _,grantFor as I,grantsGeneration as S}from"../grants/mirror.js";import{readConfig as B}from"../config.js";import{emitEvent as y}from"../events/emit.js";import{ensureAppSpace as F}from"./space.js";import{compileLaunch as G,launchStillGranted as M}from"./mounts.js";import{pinSandboxRuntimeHome as j}from"./runtime-home.js";import{sandboxCacheEnv as q}from"./cache-env.js";import{launcherRequest as b}from"../../launcher/client.js";import{LAUNCHER_SOCKET as T}from"../../launcher/spec.js";function U(e){return`cron-${e}`}u(U,"cronLaunchId");function ce(){if(process.platform!=="linux")return!1;if(v(T))return!0;throw new Error("root launcher socket is unavailable; refusing an unsandboxed app process")}u(ce,"appProcessSandboxed");function fe(){return A??(process.platform==="linux"&&v(T))}u(fe,"appProcessesSandboxed");let A;function le(e){A=e}u(le,"__setAppProcessesSandboxedForTest");async function me(e,r,n,o=!1,t,d){const a=n===void 0?null:await R(n),s=d!==void 0?d.grantId?await h(d.grantId):await I(e,d.sub):a?null:await _(e);if(d!==void 0?!s&&!(d.grantId===null&&e==="app:terminal"):!a&&!s)throw new Error(`no active grant for ${e}`);return(await G({nodeId:n??"proc-cwd-check",app:e,...d!==void 0?{sub:d.sub,grantId:s?.id??null,scopes:d.scopes}:{sub:a?a.sub??"user:local":s.sub,grantId:a?a.grant_id??null:s.id,scopes:a?.scopes??null},command:["true"],env:{},...n===void 0?{withoutNode:!0}:{},...t===void 0?{}:{folder:t},isolated:a?.isolated===!0||o,auditMissing:u(()=>{},"auditMissing")})).mounts.some(({source:c})=>r===c||r.startsWith(c==="/"?"/":`${c}/`))}u(me,"cwdIsMounted");async function D(e,r="SIGKILL",n){if(!("ok"in await b({operation:"stop",pid:e,signal:r,...n===void 0?{}:{nodeId:n}})))throw new Error("launcher did not stop process")}u(D,"stopAppProcess");function W(e,r,n,o,t){return o?t??O(e,r):n}u(W,"appProcessCwd");async function pe(e){if(e.cron!==void 0&&(e.nodeId!==void 0||e.principal===void 0))throw new Error("a cron launch has a stored principal and no node");const r=e.nodeId===void 0?null:await R(e.nodeId);if(e.nodeId!==void 0&&!r)throw new Error(`missing node ${e.nodeId}`);const n=r?.grantee??e.app??"app:terminal";if($(n),e.app!==void 0&&e.app!==n)throw new Error("app does not match node");const o=e.principal;let t=null;if(o!==void 0){if(t=o.grantId?await h(o.grantId):await I(n,o.sub),!(t===null&&o.grantId===null&&n==="app:terminal"&&!B("user").runtime?.issuer)&&(!t||t.grantee!==n||t.sub!==o.sub))throw new Error(`no active grant for ${n}`)}else if(r){if(n!=="app:terminal"&&!(r.grant_id?await h(r.grant_id):await I(n,r.sub??"user:local")))throw new Error(`no active grant for ${n}`)}else if(t=await _(n),!t)throw new Error(`no active grant for ${n}`);await F(n);const d=e.cron===void 0?e.nodeId??`proc-${N()}`:U(e.cron.executionId),a=r?.isolated===!0||e.isolated===!0;if(a&&!r&&e.folder===void 0)throw new Error("isolated process requires a live node");const s=K(n),m=W(d,n,e.cwd,a,e.folder),c=r?k(d,n,a):a&&e.folder!==void 0?g(e.folder,"home"):s.home,L=j(Object.fromEntries(Object.entries({...e.env,...process.platform==="linux"?q(n):{},HOME:c,PI_CODING_AGENT_DIR:g(c,".pi","agent"),PWD:m,...e.nodeId===void 0&&e.cron===void 0?{}:{CRTR_API_SOCKET:g(H(d),"cli.sock")}}).filter(i=>i[1]!==void 0))),E=o!==void 0?{nodeId:d,app:n,sub:o.sub,grantId:t?.id??null,scopes:o.scopes}:{nodeId:d,app:n,sub:r?r.sub??"user:local":t.sub,grantId:r?r.grant_id??null:t.id,scopes:r?.scopes??null},P=u(async()=>{const i=await G({...E,command:e.command,env:L,...e.nodeId===void 0?{withoutNode:!0}:{},isolated:a,cwd:m,...e.folder===void 0?{}:{folder:e.folder},...e.cron===void 0?{}:{cron:e.cron.anchorDir===void 0?{}:{anchorDir:e.cron.anchorDir}},...e.pluginRoot===void 0?{}:{pluginRoot:e.pluginRoot},auditMissing:u(w=>y({level:"warn",event:"process.mount.missing",...e.nodeId===void 0?{}:{node_id:e.nodeId},fields:{source:w}}),"auditMissing")});if(e.pluginRoot!==void 0&&(i.pluginRoot=e.pluginRoot),e.capture===!1){if(e.nodeId===void 0||e.stdin!==void 0)throw new Error("uncaptured process requires a node and no stdin")}else i.capture={stdoutBytes:e.stdoutBytes??256*1024,stderrBytes:e.stderrBytes??256*1024,...e.stderrTail?{stderrTail:!0}:{},...e.stdin===void 0?{}:{stdin:e.stdin}};return i},"compile");let f;for(let i=0;i<2&&f===void 0;i++){const w=await S(),x=await P(),l=await b({operation:"launch",spec:x});if(!("pid"in l))throw new Error("launcher did not return a process id");if(await S()===w||await M(E,x)){f=l.pid;break}y({level:"info",event:"process.launch.regranted",...e.nodeId===void 0?{}:{node_id:e.nodeId},fields:{pid:l.pid}}),await D(l.pid,"SIGKILL").catch(()=>{})}if(f===void 0)throw new Error("grant changed during every launch attempt");const p=f;return{pid:p,get completion(){return b({operation:"wait",pid:p}).then(i=>{if(!("result"in i))throw new Error("launcher did not return process completion");return i.result})},stop:u((i="SIGKILL")=>D(p,i,e.cron===void 0?e.nodeId:d),"stop")}}u(pe,"launchAppProcess");export{le as __setAppProcessesSandboxedForTest,W as appProcessCwd,ce as appProcessSandboxed,fe as appProcessesSandboxed,U as cronLaunchId,me as cwdIsMounted,pe as launchAppProcess,D as stopAppProcess};
@@ -1,2 +1,2 @@
1
1
  var f=Object.defineProperty;var n=(o,r)=>f(o,"name",{value:r,configurable:!0});import{chownSync as a,chmodSync as d,existsSync as l,mkdirSync as c,readFileSync as h,statSync as m}from"node:fs";import{appSpace as g,appsRoot as w,userFilesRoot as y}from"../layout.js";import{launcherRequest as S}from"../../launcher/client.js";import{LAUNCHER_SOCKET as x}from"../../launcher/spec.js";import{allocateAppUser as E,uidForApp as v}from"./users.js";function p(){const o=h("/etc/group","utf8").split(`
2
- `).find(e=>e.startsWith("crtr-data:"));if(!o)throw new Error("crtr-data group is required on sandboxed Linux");const r=Number(o.split(":")[2]);if(!Number.isInteger(r))throw new Error("invalid crtr-data group id");return r}n(p,"dataGroup");function L(){const o=y(),r=p();c(o,{recursive:!0,mode:1528});const e=m(o),t=e.mode&4095;if(!e.isDirectory()||e.gid!==r||t!==1528){if(!e.isDirectory()||e.uid!==process.getuid())throw new Error(`${o} has owner ${e.uid}, group ${e.gid}, mode ${t.toString(8).padStart(4,"0")}; requires an crtr-data (${r}) directory with mode 2770; only its owner can repair it`);e.gid!==r&&a(o,e.uid,r),t!==1528&&d(o,1528)}}n(L,"ensureUserFiles");async function N(o){const r=g(o);if(!(process.platform==="linux"&&l(x))){if(process.platform==="linux")throw new Error("app space requires the root launcher on Linux");for(const i of[r.root,r.profiles,r.conversations,r.nodes,r.files,r.home,r.cache])c(i,{recursive:!0});return{uid:v(o),gid:process.getgid(),root:r.root}}const t=p(),s=E(o),u=await S({operation:"user.create",app:r.root.slice(w().length+1),uid:s.uid});if(!("uid"in u)||u.uid!==s.uid)throw new Error(`launcher did not create OS user for ${o}`);for(const i of[r.root,r.profiles,r.conversations,r.nodes,r.files,r.home,r.cache])c(i,{recursive:!0,mode:1528}),a(i,process.getuid(),t),d(i,1528);return{uid:s.uid,gid:t,root:r.root}}n(N,"ensureAppSpace");export{N as ensureAppSpace,L as ensureUserFiles};
2
+ `).find(e=>e.startsWith("crtr-data:"));if(!o)throw new Error("crtr-data group is required on sandboxed Linux");const r=Number(o.split(":")[2]);if(!Number.isInteger(r))throw new Error("invalid crtr-data group id");return r}n(p,"dataGroup");function L(){const o=y(),r=p();c(o,{recursive:!0,mode:1528});const e=m(o),t=e.mode&4095;if(!e.isDirectory()||e.gid!==r||t!==1528){if(!e.isDirectory()||e.uid!==process.getuid())throw new Error(`${o} has owner ${e.uid}, group ${e.gid}, mode ${t.toString(8).padStart(4,"0")}; requires an crtr-data (${r}) directory with mode 2770; only its owner can repair it`);e.gid!==r&&a(o,e.uid,r),t!==1528&&d(o,1528)}}n(L,"ensureUserFiles");async function N(o){const r=g(o);if(!(process.platform==="linux"&&l(x))){if(process.platform==="linux")throw new Error("app space requires the root launcher on Linux");for(const i of[r.root,r.profiles,r.conversations,r.nodes,r.files,r.home,r.cache])c(i,{recursive:!0});return{uid:await v(o),gid:process.getgid(),root:r.root}}const t=p(),s=await E(o),u=await S({operation:"user.create",app:r.root.slice(w().length+1),uid:s.uid});if(!("uid"in u)||u.uid!==s.uid)throw new Error(`launcher did not create OS user for ${o}`);for(const i of[r.root,r.profiles,r.conversations,r.nodes,r.files,r.home,r.cache])c(i,{recursive:!0,mode:1528}),a(i,process.getuid(),t),d(i,1528);return{uid:s.uid,gid:t,root:r.root}}n(N,"ensureAppSpace");export{N as ensureAppSpace,L as ensureUserFiles};
@@ -1,9 +1,9 @@
1
- import type { DatabaseSync } from 'node:sqlite';
1
+ import { type CanvasDb } from '../canvas/db.js';
2
2
  import type { ObjectRow } from '../graph/types.js';
3
3
  import { type TeardownResult } from '../runtime/host.js';
4
4
  /** End the job object of a backgrounded command as killed. A command that was never backgrounded
5
5
  * has no job object; that answers false. Daemon-only: opens canvas.db. */
6
- export declare function killBashJobObject(jobId: string, killedBy: (db: DatabaseSync) => ObjectRow | null, reason?: string): boolean;
6
+ export declare function killBashJobObject(jobId: string, killedBy: (db: CanvasDb) => Promise<ObjectRow | null>, reason?: string): Promise<boolean>;
7
7
  /** Record a backgrounded command as its node's job object (id = job id); an existing job
8
8
  * object is returned as is. The one path for both the broker's record call and the
9
9
  * daemon adopting a job the broker backgrounded while exiting. Daemon-only. */
@@ -11,7 +11,7 @@ export declare function recordBashJobObject(nodeId: string, jobId: string, spec:
11
11
  command: string;
12
12
  jobDir: string;
13
13
  logPath: string;
14
- }): ObjectRow;
14
+ }): Promise<ObjectRow>;
15
15
  /** Stop the broker first so it cannot start another job during the job scan. */
16
16
  export declare function stopNodeSandboxes(nodeId: string, reason: string, options?: {
17
17
  excludePid?: number;
@@ -1,2 +1,2 @@
1
- var _=Object.defineProperty;var a=(e,t)=>_(e,"name",{value:t,configurable:!0});import{prepared as x}from"../sqlite-statements.js";import{randomUUID as y}from"node:crypto";import{activeBackgroundBashJobs as R,stopBackgroundBashJob as S}from"../bash-jobs.js";import{getNode as T}from"../canvas/index.js";import{openDb as D,withCanvasWrite as h}from"../canvas/db.js";import{finishJob as J,startJob as O}from"../graph/jobs.js";import{getById as w,nodeObject as M}from"../graph/objects.js";import{readLiveSession as N}from"../canvas/sessions.js";import{contextDir as W}from"../canvas/node-agent-paths.js";import{conversationStore as $}from"../conversation-store/index.js";import{requestBrokerTeardown as C}from"../runtime/host.js";import{holdRecovery as L}from"../runtime/recovery-hold.js";function P(e,t,o){return h(n=>{const r=w(n,e);return r===null||r.type!=="job"?!1:(J(n,r,{killedBy:t(n),...o===void 0?{}:{reason:o}}),!0)})}a(P,"killBashJobObject");function I(e,t,o){return h(n=>{const r=w(n,t);if(r!==null){if(r.type!=="job")throw new Error(`${t} names a ${r.type}`);return r}return O(n,M(n,e),{id:t,...o})})}a(I,"recordBashJobObject");const d=new Map;function ee(e,t,o={}){const n=d.get(e);if(n)return n;const r=T(e);if(!r)return Promise.resolve({confirmed:!1,error:new Error(`missing node ${e}`)});const m=N(e)?.sessionId,l=a(()=>x(D(),`SELECT type, body_json FROM run_events WHERE node_id = ?
2
- AND type IN ('node.turn.started', 'node.turn.completed') ORDER BY sequence_number DESC LIMIT 1`).get(e),"latestTurn"),v=r.run_id!==null&&r.pi_pid!==null&&l()?.type==="node.turn.started",E=o.holdRecovery?L(e):()=>{},j=C(e,{excludePid:o.excludePid}),c=(async()=>{const p=await j;if(!p.confirmed)return p;try{const s=W(e);for(const u of R(s,!0)){const i=await S(s,u.jobId,!0,e,t);if(i.kind==="not-stoppable")throw new Error(`background bash job ${u.jobId} could not be stopped`);i.kind!=="stopped"||o.deleting||P(u.jobId,()=>null,t)}if(v&&m&&!o.deleting){if(l()?.type!=="node.turn.started")return await o.after?.(),p;const i=$(),{entries:k}=i.read(m),B=k.at(-1),f=new Date().toISOString(),g=t==="permission_revoked",b={type:"message",id:y(),parentId:B?.id??null,timestamp:f,message:{role:"assistant",content:[],api:"openai-completions",provider:"crouter",model:"",usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:g?"error":"aborted",errorMessage:t,timestamp:Date.now()}};i.append(m,[b,{type:"custom",id:y(),parentId:b.id,timestamp:f,customType:"crtr-turn-end",data:g?{stop_reason:"error",error:{code:"model_error",message:t}}:{stop_reason:"aborted"}}])}return await o.after?.(),p}catch(s){return{confirmed:!1,error:s instanceof Error?s:new Error(String(s))}}})();return d.set(e,c),c.finally(()=>{E(),d.get(e)===c&&d.delete(e)}),c}a(ee,"stopNodeSandboxes");export{P as killBashJobObject,I as recordBashJobObject,ee as stopNodeSandboxes};
1
+ var _=Object.defineProperty;var s=(t,e)=>_(t,"name",{value:e,configurable:!0});import{randomUUID as g}from"node:crypto";import{activeBackgroundBashJobs as x,stopBackgroundBashJob as R}from"../bash-jobs.js";import{getNode as T}from"../canvas/index.js";import{withCanvasWrite as b,openDb as D}from"../canvas/db.js";import{finishJob as S,startJob as J}from"../graph/jobs.js";import{getById as h,nodeObject as O}from"../graph/objects.js";import{readLiveSession as M}from"../canvas/sessions.js";import{contextDir as N}from"../canvas/node-agent-paths.js";import{conversationStore as W}from"../conversation-store/index.js";import{requestBrokerTeardown as $}from"../runtime/host.js";import{holdRecovery as C}from"../runtime/recovery-hold.js";async function L(t,e,o){return await b(async n=>{const r=await h(n,t);return r===null||r.type!=="job"?!1:(await S(n,r,{killedBy:await e(n),...o===void 0?{}:{reason:o}}),!0)})}s(L,"killBashJobObject");async function X(t,e,o){return await b(async n=>{const r=await h(n,e);if(r!==null){if(r.type!=="job")throw new Error(`${e} names a ${r.type}`);return r}return await J(n,await O(n,t),{id:e,...o})})}s(X,"recordBashJobObject");const d=new Map;async function Z(t,e,o={}){const n=d.get(t);if(n)return n;const r=await T(t);if(!r)return Promise.resolve({confirmed:!1,error:new Error(`missing node ${t}`)});const l=(await M(t))?.sessionId,m=s(async()=>await(await D()).prepare(`SELECT type, body_json FROM run_events WHERE node_id = ?
2
+ AND type IN ('node.turn.started', 'node.turn.completed') ORDER BY sequence_number DESC LIMIT 1`).get(t),"latestTurn"),v=r.run_id!==null&&r.pi_pid!==null&&(await m())?.type==="node.turn.started",E=o.holdRecovery?C(t):()=>{},j=$(t,{excludePid:o.excludePid}),c=(async()=>{const u=await j;if(!u.confirmed)return u;try{const a=await N(t);for(const p of x(a,!0)){const i=await R(a,p.jobId,!0,t,e);if(i.kind==="not-stoppable")throw new Error(`background bash job ${p.jobId} could not be stopped`);i.kind!=="stopped"||o.deleting||await L(p.jobId,async()=>null,e)}if(v&&l&&!o.deleting){if((await m())?.type!=="node.turn.started")return await o.after?.(),u;const i=W(),{entries:k}=await i.read(l),B=k.at(-1),f=new Date().toISOString(),w=e==="permission_revoked",y={type:"message",id:g(),parentId:B?.id??null,timestamp:f,message:{role:"assistant",content:[],api:"openai-completions",provider:"crouter",model:"",usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:w?"error":"aborted",errorMessage:e,timestamp:Date.now()}};await i.append(l,[y,{type:"custom",id:g(),parentId:y.id,timestamp:f,customType:"crtr-turn-end",data:w?{stop_reason:"error",error:{code:"model_error",message:e}}:{stop_reason:"aborted"}}])}return await o.after?.(),u}catch(a){return{confirmed:!1,error:a instanceof Error?a:new Error(String(a))}}})();return d.set(t,c),c.finally(()=>{E(),d.get(t)===c&&d.delete(t)}),c}s(Z,"stopNodeSandboxes");export{L as killBashJobObject,X as recordBashJobObject,Z as stopNodeSandboxes};
@@ -5,15 +5,15 @@ export interface AppUser {
5
5
  status: 'active' | 'removed';
6
6
  }
7
7
  /** The launcher is absent on macOS; there is no app uid on that host. */
8
- export declare function uidForApp(app: string): number;
8
+ export declare function uidForApp(app: string): Promise<number>;
9
9
  /** An app has at most one active row. A removed app that reconnects gets a new
10
10
  * row above every uid ever allocated, so a uid is never reused. */
11
- export declare function allocateAppUser(app: string): AppUser;
12
- export declare function activeAppUsers(): Array<{
11
+ export declare function allocateAppUser(app: string): Promise<AppUser>;
12
+ export declare function activeAppUsers(): Promise<Array<{
13
13
  app: string;
14
14
  uid: number;
15
- }>;
15
+ }>>;
16
16
  /** The app's OS-user row not yet marked removed, if any. */
17
- export declare function activeAppUser(app: string): AppUser | null;
17
+ export declare function activeAppUser(app: string): Promise<AppUser | null>;
18
18
  /** The removal cascade's last write (runtime spec, "On removal"). */
19
- export declare function markAppUserRemoved(uid: number): void;
19
+ export declare function markAppUserRemoved(uid: number): Promise<void>;
@@ -1 +1 @@
1
- var E=Object.defineProperty;var r=(t,e)=>E(t,"name",{value:e,configurable:!0});import{prepared as p}from"../sqlite-statements.js";import{existsSync as d}from"node:fs";import{openDb as i,withCanvasWrite as n}from"../canvas/db.js";import{APP_UID_MAX as m,APP_UID_MIN as o,LAUNCHER_SOCKET as S}from"../../launcher/spec.js";function R(t){return process.platform!=="linux"||!d(S)?process.getuid?.()??0:A(t).uid}r(R,"uidForApp");function A(t){if(process.platform!=="linux")throw new Error("app OS users exist only on Linux");return n(e=>{const a=p(e,"SELECT app, uid, created, status FROM app_users WHERE app = ? AND status = 'active'").get(t);if(a)return a;const c=p(e,"SELECT MAX(uid) AS uid FROM app_users").get().uid,s=Math.max(o,(c??o-1)+1);if(s>m)throw new Error("app OS user range exhausted");const u=new Date().toISOString();return p(e,"INSERT INTO app_users (app, uid, created, status) VALUES (?, ?, ?, ?)").run(t,s,u,"active"),{app:t,uid:s,created:u,status:"active"}})}r(A,"allocateAppUser");function O(){return p(i(),"SELECT app, uid FROM app_users WHERE status = 'active'").all().map(e=>({app:e.app.startsWith("app:")?e.app.slice(4):e.app,uid:e.uid}))}r(O,"activeAppUsers");function D(t){return p(i(),"SELECT app, uid, created, status FROM app_users WHERE app = ? AND status = 'active'").get(t)??null}r(D,"activeAppUser");function T(t){n(e=>{p(e,"UPDATE app_users SET status = 'removed', removed_at = ? WHERE uid = ? AND status = 'active'").run(new Date().toISOString(),t)})}r(T,"markAppUserRemoved");export{D as activeAppUser,O as activeAppUsers,A as allocateAppUser,T as markAppUserRemoved,R as uidForApp};
1
+ var o=Object.defineProperty;var e=(t,a)=>o(t,"name",{value:a,configurable:!0});import{existsSync as c}from"node:fs";import{withCanvasWrite as E,openDb as p}from"../canvas/db.js";import{APP_UID_MAX as d,APP_UID_MIN as u,LAUNCHER_SOCKET as w}from"../../launcher/spec.js";async function l(t){return process.platform!=="linux"||!c(w)?process.getuid?.()??0:(await A(t)).uid}e(l,"uidForApp");async function A(t){if(process.platform!=="linux")throw new Error("app OS users exist only on Linux");return await E(async a=>{const s=await a.prepare("SELECT app, uid, created, status FROM app_users WHERE app = ? AND status = 'active'").get(t);if(s)return s;const n=(await a.prepare("SELECT MAX(uid) AS uid FROM app_users").get()).uid,r=Math.max(u,(n??u-1)+1);if(r>d)throw new Error("app OS user range exhausted");const i=new Date().toISOString();return await a.prepare("INSERT INTO app_users (app, uid, created, status) VALUES (?, ?, ?, ?)").run(t,r,i,"active"),{app:t,uid:r,created:i,status:"active"}})}e(A,"allocateAppUser");async function v(){return(await(await p()).prepare("SELECT app, uid FROM app_users WHERE status = 'active'").all()).map(a=>({app:a.app.startsWith("app:")?a.app.slice(4):a.app,uid:a.uid}))}e(v,"activeAppUsers");async function _(t){return await(await p()).prepare("SELECT app, uid, created, status FROM app_users WHERE app = ? AND status = 'active'").get(t)??null}e(_,"activeAppUser");async function R(t){await(await p()).prepare("UPDATE app_users SET status = 'removed', removed_at = ? WHERE uid = ? AND status = 'active'").run(new Date().toISOString(),t)}e(R,"markAppUserRemoved");export{_ as activeAppUser,v as activeAppUsers,A as allocateAppUser,R as markAppUserRemoved,l as uidForApp};
@@ -1,5 +1,5 @@
1
- import type { DatabaseSync } from 'node:sqlite';
2
1
  import { type StorageClient, type StorageConfig } from './client.js';
2
+ import type { CanvasDb } from '../canvas/db.js';
3
3
  /** The fetch step of one `run.start` or `run.message` is bounded to 110 s in
4
4
  * total (the hosting router waits 120 s for its headers). */
5
5
  export declare const ATTACHMENT_FETCH_BUDGET_MS = 110000;
@@ -24,7 +24,7 @@ export interface ResolveOptions {
24
24
  /** Re-check, inside the accepting write, that every used upload is still this
25
25
  * grantee's and not pending delete (the due-work tick or an app removal may
26
26
  * have released it while its bytes were fetched). */
27
- export declare function assertUploadsUsable(grantee: string, uses: readonly AttachmentUse[], db: DatabaseSync): void;
27
+ export declare function assertUploadsUsable(grantee: string, uses: readonly AttachmentUse[], db: CanvasDb): Promise<void>;
28
28
  /** Fetch every upload a storage URL in `text` names into
29
29
  * `appSpace(grantee).nodes/<rootId>/attachments/` and replace exactly each
30
30
  * URL's span with the file's absolute runtime path. Without configured
@@ -1 +1 @@
1
- var N=Object.defineProperty;var i=(e,n)=>N(e,"name",{value:n,configurable:!0});import{constants as Z,createWriteStream as j}from"node:fs";import{extname as q,join as E}from"node:path";import{Transform as G}from"node:stream";import{pipeline as X}from"node:stream/promises";import{appSpace as Y}from"../layout.js";import{RunError as v}from"../runs/operations.js";import{createFileBeneath as J,existsBeneath as z,openBeneath as K,removeTreeBeneath as O,setModeBeneath as P,unlinkBeneath as Q,withDirBeneath as V}from"../spaces/open-beneath.js";import{ensureAppSpace as ee}from"../spaces/space.js";import{storageClient as te,storageConfig as oe,StorageRefused as ne}from"./client.js";import{getUpload as k}from"./tables.js";const re=11e4,p=i((e,n)=>new v(400,"invalid_request",n,void 0,{url:e}),"refused"),R=i(e=>new v(503,"storage_unavailable",e,void 0,void 0,void 0,!0),"unavailable");function x(e,n){return/^[^\s<>"'`)\]]*/.exec(e.slice(n))[0].replace(/[.,;:!?]+$/,"")}i(x,"shownUrl");function ae(e,n,r,c,d){const l=`${n}/`,_=[];let h=0;for(let u=e.indexOf(l,h);u!==-1;u=e.indexOf(l,h)){const t=x(e,u),f=/^([A-Za-z0-9_-]+)\/([A-Za-z0-9_-]+)\//.exec(e.slice(u+l.length));if(!f)throw p(t,`storage URL ${t} does not name an upload`);if(f[1]!==r)throw p(t,`storage URL ${t} names another runtime`);const s=k(f[2],d);if(!s||s.grantee!==c)throw p(t,`storage URL ${t} names an unknown upload`);if(s.delete_pending_since)throw p(t,`storage URL ${t} names a deleted upload`);const $=u+l.length+f[0].length,m=encodeURIComponent(s.name);if(!e.startsWith(m,$))throw p(t,`storage URL ${t} does not match the upload's name`);_.push({start:u,end:$+m.length,upload:s}),h=$+m.length}return _}i(ae,"matchStorageUrls");function _e(e,n,r){for(const c of n){const d=k(c.upload_id,r);if(!d||d.grantee!==e||d.delete_pending_since)throw p(c.url,`storage URL ${c.url} names an upload deleted while it was fetched`)}}i(_e,"assertUploadsUsable");function se(e,n){if(n===1)return e;const r=q(e);return r&&r!==e?`${e.slice(0,-r.length)}-${n}${r}`:`${e}-${n}`}i(se,"candidate");async function $e(e,n,r,c={}){const d={text:r,uses:[],cleanup:i(()=>{},"cleanup")},l=(c.config??oe)();if(!l||!r.includes(`${l.base_url}/`))return d;const _=(c.client??te)(),h=ae(r,l.base_url,_.runtimeId,e);if(!h.length)return d;const u=await ee(e),t=Y(e).nodes,f=E(t,n),s=E(f,"attachments"),$={uid:process.getuid?.()??0,gid:u.gid},m=!z(t,f),I=!m&&!z(t,s),C=[];let D=!1;const M=i(()=>{if(!D){D=!0;for(const o of C)try{Q(t,o)}catch{}try{m?O(t,f):I&&O(t,s)}catch{}}},"cleanup"),U=AbortSignal.timeout(c.budgetMs??re),b=new Map;try{V(t,s,()=>{},!0);for(const{upload:o,start:B}of h){if(b.has(o.upload_id))continue;const g=x(r,B);let L;try{L=await _.fetchUpload(o.upload_id,U)}catch(a){throw a instanceof ne?p(g,a.status===409?`storage URL ${g} names an upload that was never finished`:`storage URL ${g} names an unknown upload`):U.aborted?R("attachments could not be fetched within 110 s"):a}let w="";for(let a=1;;a++){w=E(s,se(o.name,a));try{J(t,w,Buffer.alloc(0),432);break}catch(A){if(A.code!=="EEXIST")throw L.body.destroy(),A}}C.push(w);let T=0;const W=new G({transform(a,A,H){T+=a.length,H(null,a)}}),F=K(t,w,Z.O_WRONLY);try{await X(L.body,W,j("",{fd:F,autoClose:!0}),{signal:U})}catch(a){throw U.aborted?R("attachments could not be fetched within 110 s"):a instanceof v?a:R(`storage stopped sending ${o.name}: ${a instanceof Error?a.message:String(a)}`)}if(T!==o.size)throw R(`storage sent ${T} of ${o.size} bytes of ${o.name}`);P(t,w,432,$),b.set(o.upload_id,{path:w,url:g})}}catch(o){throw M(),o}let y="",S=0;for(const o of h)y+=r.slice(S,o.start)+b.get(o.upload.upload_id).path,S=o.end;return y+=r.slice(S),{text:y,uses:[...b].map(([o,{path:B,url:g}])=>({upload_id:o,path:B,url:g})),cleanup:M}}i($e,"resolveStorageUrls");export{re as ATTACHMENT_FETCH_BUDGET_MS,_e as assertUploadsUsable,$e as resolveStorageUrls};
1
+ var N=Object.defineProperty;var i=(e,o)=>N(e,"name",{value:o,configurable:!0});import{constants as Z,createWriteStream as j}from"node:fs";import{extname as q,join as E}from"node:path";import{Transform as G}from"node:stream";import{pipeline as X}from"node:stream/promises";import{appSpace as Y}from"../layout.js";import{RunError as v}from"../runs/operations.js";import{createFileBeneath as J,existsBeneath as z,openBeneath as K,removeTreeBeneath as O,setModeBeneath as P,unlinkBeneath as Q,withDirBeneath as V}from"../spaces/open-beneath.js";import{ensureAppSpace as ee}from"../spaces/space.js";import{storageClient as te,storageConfig as ne,StorageRefused as oe}from"./client.js";import{getUpload as k}from"./tables.js";const re=11e4,p=i((e,o)=>new v(400,"invalid_request",o,void 0,{url:e}),"refused"),y=i(e=>new v(503,"storage_unavailable",e,void 0,void 0,void 0,!0),"unavailable");function x(e,o){return/^[^\s<>"'`)\]]*/.exec(e.slice(o))[0].replace(/[.,;:!?]+$/,"")}i(x,"shownUrl");async function ae(e,o,r,c,d){const l=`${o}/`,_=[];let h=0;for(let u=e.indexOf(l,h);u!==-1;u=e.indexOf(l,h)){const t=x(e,u),f=/^([A-Za-z0-9_-]+)\/([A-Za-z0-9_-]+)\//.exec(e.slice(u+l.length));if(!f)throw p(t,`storage URL ${t} does not name an upload`);if(f[1]!==r)throw p(t,`storage URL ${t} names another runtime`);const s=await k(f[2],d);if(!s||s.grantee!==c)throw p(t,`storage URL ${t} names an unknown upload`);if(s.delete_pending_since)throw p(t,`storage URL ${t} names a deleted upload`);const $=u+l.length+f[0].length,m=encodeURIComponent(s.name);if(!e.startsWith(m,$))throw p(t,`storage URL ${t} does not match the upload's name`);_.push({start:u,end:$+m.length,upload:s}),h=$+m.length}return _}i(ae,"matchStorageUrls");async function _e(e,o,r){for(const c of o){const d=await k(c.upload_id,r);if(!d||d.grantee!==e||d.delete_pending_since)throw p(c.url,`storage URL ${c.url} names an upload deleted while it was fetched`)}}i(_e,"assertUploadsUsable");function se(e,o){if(o===1)return e;const r=q(e);return r&&r!==e?`${e.slice(0,-r.length)}-${o}${r}`:`${e}-${o}`}i(se,"candidate");async function $e(e,o,r,c={}){const d={text:r,uses:[],cleanup:i(()=>{},"cleanup")},l=(c.config??ne)();if(!l||!r.includes(`${l.base_url}/`))return d;const _=(c.client??te)(),h=await ae(r,l.base_url,_.runtimeId,e);if(!h.length)return d;const u=await ee(e),t=Y(e).nodes,f=E(t,o),s=E(f,"attachments"),$={uid:process.getuid?.()??0,gid:u.gid},m=!z(t,f),I=!m&&!z(t,s),C=[];let D=!1;const M=i(()=>{if(!D){D=!0;for(const n of C)try{Q(t,n)}catch{}try{m?O(t,f):I&&O(t,s)}catch{}}},"cleanup"),U=AbortSignal.timeout(c.budgetMs??re),b=new Map;try{V(t,s,()=>{},!0);for(const{upload:n,start:B}of h){if(b.has(n.upload_id))continue;const g=x(r,B);let L;try{L=await _.fetchUpload(n.upload_id,U)}catch(a){throw a instanceof oe?p(g,a.status===409?`storage URL ${g} names an upload that was never finished`:`storage URL ${g} names an unknown upload`):U.aborted?y("attachments could not be fetched within 110 s"):a}let w="";for(let a=1;;a++){w=E(s,se(n.name,a));try{J(t,w,Buffer.alloc(0),432);break}catch(A){if(A.code!=="EEXIST")throw L.body.destroy(),A}}C.push(w);let T=0;const W=new G({transform(a,A,H){T+=a.length,H(null,a)}}),F=K(t,w,Z.O_WRONLY);try{await X(L.body,W,j("",{fd:F,autoClose:!0}),{signal:U})}catch(a){throw U.aborted?y("attachments could not be fetched within 110 s"):a instanceof v?a:y(`storage stopped sending ${n.name}: ${a instanceof Error?a.message:String(a)}`)}if(T!==n.size)throw y(`storage sent ${T} of ${n.size} bytes of ${n.name}`);P(t,w,432,$),b.set(n.upload_id,{path:w,url:g})}}catch(n){throw M(),n}let R="",S=0;for(const n of h)R+=r.slice(S,n.start)+b.get(n.upload.upload_id).path,S=n.end;return R+=r.slice(S),{text:R,uses:[...b].map(([n,{path:B,url:g}])=>({upload_id:n,path:B,url:g})),cleanup:M}}i($e,"resolveStorageUrls");export{re as ATTACHMENT_FETCH_BUDGET_MS,_e as assertUploadsUsable,$e as resolveStorageUrls};
@@ -21,9 +21,9 @@ export declare function createShare(caller: FileCaller, input: {
21
21
  expires_at: string | null;
22
22
  }>;
23
23
  /** `share.list`: the shares `createdBy` created. */
24
- export declare function listOwnShares(createdBy: string): {
24
+ export declare function listOwnShares(createdBy: string): Promise<{
25
25
  shares: ShareView[];
26
- };
26
+ }>;
27
27
  /** `share.delete`: turn the share off, then delete its stored copy. A storage
28
28
  * failure leaves `object_deleted_at` unset for the due-work tick to retry. */
29
29
  export declare function deleteOwnShare(createdBy: string, shareId: string): Promise<{
@@ -1 +1 @@
1
- var g=Object.defineProperty;var n=(e,t)=>g(e,"name",{value:t,configurable:!0});import{closeSync as x,read as v}from"node:fs";import{promisify as O}from"node:util";import{basename as $,relative as u,sep as d}from"node:path";import{Readable as _}from"node:stream";import{appsRoot as m,appSpace as A}from"../layout.js";import{RunError as s}from"../runs/operations.js";import{scopeAllowed as k}from"../scopes.js";import{invalidStorageName as q,storageClient as w,UPLOAD_MAX_BYTES as D}from"./client.js";import{contentTypeFor as E,openCallerFile as C}from"./download.js";import{getShare as R,insertShare as T,listShares as B,markShareObjectDeleted as N,turnShareOff as F}from"./tables.js";const f="crtr:files:share";function y(e,t){const r=u(e,t);return r===""||r!==".."&&!r.startsWith(`..${d}`)&&!r.startsWith(d)}n(y,"contains");function M(e){if(y(m(),e)){const t=u(m(),e).split(d)[0];if(t)return`app:${t}`}return"user"}n(M,"spaceOf");const b=n(e=>new s(503,"storage_unavailable",e,void 0,void 0,void 0,!0),"unavailable"),P=O(v);async function*U(e,t){let r=0;for(;r<t;){const a=Buffer.allocUnsafe(Math.min(1048576,t-r)),{bytesRead:i}=await P(e,a,0,a.length,r);if(i===0)throw new Error("shared file shrank while it was being copied");r+=i,yield a.subarray(0,i)}}n(U,"chunks");async function W(e,t,r,a){const i=_.from(U(t,r));let c;try{c=await fetch(e,{method:"PUT",signal:AbortSignal.timeout(11e4),headers:{"Content-Type":a,"Content-Length":String(r)},body:_.toWeb(i),duplex:"half"})}catch(p){throw b(`storage could not be reached: ${p instanceof Error?p.message:String(p)}`)}finally{i.destroy()}if(await c.body?.cancel().catch(()=>{}),!c.ok)throw b(`storage answered ${c.status} to the share upload`)}n(W,"putBytes");async function Z(e,t){if(typeof t.path!="string"||!t.path)throw new s(400,"invalid_request","path is required","path");let r;if(t.expires_at!==void 0&&t.expires_at!==null){const i=typeof t.expires_at=="string"?Date.parse(t.expires_at):NaN;if(!Number.isFinite(i))throw new s(400,"invalid_request","expires_at must be an ISO 8601 time","expires_at");if(i<=Date.now())throw new s(400,"invalid_request","expires_at must be in the future","expires_at");r=new Date(i).toISOString()}const a=C(e,t.path);try{if(!k(e.resolved,f)&&!y(A(e.app).root,a.path))throw new s(403,"scope_missing",`missing scope ${f}: without it only files in the app's own space can be shared`,void 0,void 0,f);if(a.size>D)throw new s(400,"invalid_request","file exceeds 100 MiB","path");const i=$(a.path),c=q(i);if(c)throw new s(400,"invalid_request",`file name cannot be shared: ${c}`,"path");const p=E(a.path),h=w(),o=await h.createShare({name:i,media_type:p,size:a.size,...r?{expires_at:r}:{}});try{await W(o.upload_link,a.fd,a.size,p)}catch(S){throw await h.deleteShare(o.share_id).catch(()=>{}),S}const l=o.expires_at??r??null;return T({share_id:o.share_id,source_space:M(a.path),source_path:a.path,storage_key:`${h.runtimeId}/shares/${o.share_id}/${i}`,url:o.url,created_by:e.app,created_at:new Date().toISOString(),expires_at:l}),{share_id:o.share_id,url:o.url,expires_at:l}}finally{x(a.fd)}}n(Z,"createShare");function j(e){return{share_id:e.share_id,url:e.url,source_path:e.source_path,created_by:e.created_by,created_at:e.created_at,expires_at:e.expires_at,status:e.status}}n(j,"view");function ee(e){return{shares:B(e).map(j)}}n(ee,"listOwnShares");async function te(e,t){const r=R(t);if(!r||r.created_by!==e)throw new s(404,"not_found","share not found");if(F(t),!r.object_deleted_at)try{await w().deleteShare(t),N(t)}catch(a){if(!(a instanceof s&&a.code==="storage_unavailable"))throw a}return{share_id:t,status:"off"}}n(te,"deleteOwnShare");export{f as SHARE_SCOPE,Z as createShare,te as deleteOwnShare,ee as listOwnShares};
1
+ var g=Object.defineProperty;var n=(e,t)=>g(e,"name",{value:t,configurable:!0});import{closeSync as x,read as v}from"node:fs";import{promisify as O}from"node:util";import{basename as $,relative as u,sep as d}from"node:path";import{Readable as _}from"node:stream";import{appsRoot as m,appSpace as A}from"../layout.js";import{RunError as s}from"../runs/operations.js";import{scopeAllowed as k}from"../scopes.js";import{invalidStorageName as q,storageClient as w,UPLOAD_MAX_BYTES as D}from"./client.js";import{contentTypeFor as E,openCallerFile as C}from"./download.js";import{getShare as R,insertShare as T,listShares as B,markShareObjectDeleted as N,turnShareOff as F}from"./tables.js";const f="crtr:files:share";function y(e,t){const a=u(e,t);return a===""||a!==".."&&!a.startsWith(`..${d}`)&&!a.startsWith(d)}n(y,"contains");function M(e){if(y(m(),e)){const t=u(m(),e).split(d)[0];if(t)return`app:${t}`}return"user"}n(M,"spaceOf");const b=n(e=>new s(503,"storage_unavailable",e,void 0,void 0,void 0,!0),"unavailable"),P=O(v);async function*U(e,t){let a=0;for(;a<t;){const r=Buffer.allocUnsafe(Math.min(1048576,t-a)),{bytesRead:i}=await P(e,r,0,r.length,a);if(i===0)throw new Error("shared file shrank while it was being copied");a+=i,yield r.subarray(0,i)}}n(U,"chunks");async function W(e,t,a,r){const i=_.from(U(t,a));let c;try{c=await fetch(e,{method:"PUT",signal:AbortSignal.timeout(11e4),headers:{"Content-Type":r,"Content-Length":String(a)},body:_.toWeb(i),duplex:"half"})}catch(p){throw b(`storage could not be reached: ${p instanceof Error?p.message:String(p)}`)}finally{i.destroy()}if(await c.body?.cancel().catch(()=>{}),!c.ok)throw b(`storage answered ${c.status} to the share upload`)}n(W,"putBytes");async function Z(e,t){if(typeof t.path!="string"||!t.path)throw new s(400,"invalid_request","path is required","path");let a;if(t.expires_at!==void 0&&t.expires_at!==null){const i=typeof t.expires_at=="string"?Date.parse(t.expires_at):NaN;if(!Number.isFinite(i))throw new s(400,"invalid_request","expires_at must be an ISO 8601 time","expires_at");if(i<=Date.now())throw new s(400,"invalid_request","expires_at must be in the future","expires_at");a=new Date(i).toISOString()}const r=C(e,t.path);try{if(!k(e.resolved,f)&&!y(A(e.app).root,r.path))throw new s(403,"scope_missing",`missing scope ${f}: without it only files in the app's own space can be shared`,void 0,void 0,f);if(r.size>D)throw new s(400,"invalid_request","file exceeds 100 MiB","path");const i=$(r.path),c=q(i);if(c)throw new s(400,"invalid_request",`file name cannot be shared: ${c}`,"path");const p=E(r.path),h=w(),o=await h.createShare({name:i,media_type:p,size:r.size,...a?{expires_at:a}:{}});try{await W(o.upload_link,r.fd,r.size,p)}catch(S){throw await h.deleteShare(o.share_id).catch(()=>{}),S}const l=o.expires_at??a??null;return await T({share_id:o.share_id,source_space:M(r.path),source_path:r.path,storage_key:`${h.runtimeId}/shares/${o.share_id}/${i}`,url:o.url,created_by:e.app,created_at:new Date().toISOString(),expires_at:l}),{share_id:o.share_id,url:o.url,expires_at:l}}finally{x(r.fd)}}n(Z,"createShare");function j(e){return{share_id:e.share_id,url:e.url,source_path:e.source_path,created_by:e.created_by,created_at:e.created_at,expires_at:e.expires_at,status:e.status}}n(j,"view");async function ee(e){return{shares:(await B(e)).map(j)}}n(ee,"listOwnShares");async function te(e,t){const a=await R(t);if(!a||a.created_by!==e)throw new s(404,"not_found","share not found");if(await F(t),!a.object_deleted_at)try{await w().deleteShare(t),await N(t)}catch(r){if(!(r instanceof s&&r.code==="storage_unavailable"))throw r}return{share_id:t,status:"off"}}n(te,"deleteOwnShare");export{f as SHARE_SCOPE,Z as createShare,te as deleteOwnShare,ee as listOwnShares};
@@ -1,4 +1,4 @@
1
- import type { DatabaseSync } from 'node:sqlite';
1
+ import { type CanvasDb } from '../canvas/db.js';
2
2
  /** Row helpers for the v60 file-transfer tables. Each takes an optional handle
3
3
  * so a caller inside `withCanvasWrite` passes its transaction. */
4
4
  export interface UploadRow {
@@ -27,37 +27,37 @@ export interface ShareRow {
27
27
  status: 'on' | 'off';
28
28
  object_deleted_at: string | null;
29
29
  }
30
- export declare function insertUpload(row: Omit<UploadRow, 'delete_pending_since'>, db?: DatabaseSync): void;
31
- export declare function getUpload(uploadId: string, db?: DatabaseSync): UploadRow | null;
32
- export declare function deleteUploadRow(uploadId: string, db?: DatabaseSync): void;
30
+ export declare function insertUpload(row: Omit<UploadRow, 'delete_pending_since'>, db?: CanvasDb): Promise<void>;
31
+ export declare function getUpload(uploadId: string, db?: CanvasDb): Promise<UploadRow | null>;
32
+ export declare function deleteUploadRow(uploadId: string, db?: CanvasDb): Promise<void>;
33
33
  /** Uploads the runtime owes storage a delete for, oldest first. */
34
- export declare function pendingUploadDeletes(db?: DatabaseSync): UploadRow[];
34
+ export declare function pendingUploadDeletes(db?: CanvasDb): Promise<UploadRow[]>;
35
35
  /** Mark uploads for deletion (idempotent: keeps the first mark). */
36
- export declare function markUploadsDeletePending(uploadIds: readonly string[], db?: DatabaseSync, at?: string): void;
37
- export declare function insertUploadUses(uses: readonly UploadUseRow[], db?: DatabaseSync): void;
36
+ export declare function markUploadsDeletePending(uploadIds: readonly string[], db?: CanvasDb, at?: string): Promise<void>;
37
+ export declare function insertUploadUses(uses: readonly UploadUseRow[], db?: CanvasDb): Promise<void>;
38
38
  /** Remove one recorded use (a file result undone after it was recorded). */
39
- export declare function deleteUploadUse(use: UploadUseRow, db?: DatabaseSync): void;
39
+ export declare function deleteUploadUse(use: UploadUseRow, db?: CanvasDb): Promise<void>;
40
40
  /** Record the size storage actually holds for an upload created with `max_size`. */
41
- export declare function setUploadSize(uploadId: string, size: number, db?: DatabaseSync): void;
41
+ export declare function setUploadSize(uploadId: string, size: number, db?: CanvasDb): Promise<void>;
42
42
  /** The use recorded at `path`, if any. */
43
- export declare function uploadUseAt(path: string, db?: DatabaseSync): UploadUseRow | null;
43
+ export declare function uploadUseAt(path: string, db?: CanvasDb): Promise<UploadUseRow | null>;
44
44
  /** Delete a run's uses and mark each of its uploads that no other run uses for
45
45
  * deletion. Returns the upload ids newly owed a storage delete. */
46
- export declare function releaseRunUploads(runIds: readonly string[], db?: DatabaseSync): string[];
46
+ export declare function releaseRunUploads(runIds: readonly string[], db?: CanvasDb): Promise<string[]>;
47
47
  /** Uploads never used 24 h after creation (the tick marks them for deletion). */
48
- export declare function staleUnusedUploads(before: string, db?: DatabaseSync): string[];
49
- export declare function insertShare(row: Omit<ShareRow, 'status' | 'object_deleted_at'>, db?: DatabaseSync): void;
50
- export declare function getShare(shareId: string, db?: DatabaseSync): ShareRow | null;
48
+ export declare function staleUnusedUploads(before: string, db?: CanvasDb): Promise<string[]>;
49
+ export declare function insertShare(row: Omit<ShareRow, 'status' | 'object_deleted_at'>, db?: CanvasDb): Promise<void>;
50
+ export declare function getShare(shareId: string, db?: CanvasDb): Promise<ShareRow | null>;
51
51
  /** Shares `created_by` owns; `null` (the person) lists every share. */
52
- export declare function listShares(createdBy: string | null, db?: DatabaseSync): ShareRow[];
53
- export declare function turnShareOff(shareId: string, db?: DatabaseSync): void;
52
+ export declare function listShares(createdBy: string | null, db?: CanvasDb): Promise<ShareRow[]>;
53
+ export declare function turnShareOff(shareId: string, db?: CanvasDb): Promise<void>;
54
54
  /** Turn every share `created_by` owns off; returns their ids. */
55
- export declare function turnSharesOffFor(createdBy: string, db?: DatabaseSync): string[];
55
+ export declare function turnSharesOffFor(createdBy: string, db?: CanvasDb): Promise<string[]>;
56
56
  /** Shares `on` whose `expires_at` has passed turn `off`; returns their ids. */
57
- export declare function expireShares(at?: string, db?: DatabaseSync): string[];
57
+ export declare function expireShares(at?: string, db?: CanvasDb): Promise<string[]>;
58
58
  /** Shares `off` whose stored object storage has not confirmed deleted. */
59
- export declare function sharesOwingObjectDelete(db?: DatabaseSync): ShareRow[];
60
- export declare function markShareObjectDeleted(shareId: string, db?: DatabaseSync, at?: string): void;
59
+ export declare function sharesOwingObjectDelete(db?: CanvasDb): Promise<ShareRow[]>;
60
+ export declare function markShareObjectDeleted(shareId: string, db?: CanvasDb, at?: string): Promise<void>;
61
61
  /** Mark every upload `grantee` created for deletion (app removal); returns the
62
62
  * ids newly marked. */
63
- export declare function markGranteeUploadsDeletePending(grantee: string, db?: DatabaseSync, at?: string): string[];
63
+ export declare function markGranteeUploadsDeletePending(grantee: string, db?: CanvasDb, at?: string): Promise<string[]>;