@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
@@ -10,13 +10,13 @@ export declare const RUN_STREAM_IDLE_MS = 60000;
10
10
  export interface RunStreamOptions {
11
11
  idleMs?: number;
12
12
  idleCheckMs?: number;
13
- isRunning?: (runId: string) => boolean;
13
+ isRunning?: (runId: string) => Promise<boolean>;
14
14
  }
15
15
  export declare function streamRunEvents(req: IncomingMessage, res: ServerResponse, id: string, principal: AppPrincipal | RequestPrincipal, after: number, requestId: string, framing: 'sse' | 'ndjson', options?: RunStreamOptions): Promise<void>;
16
- export declare function createAppListener(config: NonNullable<ScopeConfig['runtime']>, grantsReady: () => boolean, syncGrants: GrantSync, listenerOptions?: {
16
+ export declare function createAppListener(config: NonNullable<ScopeConfig['runtime']>, grantsReady: () => Promise<boolean>, syncGrants: GrantSync, listenerOptions?: {
17
17
  deferHead?: DeferHeadOptions;
18
18
  stream?: RunStreamOptions;
19
- }): {
19
+ }): Promise<{
20
20
  ready: Promise<void>;
21
21
  close: () => Promise<void>;
22
- };
22
+ }>;
@@ -1,24 +1,24 @@
1
- var G=Object.defineProperty;var s=(e,r)=>G(e,"name",{value:r,configurable:!0});import{randomUUID as F}from"node:crypto";import{createServer as Y}from"node:http";import{Router as J}from"./router.js";import{toErrorBody as q}from"./map.js";import{objectRoutes as Q}from"./handlers/objects.js";import{customObjectRoutes as W}from"./handlers/custom-objects.js";import{docRoutes as K}from"./handlers/docs.js";import{OPERATIONS as Z}from"./operations.js";import{runtimeReadiness as ee}from"../readiness.js";import{errorCodes as L}from"../../api/error-codes.js";import{MINIMUM_RUNTIME_VERSION_HEADER as te,RUNTIME_VERSION_HEADER as ne,minimumRuntimeRefusal as re}from"../../api/runtime-version.js";import{CONTRACT_HEADER as ae,CONTRACT_LEVEL as U,REQUIRED_CONTRACT_HEADER as oe,contractRefusal as ie}from"../../api/contract.js";import{crtrVersion as j}from"../../shared/crtr-version.js";import{AppPrincipalResolver as se}from"./principal.js";import{isDaemonRoute as ue,runtimeOwner as de,servePeer as V}from"../peer/ingress.js";import{applySyncNotice as ce}from"./sync-notice.js";import{ownMachineId as le}from"../../core/peer/directory.js";import{handleRunOperation as fe,integer as me}from"./handlers/runs.js";import{llmCallerOf as pe,parseLlmRequest as he,runLlm as ye}from"../../core/llm/run.js";import{parseUsageMonth as we,usageFor as _e}from"../../core/usage/ledger.js";import{capFields as ge}from"./handlers/llm.js";import{CONTROL_BODY_MAX_BYTES as ve,MODEL_CONTEXT_BODY_MAX_BYTES as Re}from"../../core/llm/body-limits.js";import{RunError as l,runIsRunning as Oe}from"../../core/runs/operations.js";import{requireRun as x}from"./router.js";import{deferHead as Ee}from"./deferred-head.js";import{readRunEvents as X,registerGrantStream as be,subscribeRunEvents as Se}from"../../core/runs/events.js";import{activeGrant as $,payerOfGrant as Te}from"../../core/grants/mirror.js";function Ae(e){if(Te(e)==="app")throw new l(401,"grant_revoked","this app-paid grant is no longer active");return null}s(Ae,"appPaidGone");import{releaseGrantWaiters as Ne}from"../../core/grants/watch.js";import{runNotices as Ce}from"../run-notices.js";import{handleVendorSignIn as Pe,isVendorSignInPath as Ie}from"./vendor-signin.js";import{listAppProfiles as ke}from"./handlers/app-profiles.js";import{handleTransferDownload as He,handleTransferOperation as Me,TRANSFER_OPERATIONS as De}from"./handlers/transfer.js";import{handleQuestionOperation as je,QUESTION_OPERATIONS as xe}from"./handlers/questions.js";import{vendorStatus as Be}from"./handlers/vendor-status.js";import{handleMemoryOperation as Je,MEMORY_OPERATIONS as Le}from"./handlers/memory.js";import{abortOnClose as Ue,callerFromApp as Ve,handleProviderOperation as Xe,PROVIDER_OPERATIONS as $e,providerFailure as ze}from"./handlers/providers.js";function Ge(e){return Object.prototype.hasOwnProperty.call(L,e)?L[e]:void 0}s(Ge,"fixedRow");function Fe(e){const r=Ge(e);return r?r.type:e==="stream_gap"||e==="provider_error"||e==="runtime_version_unsupported"?"invalid_request_error":"server_error"}s(Fe,"errorType");function Ye(e){if(!e||typeof e!="object"||Array.isArray(e)||!("rate_limit"in e))return e;const{rate_limit:r,...o}=e;return o}s(Ye,"appDetails");function D(e,r,o){const f=Ye(e.details);return{error:{code:e.code,message:e.message,...f===void 0?{}:{details:f},type:Fe(e.code),...e.param?{param:e.param}:{},origin:"runtime",retryable:e.retryable||e.code==="stream_dropped",request_id:r,...o?{run_id:o}:{},...e.scope?{scope:e.scope}:{},...e.code==="unauthorized"?{user_action:"reconnect"}:{},...ge(e),...e.code==="all_routes_exhausted"?{retry_after_s:e.details.retry_after_s}:{}}}}s(D,"envelope");function qe(e,r,o,f){const u=r instanceof l?r:new l(500,"server_failure","runtime request failed");if(r instanceof l||console.error("[app-listener]",r),e.headersSent&&!String(e.getHeader("Content-Type")??"").startsWith("text/event-stream")){e.destroy();return}if(e.headersSent){e.end(`event: error
2
- data: ${JSON.stringify(D(u,o,f))}
1
+ var F=Object.defineProperty;var i=(e,r)=>F(e,"name",{value:r,configurable:!0});import{randomUUID as Y}from"node:crypto";import{createServer as q}from"node:http";import{Router as L}from"./router.js";import{toErrorBody as Q}from"./map.js";import{objectRoutes as W}from"./handlers/objects.js";import{customObjectRoutes as K}from"./handlers/custom-objects.js";import{docRoutes as Z}from"./handlers/docs.js";import{OPERATIONS as ee}from"./operations.js";import{runtimeReadiness as te}from"../readiness.js";import{errorCodes as U}from"../../api/error-codes.js";import{MINIMUM_RUNTIME_VERSION_HEADER as ne,RUNTIME_VERSION_HEADER as re,minimumRuntimeRefusal as ae}from"../../api/runtime-version.js";import{CONTRACT_HEADER as oe,CONTRACT_LEVEL as V,REQUIRED_CONTRACT_HEADER as ie,contractRefusal as se}from"../../api/contract.js";import{crtrVersion as j}from"../../shared/crtr-version.js";import{AppPrincipalResolver as ue}from"./principal.js";import{isDaemonRoute as de,runtimeOwner as ce,servePeer as X}from"../peer/ingress.js";import{applySyncNotice as le}from"./sync-notice.js";import{ownMachineId as fe}from"../../core/peer/directory.js";import{handleRunOperation as me,integer as pe}from"./handlers/runs.js";import{llmCallerOf as he,parseLlmRequest as we,runLlm as ye}from"../../core/llm/run.js";import{parseUsageMonth as _e,usageFor as ve}from"../../core/usage/ledger.js";import{capFields as ge}from"./handlers/llm.js";import{CONTROL_BODY_MAX_BYTES as Re,MODEL_CONTEXT_BODY_MAX_BYTES as Oe}from"../../core/llm/body-limits.js";import{RunError as f,runIsRunning as Ee}from"../../core/runs/operations.js";import{requireRun as x}from"./router.js";import{deferHead as be}from"./deferred-head.js";import{readRunEvents as $,registerGrantStream as Se,subscribeRunEvents as Te}from"../../core/runs/events.js";import{activeGrant as z,payerOfGrant as Ae}from"../../core/grants/mirror.js";async function Ne(e){if(await Ae(e)==="app")throw new f(401,"grant_revoked","this app-paid grant is no longer active");return null}i(Ne,"appPaidGone");import{releaseGrantWaiters as Ce}from"../../core/grants/watch.js";import{emitEvent as Ie}from"../../core/events/emit.js";import{runNotices as Pe}from"../run-notices.js";import{handleVendorSignIn as ke,isVendorSignInPath as He}from"./vendor-signin.js";import{listAppProfiles as Me}from"./handlers/app-profiles.js";import{handleTransferDownload as De,handleTransferOperation as je,TRANSFER_OPERATIONS as xe}from"./handlers/transfer.js";import{handleQuestionOperation as Be,QUESTION_OPERATIONS as Je}from"./handlers/questions.js";import{vendorStatus as Le}from"./handlers/vendor-status.js";import{handleMemoryOperation as Ue,MEMORY_OPERATIONS as Ve}from"./handlers/memory.js";import{abortOnClose as Xe,callerFromApp as $e,handleProviderOperation as ze,PROVIDER_OPERATIONS as Ge,providerFailure as Fe}from"./handlers/providers.js";function Ye(e){return Object.prototype.hasOwnProperty.call(U,e)?U[e]:void 0}i(Ye,"fixedRow");function qe(e){const r=Ye(e);return r?r.type:e==="stream_gap"||e==="provider_error"||e==="runtime_version_unsupported"?"invalid_request_error":"server_error"}i(qe,"errorType");function Qe(e){if(!e||typeof e!="object"||Array.isArray(e)||!("rate_limit"in e))return e;const{rate_limit:r,...o}=e;return o}i(Qe,"appDetails");function D(e,r,o){const m=Qe(e.details);return{error:{code:e.code,message:e.message,...m===void 0?{}:{details:m},type:qe(e.code),...e.param?{param:e.param}:{},origin:"runtime",retryable:e.retryable||e.code==="stream_dropped",request_id:r,...o?{run_id:o}:{},...e.scope?{scope:e.scope}:{},...e.code==="unauthorized"?{user_action:"reconnect"}:{},...ge(e),...e.code==="all_routes_exhausted"?{retry_after_s:e.details.retry_after_s}:{}}}}i(D,"envelope");function We(e,r,o,m){const u=r instanceof f?r:new f(500,"server_failure","runtime request failed");if(r instanceof f||console.error("[app-listener]",r),e.headersSent&&!String(e.getHeader("Content-Type")??"").startsWith("text/event-stream")){e.destroy();return}if(e.headersSent){e.end(`event: error
2
+ data: ${JSON.stringify(D(u,o,m))}
3
3
 
4
- `);return}e.writeHead(u.status,{"Content-Type":"application/json; charset=utf-8","Request-Id":o,"X-Content-Type-Options":"nosniff",...u.code==="all_routes_exhausted"?{"Retry-After":String(u.details.retry_after_s)}:{}}),e.end(JSON.stringify(D(u,o,f)))}s(qe,"fail");function z(e){return Array.isArray(e)?e[0]:e}s(z,"headerValue");function O(e,r,o){e.writeHead(r,{"Content-Type":"application/json; charset=utf-8"}),e.end(JSON.stringify(o))}s(O,"json");async function P(e,r=ve){const o=[];let f=0;for await(const u of e){if(f+=u.length,f>r)throw new l(400,"invalid_request","request body too large");o.push(u)}if(f)try{return JSON.parse(Buffer.concat(o).toString("utf8"))}catch{throw new l(400,"invalid_request","invalid JSON body")}}s(P,"bodyOf");function Qe(e,r){const o=e.headers["last-event-id"]??r.get("after");if(Array.isArray(o))throw new l(400,"invalid_request","invalid cursor","after");return me(o??null,"after",0,Number.MAX_SAFE_INTEGER,0)}s(Qe,"cursor");function We(e){return`id: ${e.sequence_number}
4
+ `);return}e.writeHead(u.status,{"Content-Type":"application/json; charset=utf-8","Request-Id":o,"X-Content-Type-Options":"nosniff",...u.code==="all_routes_exhausted"?{"Retry-After":String(u.details.retry_after_s)}:{}}),e.end(JSON.stringify(D(u,o,m)))}i(We,"fail");function G(e){return Array.isArray(e)?e[0]:e}i(G,"headerValue");function O(e,r,o){e.writeHead(r,{"Content-Type":"application/json; charset=utf-8"}),e.end(JSON.stringify(o))}i(O,"json");async function I(e,r=Re){const o=[];let m=0;for await(const u of e){if(m+=u.length,m>r)throw new f(400,"invalid_request","request body too large");o.push(u)}if(m)try{return JSON.parse(Buffer.concat(o).toString("utf8"))}catch{throw new f(400,"invalid_request","invalid JSON body")}}i(I,"bodyOf");function Ke(e,r){const o=e.headers["last-event-id"]??r.get("after");if(Array.isArray(o))throw new f(400,"invalid_request","invalid cursor","after");return pe(o??null,"after",0,Number.MAX_SAFE_INTEGER,0)}i(Ke,"cursor");function Ze(e){return`id: ${e.sequence_number}
5
5
  event: ${e.type}
6
6
  data: ${JSON.stringify(e)}
7
7
 
8
- `}s(We,"frame");const Ke=6e4;function Ze(e,r,o,f,u,y,E,A={}){x(f,o);let g=X(o,u);if(u>g.latest_sequence)throw new l(400,"invalid_request","cursor is beyond the run","after");if(u<g.latest_sequence&&(g.earliest_sequence===null||u<g.earliest_sequence-1))throw new l(409,"stream_gap","events have expired",void 0,{earliest_sequence:g.earliest_sequence,latest_sequence:g.latest_sequence});if(r.destroyed||e.destroyed)return r.destroy(),Promise.resolve();r.writeHead(200,{"Content-Type":E==="sse"?"text/event-stream":"application/x-ndjson","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),E==="sse"?r.write(`: connected
8
+ `}i(Ze,"frame");const et=6e4;async function tt(e,r,o,m,u,w,b,N={}){await x(m,o);let v=await $(o,u);if(u>v.latest_sequence)throw new f(400,"invalid_request","cursor is beyond the run","after");if(u<v.latest_sequence&&(v.earliest_sequence===null||u<v.earliest_sequence-1))throw new f(409,"stream_gap","events have expired",void 0,{earliest_sequence:v.earliest_sequence,latest_sequence:v.latest_sequence});if(r.destroyed||e.destroyed)return r.destroy(),Promise.resolve();r.writeHead(200,{"Content-Type":b==="sse"?"text/event-stream":"application/x-ndjson","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),b==="sse"?r.write(`: connected
9
9
 
10
- `):r.flushHeaders();let w=u;const B=Ce().streamOpened(o);let n=!1,t=!1,h=!1,b;const N=new Promise(m=>{b=m}),_=s(()=>{n||(n=!0,B(w),clearInterval(d),clearInterval(R),I(),H(),r.off("close",_),r.off("drain",p),r.end(),b())},"end"),p=s(()=>{h=!1,a()},"onDrain"),v=s(m=>{n||r.write(E==="sse"?`event: error
11
- data: ${JSON.stringify(D(m,y,o))}
10
+ `):r.flushHeaders();let y=u;const B=await Pe().streamOpened(o);let n=!1,t=!1,h=!1,S;const C=new Promise(d=>{S=d}),_=i(()=>{n||(n=!0,B(y).catch(d=>console.error("[app-listener]",d)),clearInterval(c),clearInterval(A),P(),H(),r.off("close",_),r.off("drain",p),r.end(),S())},"end"),p=i(()=>{h=!1,a()},"onDrain"),R=i(d=>{n||r.write(b==="sse"?`event: error
11
+ data: ${JSON.stringify(D(d,w,o))}
12
12
 
13
- `:`${JSON.stringify({type:"error",...D(m,y,o)})}
14
- `),_()},"error"),a=s(()=>{if(!(n||t)){t=!0;try{if(!T()){k();return}if(x(f,o),g=X(o,w),g.backlog_count>1e3||g.backlog_bytes>32*1024*1024){v(new l(503,"stream_dropped","stream reader fell behind",void 0,{last_sequence:w}));return}for(const m of g.events){if(h)break;h=!r.write(E==="sse"?We(m):`${JSON.stringify(m)}
15
- `),w=m.sequence_number}}catch(m){v(m instanceof l?m:new l(500,"server_failure","stream failed"))}finally{t=!1}}},"flush"),k=s(()=>v(new l(401,"grant_revoked","grant is not active")),"revoked"),T=s(()=>"class"in f||$(f.grant)!==null,"grantActive"),I=Se(o,a),H="class"in f?()=>{}:be(f.grant,k),d=setInterval(()=>{!n&&!h&&E==="sse"&&r.write(`: keepalive
13
+ `:`${JSON.stringify({type:"error",...D(d,w,o)})}
14
+ `),_()},"error"),a=i(async()=>{if(!(n||t)){t=!0;try{if(!await T()){k();return}if(await x(m,o),v=await $(o,y),v.backlog_count>1e3||v.backlog_bytes>32*1024*1024){R(new f(503,"stream_dropped","stream reader fell behind",void 0,{last_sequence:y}));return}for(const d of v.events){if(h)break;h=!r.write(b==="sse"?Ze(d):`${JSON.stringify(d)}
15
+ `),y=d.sequence_number}}catch(d){R(d instanceof f?d:new f(500,"server_failure","stream failed"))}finally{t=!1}}},"flush"),k=i(()=>R(new f(401,"grant_revoked","grant is not active")),"revoked"),T=i(async()=>"class"in m||await z(m.grant)!==null,"grantActive"),P=await Te(o,a),H="class"in m?()=>{}:Se(m.grant,k),c=setInterval(()=>{!n&&!h&&b==="sse"&&r.write(`: keepalive
16
16
 
17
- `)},15e3),M=A.idleMs??Ke,i=A.isRunning??Oe;let S=Date.now(),c=w;const R=setInterval(()=>{if(n||E!=="sse")return;const m=Date.now();let C=!0;try{C=i(o)}catch{}if(C||w!==c){S=m,c=w;return}m-S<M||h||(r.write(`event: idle
17
+ `)},15e3),M=N.idleMs??et,s=N.isRunning??Ee;let g=Date.now(),l=y;const E=i(async()=>{if(n||b!=="sse")return;const d=Date.now();let J=!0;try{J=await s(o)}catch{}if(!n){if(J||y!==l){g=d,l=y;return}d-g<M||h||(r.write(`event: idle
18
18
  data: {}
19
19
 
20
- `),_())},A.idleCheckMs??1e3);return R.unref(),r.on("drain",p),r.on("close",_),a(),N}s(Ze,"streamRunEvents");function xt(e,r,o,f={}){const u=e.listener;if(!e.issuer||!e.audience||!u?.address||!Number.isInteger(u.port)||u.port<1||u.port>65535)throw new Error("runtime issuer, audience and listener address/port are required");if(["0.0.0.0","::","[::]"].includes(u.address))throw new Error("runtime listener must bind a specific address");const y=new se(e.issuer,e.audience,o,e.jwksUrl),E=new J,A=new Map;for(const n of Z.filter(t=>t.stage!==void 0)){const t=s(()=>({status:500}),"handler");E.register({method:n.method,pattern:n.path,handler:t}),A.set(t,n)}const g=new J().registerAll(Q).registerAll(W).registerAll(K),w=Y((n,t)=>{(async()=>{Ee(n,t,f.deferHead);const h=F();t.setHeader("Request-Id",h),t.setHeader(ne,j()),t.setHeader(ae,U);let b;try{const N=z(n.headers[te.toLowerCase()]),_=re(N,j())??ie(z(n.headers[oe.toLowerCase()]),U,{legacyMinimum:N,runtimeVersion:j()});if(_!==null)throw _.status===400?new l(400,_.code,_.message,_.param):new l(426,_.code,_.message,void 0,_.details);const p=new URL(n.url??"/","http://runtime.local");if(Ie(p.pathname)){await Pe(n,t,p,y);return}const v=E.match(n.method??"GET",p.pathname),a=v?A.get(v.handler):void 0,k=a?.name==="runtime.sync-notice"||a?.name==="runtime.vendor-status";let T,I;if(!k&&n.headers.authorization!==void 0)try{T=await y.verifyCall(n.headers.authorization)}catch(i){I=i}const H={issuer:e.issuer,jwks:y.jwks,audience:s(()=>e.audience,"audience"),owner:de,self:le,syncGrants:o,ready:s(()=>y.isReady()&&r(),"ready")};if(T?.chain[0]?.sub.startsWith("runtime:")){await V(n,t,H,T);return}if(T===void 0&&a===void 0&&await ue(n.method??"GET",p.pathname)){await V(n,t,H,{status:401,code:"unauthorized",message:I===void 0?"a machine token is required":"invalid machine token"});return}if(a?.name==="ready"){const i=ee({jwksReady:y.isReady(),grantsReady:r});O(t,i.ready?200:503,i);return}if((n.method!=="GET"||p.pathname!=="/v1/health")&&(!y.isReady()||!r()))throw new l(503,"runtime_starting","runtime_starting");if(!v||!a)throw new l(404,"not_found","unknown operation");if(b=v.params.run_id,a.name==="health"){O(t,200,{status:"ok",api_version:"2026-09-23"});return}if(a.name==="runtime.sync-notice"){await ce(await y.verifySyncNotice(n.headers.authorization),o,h),t.writeHead(204),t.end();return}if(a.name==="runtime.vendor-status"){await y.verifyDirectoryRead(n.headers.authorization,"vendor_status"),O(t,200,Be());return}if(T===void 0)throw I??new l(401,"unauthorized","a directory access token is required");const d=await y.resolveVerified(T,a.scope);if(t.setHeader("Request-Id",h),b&&x(d,b,["run.message","run.interrupt","run.cancel","run.rename","run.delete"].includes(a.name),a.name==="run.delete"),a.stage==="objects"){const i=g.match(a.method,p.pathname);if(!i)throw new l(404,"not_found","unknown operation");const S={method:a.method,path:p.pathname,params:i.params,query:p.searchParams,body:await P(n,i.maxBodyBytes),ceiling:d.resolved,principal:{class:"app",app:d.grantee,scopes:d.resolved},req:n,res:t};let c;try{c=await i.handler(S)}catch(R){const{status:m,body:C}=q(R);throw m>=500&&console.error("[app-listener]",R),new l(m,C.error.code,C.error.message,void 0,C.error.details)}if(t.headersSent)return;if(c.rawBody!==void 0||c.status===204||c.body===void 0){t.writeHead(c.status,c.headers??{}),t.end(c.rawBody);return}t.writeHead(c.status,{"Content-Type":"application/json; charset=utf-8",...c.headers??{}}),t.end(JSON.stringify(c.body));return}if(a.stream==="bytes"){await He(n,t,d,p.searchParams);return}if(a.stream){Ze(n,t,b,d,Qe(n,p.searchParams),h,"sse",f.stream);return}if(a.name==="llm"){const i=he(await P(n,Re)),S=new AbortController,c=s(()=>S.abort(),"abort");t.on("close",c);try{const R=await ye(i,S.signal,i.stream?m=>{t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.write(`data: ${JSON.stringify(m)}
20
+ `),_())}},"checkIdle"),A=setInterval(()=>{E().catch(d=>Ie({level:"error",event:"api.run_stream.idle_check_failed",error:d}))},N.idleCheckMs??1e3);return A.unref(),r.on("drain",p),r.on("close",_),await a(),C}i(tt,"streamRunEvents");async function Lt(e,r,o,m={}){const u=e.listener;if(!e.issuer||!e.audience||!u?.address||!Number.isInteger(u.port)||u.port<1||u.port>65535)throw new Error("runtime issuer, audience and listener address/port are required");if(["0.0.0.0","::","[::]"].includes(u.address))throw new Error("runtime listener must bind a specific address");const w=new ue(e.issuer,e.audience,o,e.jwksUrl),b=new L,N=new Map;for(const n of ee.filter(t=>t.stage!==void 0)){const t=i(()=>({status:500}),"handler");b.register({method:n.method,pattern:n.path,handler:t}),N.set(t,n)}const v=new L().registerAll(W).registerAll(K).registerAll(Z),y=q((n,t)=>{(async()=>{be(n,t,m.deferHead);const h=Y();t.setHeader("Request-Id",h),t.setHeader(re,j()),t.setHeader(oe,V);let S;try{const C=G(n.headers[ne.toLowerCase()]),_=ae(C,j())??se(G(n.headers[ie.toLowerCase()]),V,{legacyMinimum:C,runtimeVersion:j()});if(_!==null)throw _.status===400?new f(400,_.code,_.message,_.param):new f(426,_.code,_.message,void 0,_.details);const p=new URL(n.url??"/","http://runtime.local");if(He(p.pathname)){await ke(n,t,p,w);return}const R=b.match(n.method??"GET",p.pathname),a=R?N.get(R.handler):void 0,k=a?.name==="runtime.sync-notice"||a?.name==="runtime.vendor-status";let T,P;if(!k&&n.headers.authorization!==void 0)try{T=await w.verifyCall(n.headers.authorization)}catch(s){P=s}const H={issuer:e.issuer,jwks:w.jwks,audience:i(async()=>e.audience,"audience"),owner:ce,self:fe,syncGrants:o,ready:i(async()=>w.isReady()&&await r(),"ready")};if(T?.chain[0]?.sub.startsWith("runtime:")){await X(n,t,H,T);return}if(T===void 0&&a===void 0&&await de(n.method??"GET",p.pathname)){await X(n,t,H,{status:401,code:"unauthorized",message:P===void 0?"a machine token is required":"invalid machine token"});return}if(a?.name==="ready"){const s=await r(),g=await te({jwksReady:w.isReady(),grantsReady:i(()=>s,"grantsReady")});O(t,g.ready?200:503,g);return}if((n.method!=="GET"||p.pathname!=="/v1/health")&&(!w.isReady()||!await r()))throw new f(503,"runtime_starting","runtime_starting");if(!R||!a)throw new f(404,"not_found","unknown operation");if(S=R.params.run_id,a.name==="health"){O(t,200,{status:"ok",api_version:"2026-09-23"});return}if(a.name==="runtime.sync-notice"){await le(await w.verifySyncNotice(n.headers.authorization),o,h),t.writeHead(204),t.end();return}if(a.name==="runtime.vendor-status"){await w.verifyDirectoryRead(n.headers.authorization,"vendor_status"),O(t,200,Le());return}if(T===void 0)throw P??new f(401,"unauthorized","a directory access token is required");const c=await w.resolveVerified(T,a.scope);if(t.setHeader("Request-Id",h),S&&await x(c,S,["run.message","run.interrupt","run.cancel","run.rename","run.delete"].includes(a.name),a.name==="run.delete"),a.stage==="objects"){const s=v.match(a.method,p.pathname);if(!s)throw new f(404,"not_found","unknown operation");const g={method:a.method,path:p.pathname,params:s.params,query:p.searchParams,body:await I(n,s.maxBodyBytes),ceiling:c.resolved,principal:{class:"app",app:c.grantee,scopes:c.resolved},req:n,res:t};let l;try{l=await s.handler(g)}catch(E){const{status:A,body:d}=Q(E);throw A>=500&&console.error("[app-listener]",E),new f(A,d.error.code,d.error.message,void 0,d.error.details)}if(t.headersSent)return;if(l.rawBody!==void 0||l.status===204||l.body===void 0){t.writeHead(l.status,l.headers??{}),t.end(l.rawBody);return}t.writeHead(l.status,{"Content-Type":"application/json; charset=utf-8",...l.headers??{}}),t.end(JSON.stringify(l.body));return}if(a.stream==="bytes"){await De(n,t,c,p.searchParams);return}if(a.stream){await tt(n,t,S,c,Ke(n,p.searchParams),h,"sse",m.stream);return}if(a.name==="llm"){const s=we(await I(n,Oe)),g=new AbortController,l=i(()=>g.abort(),"abort");t.on("close",l);try{const E=await ye(s,g.signal,s.stream?A=>{t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.write(`data: ${JSON.stringify(A)}
21
21
 
22
- `)}:void 0,void 0,{grantee:d.grantee,spend_cap:d.spend_cap},pe($(d.grant)??Ae(d.grant)));i.stream?(t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.end(`data: [DONE]
22
+ `)}:void 0,void 0,{grantee:c.grantee,spend_cap:c.spend_cap},he(await z(c.grant)??await Ne(c.grant)));s.stream?(t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.end(`data: [DONE]
23
23
 
24
- `)):O(t,200,R.completion)}finally{t.off("close",c)}return}if(a.name==="usage.get"){O(t,200,_e(d.grantee,d.spend_cap,we(p.searchParams.get("month"))));return}if(a.name==="profile.list"){O(t,200,ke(d));return}if(xe.has(a.name)){const i=await je(a.name,d,v.params.question_id,a.method==="POST"?await P(n):void 0);O(t,i.status,i.body);return}if($e.has(a.name)){const{signal:i,release:S}=Ue(t);try{const c=await Xe(a.name,Ve(d),{params:v.params,body:a.method==="POST"?await P(n):void 0,query:p.searchParams},{requestId:h,signal:i});O(t,c.status,c.body)}catch(c){const R=ze(c,h,!0);t.writeHead(R.status,{"Content-Type":"application/json; charset=utf-8","X-Content-Type-Options":"nosniff",...R.headers}),t.end(JSON.stringify(R.body))}finally{S()}return}if(Le.has(a.name)){const i=Je(a.name,{class:"app",app:d.grantee,scopes:d.resolved},p.searchParams);O(t,i.status,i.body);return}if(De.has(a.name)){const i=await Me(a,d,v.params,p.searchParams,await P(n));O(t,i.status,i.body);return}const M=await fe(a,d,b,p.searchParams,await P(n),n.headers["idempotency-key"]);O(t,M.status,M.body)}catch(N){qe(t,N,h,b)}})()});return{ready:new Promise((n,t)=>{w.once("error",t),w.listen(u.port,u.address,()=>{w.off("error",t),n()})}),close:s(async()=>{y.close(),Ne(),w.closeAllConnections(),await new Promise((n,t)=>w.close(h=>h?t(h):n()))},"close")}}s(xt,"createAppListener");export{Ke as RUN_STREAM_IDLE_MS,xt as createAppListener,Qe as cursor,Ze as streamRunEvents};
24
+ `)):O(t,200,E.completion)}finally{t.off("close",l)}return}if(a.name==="usage.get"){O(t,200,await ve(c.grantee,c.spend_cap,_e(p.searchParams.get("month"))));return}if(a.name==="profile.list"){O(t,200,Me(c));return}if(Je.has(a.name)){const s=await Be(a.name,c,R.params.question_id,a.method==="POST"?await I(n):void 0);O(t,s.status,s.body);return}if(Ge.has(a.name)){const{signal:s,release:g}=Xe(t);try{const l=await ze(a.name,$e(c),{params:R.params,body:a.method==="POST"?await I(n):void 0,query:p.searchParams},{requestId:h,signal:s});O(t,l.status,l.body)}catch(l){const E=Fe(l,h,!0);t.writeHead(E.status,{"Content-Type":"application/json; charset=utf-8","X-Content-Type-Options":"nosniff",...E.headers}),t.end(JSON.stringify(E.body))}finally{g()}return}if(Ve.has(a.name)){const s=await Ue(a.name,{class:"app",app:c.grantee,scopes:c.resolved},p.searchParams);O(t,s.status,s.body);return}if(xe.has(a.name)){const s=await je(a,c,R.params,p.searchParams,await I(n));O(t,s.status,s.body);return}const M=await me(a,c,S,p.searchParams,await I(n),n.headers["idempotency-key"]);O(t,M.status,M.body)}catch(C){We(t,C,h,S)}})()});return{ready:new Promise((n,t)=>{y.once("error",t),y.listen(u.port,u.address,()=>{y.off("error",t),n()})}),close:i(async()=>{w.close(),Ce(),y.closeAllConnections(),await new Promise((n,t)=>y.close(h=>h?t(h):n()))},"close")}}i(Lt,"createAppListener");export{et as RUN_STREAM_IDLE_MS,Lt as createAppListener,Ke as cursor,tt as streamRunEvents};
@@ -1,8 +1,8 @@
1
- var R=Object.defineProperty;var s=(r,e)=>R(r,"name",{value:e,configurable:!0});import{WebSocketServer as $}from"ws";import{isSafeNodeId as A}from"../../core/canvas/paths.js";import{getNode as S}from"../../core/canvas/index.js";import{BROKER_READ_CAPS as C,CLIENT_READ_CAPS as T,FrameDecoder as x,FrameOverflowError as B}from"../../core/runtime/broker-protocol.js";import{classify as k}from"../../core/fault-classifier.js";import{clearFault as v,markNodeRead as N,recordFault as g}from"../../core/canvas/recovery.js";import{decideAttachRevive as O}from"../../core/runtime/revive.js";import{connectViewSocket as P,probeViewSocket as F,waitForBrokerViewSocket as U}from"../../core/runtime/view-socket.js";import{isBeneathRefusal as D}from"../../core/spaces/open-beneath.js";import{attachViewer as _,detachViewer as V,presentViewer as L}from"./viewer-presence.js";const H=new $({noServer:!0,maxPayload:C.maxLineBytes}),M=25e3,J=6e4;function W(r,e=M,i=J){let n=!0,o=!1,a=Date.now();const f=s(()=>{n=!0},"acknowledge"),m=s(()=>{o||(o=!0,clearInterval(h),r.off("pong",f))},"stop");r.on("pong",f);const h=setInterval(()=>{if(Date.now()-a>i){n=!0;return}if(!n){m(),r.terminate();return}n=!1;try{r.ping()}catch{m(),r.terminate()}},e);return h.unref(),{stop:m,noteActivity:s(()=>{a=Date.now()},"noteActivity")}}s(W,"startRemoteAttachHeartbeat");function b(r){const e=Buffer.from(r,"utf8");return e.byteLength<=123?r:e.subarray(0,123).toString("utf8")}s(b,"clampReason");function u(r,e,i,n,o){const a=JSON.stringify({error:{code:n,message:o,origin:"runtime"}}),f=`HTTP/1.1 ${e} ${i}\r
1
+ var N=Object.defineProperty;var c=(t,e)=>N(t,"name",{value:e,configurable:!0});import{WebSocketServer as O}from"ws";import{isSafeNodeId as E}from"../../core/canvas/paths.js";import{getNode as S}from"../../core/canvas/index.js";import{BROKER_READ_CAPS as P,CLIENT_READ_CAPS as D,FrameDecoder as F,FrameOverflowError as U}from"../../core/runtime/broker-protocol.js";import{emitEvent as V}from"../../core/events/emit.js";import{classify as k}from"../../core/fault-classifier.js";import{clearFault as v,markNodeRead as L,recordFault as w}from"../../core/canvas/recovery.js";import{decideAttachRevive as H}from"../../core/runtime/revive.js";import{connectViewSocket as M,probeViewSocket as W,waitForBrokerViewSocket as J}from"../../core/runtime/view-socket.js";import{isBeneathRefusal as j}from"../../core/spaces/open-beneath.js";import{attachViewer as A,detachViewer as q,presentViewer as z}from"./viewer-presence.js";const K=new O({noServer:!0,maxPayload:P.maxLineBytes}),Q=25e3,G=6e4;function X(t,e=Q,n=G){let a=!0,o=!1,i=Date.now();const f=c(()=>{a=!0},"acknowledge"),y=c(()=>{o||(o=!0,clearInterval(d),t.off("pong",f))},"stop");t.on("pong",f);const d=setInterval(()=>{if(Date.now()-i>n){a=!0;return}if(!a){y(),t.terminate();return}a=!1;try{t.ping()}catch{y(),t.terminate()}},e);return d.unref(),{stop:y,noteActivity:c(()=>{i=Date.now()},"noteActivity")}}c(X,"startRemoteAttachHeartbeat");function b(t){const e=Buffer.from(t,"utf8");return e.byteLength<=123?t:e.subarray(0,123).toString("utf8")}c(b,"clampReason");function u(t,e,n,a,o){const i=JSON.stringify({error:{code:a,message:o,origin:"runtime"}}),f=`HTTP/1.1 ${e} ${n}\r
2
2
  content-type: application/json; charset=utf-8\r
3
- content-length: ${Buffer.byteLength(a)}\r
3
+ content-length: ${Buffer.byteLength(i)}\r
4
4
  connection: close\r
5
5
  \r
6
- `+a;try{r.end(f)}catch{try{r.destroy()}catch{}}}s(u,"refuseUpgrade");function j(r){if(new URL(r.url??"/","http://127.0.0.1").searchParams.get("revive")==="0")return!0;const i=r.headers["x-crtr-attach-revive"];return(Array.isArray(i)?i[0]:i)==="0"}s(j,"reviveOptedOut");function q(r){return new URL(r.url??"/","http://127.0.0.1").searchParams.get("wakeParked")==="1"}s(q,"wakeParkedRequested");function E(r){return r===1e3||r===1001||r===1005}s(E,"isCleanViewerClose");function z(r,e){if(!A(e)){try{r.close(1008,b(`invalid node id: ${e}`))}catch{}return}if(S(e)===null){try{r.close(1011,b(`no node ${e}`))}catch{}return}v(e,{link:"viewer\u2194crtrd"});const i=P(e),n=new x(T);let o=!1,a=!1,f,m=!1,h=!1,d=!1;i.on("connect",()=>{m=!0,!o&&d&&_(e,r),v(e,{link:"relay\u2194broker"})});const p=s((t,l)=>{if(!o){if(o=!0,V(e,r),f?.stop(),!i.destroyed)try{i.destroy()}catch{}try{r.close(t,b(l))}catch{}}},"teardown");f=W(r),i.on("data",t=>{f?.noteActivity();let l;try{l=n.push(t)}catch(c){const y=c instanceof B?`broker sent an oversized frame (${c.message})`:`failed to decode a broker frame for ${e}`;p(1009,y);return}for(const c of l)if(r.readyState===r.OPEN&&(r.send(JSON.stringify(c)),d&&c?.type==="welcome"&&L(e,r)))try{N(e)}catch{}}),i.on("error",t=>{const l=k("relay\u2194broker",t);g(e,{link:"relay\u2194broker",op:"bridge socket",kind:l.kind,retry:{disposition:"manual"},message:t.message});const c=t.code==="ECONNREFUSED"||t.code==="ENOENT"?`no running broker for ${e}`:`view socket error for ${e}: ${t.message}`;p(1011,c)}),i.on("close",t=>{o||t||(v(e,{link:"relay\u2194broker"}),p(1e3,"broker socket closed"))}),r.on("close",(t,l)=>{const c=l.toString("utf8");if(o){E(t)&&v(e,{link:"viewer\u2194crtrd"});return}if(E(t))v(e,{link:"viewer\u2194crtrd"});else if(!a){a=!0;const y=k("viewer\u2194crtrd",{code:t,reason:c});g(e,{link:"viewer\u2194crtrd",op:"remote attach websocket",kind:y.kind,retry:{disposition:"auto"},message:c||`remote attach closed (${t})`})}p(t,c||`remote attach closed (${t})`)}),r.on("error",()=>{if(!a){a=!0;const t=k("viewer\u2194crtrd",{code:1006,reason:"remote attach websocket error"});g(e,{link:"viewer\u2194crtrd",op:"remote attach websocket",kind:t.kind,retry:{disposition:"auto"},message:"remote attach websocket error"})}p(1011,"remote attach websocket error")}),r.on("message",t=>{if(o||i.destroyed)return;f?.noteActivity();const c=(Array.isArray(t)?Buffer.concat(t):Buffer.isBuffer(t)?t:Buffer.from(new Uint8Array(t))).toString("utf8");if(!h)try{const w=JSON.parse(c);w?.type==="hello"&&(h=!0,d=w.attends!==!1,d&&m&&_(e,r))}catch{}const y=c.endsWith(`
7
- `)?c:c+`
8
- `;try{i.write(y)}catch{}})}s(z,"bridgeConnection");async function oe(r,e,i,n){e.on("error",()=>{});try{if(!A(n)){u(e,400,"Bad Request","invalid_node_id",`invalid node id: ${n}`);return}if(S(n)===null){u(e,404,"Not Found","node_not_found",`no node ${n}`);return}if(j(r)){if(!await F(n,250)){u(e,409,"Conflict","node_dormant",`node ${n} is dormant and revive was opted out (?revive=0)`);return}}else{let o;try{const a=await O(n,{resume:!0,capacity:"refuse"},q(r));if(a.parked){u(e,409,"Conflict","node_dormant",`node ${n} is parked; attach with ?wakeParked=1 to wake it`);return}o=a.result.launch?.exited}catch(a){const f=a instanceof Error?a.message:String(a);u(e,409,"Conflict","attach_revive_failed",`attach revive failed: ${f}`);return}if(!await U(n,o)){u(e,409,"Conflict","broker_not_ready",`broker view socket for ${n} did not become listenable after revive`);return}}if(e.destroyed)return;H.handleUpgrade(r,e,i,o=>z(o,n))}catch(o){const a=o instanceof Error?o.message:String(o);if(D(o)){u(e,400,"Bad Request","invalid_request",a);return}u(e,500,"Internal Server Error","internal",`attach upgrade failed: ${a}`)}}s(oe,"handleAttachUpgrade");export{M as REMOTE_ATTACH_HEARTBEAT_MS,J as REMOTE_ATTACH_QUIET_MS,oe as handleAttachUpgrade,E as isCleanViewerClose,u as refuseUpgrade,W as startRemoteAttachHeartbeat};
6
+ `+i;try{t.end(f)}catch{try{t.destroy()}catch{}}}c(u,"refuseUpgrade");function Y(t){if(new URL(t.url??"/","http://127.0.0.1").searchParams.get("revive")==="0")return!0;const n=t.headers["x-crtr-attach-revive"];return(Array.isArray(n)?n[0]:n)==="0"}c(Y,"reviveOptedOut");function Z(t){return new URL(t.url??"/","http://127.0.0.1").searchParams.get("wakeParked")==="1"}c(Z,"wakeParkedRequested");function R(t){return t===1e3||t===1001||t===1005}c(R,"isCleanViewerClose");function m(t,e,n){n.catch(a=>V({level:"error",event:e,node_id:t,error:a}))}c(m,"detach");async function I(t,e){if(!E(e)){try{t.close(1008,b(`invalid node id: ${e}`))}catch{}return}if(await S(e)===null){try{t.close(1011,b(`no node ${e}`))}catch{}return}await v(e,{link:"viewer\u2194crtrd"});const n=M(e),a=new F(D);let o=!1,i=!1,f,y=!1,d=!1,g=!1;n.on("connect",()=>{y=!0,!o&&g&&A(e,t),m(e,"daemon.bridge.connect_failed",v(e,{link:"relay\u2194broker"}))});const h=c((r,l)=>{if(!o){if(o=!0,q(e,t),f?.stop(),!n.destroyed)try{n.destroy()}catch{}try{t.close(r,b(l))}catch{}}},"teardown");f=X(t);const $=c(async r=>{f?.noteActivity();let l;try{l=a.push(r)}catch(s){const p=s instanceof U?`broker sent an oversized frame (${s.message})`:`failed to decode a broker frame for ${e}`;h(1009,p);return}for(const s of l)if(t.readyState===t.OPEN&&(t.send(JSON.stringify(s)),g&&s?.type==="welcome"&&z(e,t)))try{await L(e)}catch{}},"onData");n.on("data",r=>m(e,"daemon.bridge.data_failed",$(r)));const C=c(async r=>{const l=k("relay\u2194broker",r);await w(e,{link:"relay\u2194broker",op:"bridge socket",kind:l.kind,retry:{disposition:"manual"},message:r.message});const s=r.code==="ECONNREFUSED"||r.code==="ENOENT"?`no running broker for ${e}`:`view socket error for ${e}: ${r.message}`;h(1011,s)},"onSocketError");n.on("error",r=>m(e,"daemon.bridge.socket_error_failed",C(r)));const T=c(async r=>{o||r||(await v(e,{link:"relay\u2194broker"}),h(1e3,"broker socket closed"))},"onSocketClose");n.on("close",r=>m(e,"daemon.bridge.socket_close_failed",T(r)));const x=c(async(r,l)=>{const s=l.toString("utf8");if(o){R(r)&&await v(e,{link:"viewer\u2194crtrd"});return}if(R(r))await v(e,{link:"viewer\u2194crtrd"});else if(!i){i=!0;const p=k("viewer\u2194crtrd",{code:r,reason:s});await w(e,{link:"viewer\u2194crtrd",op:"remote attach websocket",kind:p.kind,retry:{disposition:"auto"},message:s||`remote attach closed (${r})`})}h(r,s||`remote attach closed (${r})`)},"onWsClose");t.on("close",(r,l)=>m(e,"daemon.bridge.ws_close_failed",x(r,l)));const B=c(async()=>{if(!i){i=!0;const r=k("viewer\u2194crtrd",{code:1006,reason:"remote attach websocket error"});await w(e,{link:"viewer\u2194crtrd",op:"remote attach websocket",kind:r.kind,retry:{disposition:"auto"},message:"remote attach websocket error"})}h(1011,"remote attach websocket error")},"onWsError");t.on("error",()=>m(e,"daemon.bridge.ws_error_failed",B())),t.on("message",r=>{if(o||n.destroyed)return;f?.noteActivity();const s=(Array.isArray(r)?Buffer.concat(r):Buffer.isBuffer(r)?r:Buffer.from(new Uint8Array(r))).toString("utf8");if(!d)try{const _=JSON.parse(s);_?.type==="hello"&&(d=!0,g=_.attends!==!1,g&&y&&A(e,t))}catch{}const p=s.endsWith(`
7
+ `)?s:s+`
8
+ `;try{n.write(p)}catch{}})}c(I,"bridgeConnection");async function me(t,e,n,a){e.on("error",()=>{});try{if(!E(a)){u(e,400,"Bad Request","invalid_node_id",`invalid node id: ${a}`);return}if(await S(a)===null){u(e,404,"Not Found","node_not_found",`no node ${a}`);return}if(Y(t)){if(!await W(a,250)){u(e,409,"Conflict","node_dormant",`node ${a} is dormant and revive was opted out (?revive=0)`);return}}else{let o;try{const i=await H(a,{resume:!0,capacity:"refuse"},Z(t));if(i.parked){u(e,409,"Conflict","node_dormant",`node ${a} is parked; attach with ?wakeParked=1 to wake it`);return}o=i.result.launch?.exited}catch(i){const f=i instanceof Error?i.message:String(i);u(e,409,"Conflict","attach_revive_failed",`attach revive failed: ${f}`);return}if(!await J(a,o)){u(e,409,"Conflict","broker_not_ready",`broker view socket for ${a} did not become listenable after revive`);return}}if(e.destroyed)return;K.handleUpgrade(t,e,n,o=>m(a,"daemon.bridge.connection_failed",I(o,a)))}catch(o){const i=o instanceof Error?o.message:String(o);if(j(o)){u(e,400,"Bad Request","invalid_request",i);return}u(e,500,"Internal Server Error","internal",`attach upgrade failed: ${i}`)}}c(me,"handleAttachUpgrade");export{Q as REMOTE_ATTACH_HEARTBEAT_MS,G as REMOTE_ATTACH_QUIET_MS,me as handleAttachUpgrade,R as isCleanViewerClose,u as refuseUpgrade,X as startRemoteAttachHeartbeat};
@@ -1,11 +1,11 @@
1
- var L=Object.defineProperty;var h=(n,r)=>L(n,"name",{value:r,configurable:!0});import{createHash as D,timingSafeEqual as A}from"node:crypto";import{createServer as W}from"node:http";import{readFileSync as U}from"node:fs";import{join as T,extname as z}from"node:path";import{fileURLToPath as B}from"node:url";import{withCanvasWrite as g}from"../../core/canvas/db.js";import{ApiError as G}from"../../api/errors.js";import{bodyOf as b}from"../../core/graph/bodies.js";import{canChange as E,isShipped as I}from"../../core/graph/access.js";import{documentRecord as H,editDocument as F,heads as x,withCurrentNames as C}from"../../core/graph/documents.js";import{getById as O}from"../../core/graph/objects.js";import{subscribeDocumentEvents as J}from"../../core/graph/events.js";import{checkoutsForCwd as M}from"../../core/graph/repo-sync/repos.js";import{canonicalName as V,repoChange as X,syncChanged as Z}from"./handlers/docs.js";import{escapeHtml as k}from"./vendor-signin.js";import{readerFor as w,resolveRef as K}from"./reader.js";import{mergeDocumentLines as Q}from"./document-merge.js";import{crtrVersion as Y}from"../../shared/crtr-version.js";const q="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'",S={class:"person"},f=encodeURIComponent(Y()),N=B(new URL("../../../dist/",import.meta.url));function m(n,r,t,s){n.writeHead(r,{"Content-Type":"application/json; charset=utf-8"}),n.end(JSON.stringify({error:{code:t,message:s}}))}h(m,"error");function j(n,r){const t=h(s=>D("sha256").update(s).digest(),"digest");return A(t(n),t(r))}h(j,"sameSecret");function ee(n,r){for(const t of(n??"").split(";")){const s=t.indexOf("=");if(s!==-1&&t.slice(0,s).trim()===r)return t.slice(s+1).trim()}}h(ee,"cookieValue");function P(n,r,t){n.writeHead(r,{"Content-Type":"application/json; charset=utf-8"}),n.end(JSON.stringify(t))}h(P,"json");function R(n){return g(r=>{const t=O(r,n.id);if(!t||t.deleted_at||t.type!=="document")return null;const s=w(r,{principal:S}),l=H(r,t),o=x(r,t),e=V(r,t),u=o.length===1&&E(r,s,t);return{id:t.id,name:e,revision:l.revision,heads_key:l.heads_key,body:o.length===1?C(r,t,b(o[0].body_hash,l.source_path)):"",editable:u,...u?{}:{readonly_reason:o.length!==1?`has ${o.length} heads and needs a merge`:I(r,t)?"shipped by a plugin":"you cannot change this document"}}})}h(R,"snapshot");function y(n){return g(r=>{const t=w(r,{principal:S});try{const s=K(r,t,n);return"deleted"in s||"remote"in s||s.type!=="document"?null:s}catch(s){if(s instanceof G&&s.code==="not_found")return null;throw s}})}h(y,"resolveDocument");async function te(n){const r=[];let t=0;for await(const s of n){if(t+=s.length,t>2e6)throw new Error("request body exceeds 2 MB");r.push(s)}return JSON.parse(Buffer.concat(r).toString("utf8"))}h(te,"requestBody");function ne(n){const r=g(t=>{const s=w(t,{principal:S}),l=O(t,n.id);if(!l||l.type!=="document"||l.deleted_at)return{status:404,value:{error:{code:"not_found",message:"document not found"}}};const o=H(t,l),e=x(t,l);if(e.length!==1||!E(t,s,l))return{status:403,value:{error:{code:"forbidden",message:"document is read-only"}}};const u=C(t,l,b(e[0].body_hash,o.source_path)),d=t.prepare("SELECT body_hash FROM revisions WHERE document = ? AND rev_id = ?").get(l.rowid,n.base_heads_key);if(!d||C(t,l,b(d.body_hash,o.source_path))!==n.base_body)return{status:409,value:{saved:!1,conflict:{revision:o.revision,heads_key:o.heads_key,current_body:u,your_body:n.body}}};const a=n.base_heads_key!==o.heads_key,i=a?Q(n.base_body,n.body,u):n.body;if(i===null)return{status:409,value:{saved:!1,conflict:{revision:o.revision,heads_key:o.heads_key,current_body:u,your_body:n.body}}};const c=F(t,s,l,{body:i},n.rationale?.trim()||"edited by the person in the browser",o.heads_key,{},v=>M(t,v));return"stale"in c?{status:409,value:{saved:!1,conflict:{revision:c.stale.revision,heads_key:c.stale.heads_key,current_body:u,your_body:n.body}}}:{status:200,value:{saved:!0,revision:c.revision,heads_key:c.heads_key,body:i,merged:a},change:X(t,s,[l])}});return r.change&&Z(r.change),r}h(ne,"save");let p="the document listener has not started";function ke(){return p}h(ke,"documentListenerUnavailable");function we(n,r){const t=`crtr_doc_${n}`,s=W((o,e)=>{(async()=>{e.setHeader("Content-Security-Policy",q),e.setHeader("X-Content-Type-Options","nosniff");const u=[`127.0.0.1:${n}`,`localhost:${n}`];if(typeof o.headers.host!="string"||!u.includes(o.headers.host))return m(e,403,"forbidden","invalid Host");if(o.method==="POST"){if(!u.some(a=>o.headers.origin===`http://${a}`))return m(e,403,"forbidden","invalid Origin");if(o.headers["content-type"]!=="application/json")return m(e,415,"unsupported_media_type","Content-Type must be application/json")}const d=new URL(o.url??"/",`http://127.0.0.1:${n}`);if(!d.pathname.startsWith("/assets/")){const a=o.method==="GET"&&d.pathname.startsWith("/r/")?d.searchParams.get("t"):null;if(a!==null&&j(a,r))return d.searchParams.delete("t"),e.writeHead(303,{Location:`${d.pathname}${d.search}`,"Set-Cookie":`${t}=${r}; HttpOnly; SameSite=Strict; Path=/`,"Cache-Control":"no-store"}),e.end();const i=ee(o.headers.cookie,t);if(a!==null||i===void 0||!j(i,r))return d.pathname.startsWith("/r/")?(e.writeHead(401,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),e.end('<!doctype html><html><head><meta charset="utf-8"><title>Not authorized</title><link rel="icon" href="data:,"></head><body style="font-family:system-ui,sans-serif;max-width:40rem;margin:4rem auto;padding:0 1rem"><h1>Not authorized</h1><p>Open this document from its link in the attach viewer.</p></body></html>')):m(e,401,"unauthorized","open the document link from the attach viewer")}if(o.method==="GET"&&d.pathname.startsWith("/r/")){let a;try{a=decodeURIComponent(d.pathname.slice(3))}catch{return m(e,400,"invalid_request","ref is not valid percent-encoding")}const i=y(a);return i?(e.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),e.end(`<!doctype html><html><head><meta charset="utf-8"><title>${k(i.name)}</title><link rel="icon" href="data:,"><link rel="stylesheet" href="/assets/${f}/editor.css"></head><body><div id="app" data-ref="${k(a)}"></div><script type="module" src="/assets/${f}/editor.js"><\/script></body></html>`)):(e.writeHead(404,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),e.end(`<!doctype html><html><head><meta charset="utf-8"><title>Document not found</title><link rel="icon" href="data:,"></head><body style="font-family:system-ui,sans-serif;max-width:40rem;margin:4rem auto;padding:0 1rem"><h1>Document not found</h1><p>No document you can read is named <code>${k(a)}</code>.</p></body></html>`))}if(o.method==="GET"&&d.pathname==="/api/doc"){const a=d.searchParams.get("ref"),i=a?y(a):null,c=i&&R(i);return c?P(e,200,{...c,ref:a}):m(e,404,"not_found","document not found")}if(o.method==="POST"&&d.pathname==="/api/save"){const a=await te(o);if(!a||typeof a!="object"||Array.isArray(a))return m(e,400,"invalid_request","invalid save body");const i=a;if(typeof i.id!="string"||typeof i.base_heads_key!="string"||typeof i.base_body!="string"||typeof i.body!="string"||i.rationale!==void 0&&typeof i.rationale!="string")return m(e,400,"invalid_request","invalid save body");const c=ne(i);return P(e,c.status,c.value)}if(o.method==="GET"&&d.pathname==="/api/events"){const a=d.searchParams.get("id");if(!a||!y(a))return m(e,404,"not_found","document not found");e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-store",Connection:"keep-alive"}),e.write(`: connected
1
+ var D=Object.defineProperty;var h=(n,a)=>D(n,"name",{value:a,configurable:!0});import{createHash as A,timingSafeEqual as U}from"node:crypto";import{createServer as W}from"node:http";import{readFileSync as z}from"node:fs";import{join as E,extname as B}from"node:path";import{fileURLToPath as G}from"node:url";import{withCanvasWrite as b}from"../../core/canvas/db.js";import{ApiError as I}from"../../api/errors.js";import{bodyOf as C}from"../../core/graph/bodies.js";import{canChange as H,isShipped as F}from"../../core/graph/access.js";import{documentRecord as x,editDocument as J,heads as O,withCurrentNames as k}from"../../core/graph/documents.js";import{getById as N}from"../../core/graph/objects.js";import{subscribeDocumentEvents as M}from"../../core/graph/events.js";import{emitEvent as V}from"../../core/events/emit.js";import{checkoutsForCwd as X}from"../../core/graph/repo-sync/repos.js";import{canonicalName as Z,repoChange as K,syncChanged as Q}from"./handlers/docs.js";import{escapeHtml as S}from"./vendor-signin.js";import{readerFor as $,resolveRef as Y}from"./reader.js";import{mergeDocumentLines as q}from"./document-merge.js";import{crtrVersion as ee}from"../../shared/crtr-version.js";const te="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'",T={class:"person"},y=encodeURIComponent(ee()),j=G(new URL("../../../dist/",import.meta.url));function m(n,a,t,i){n.writeHead(a,{"Content-Type":"application/json; charset=utf-8"}),n.end(JSON.stringify({error:{code:t,message:i}}))}h(m,"error");function P(n,a){const t=h(i=>A("sha256").update(i).digest(),"digest");return U(t(n),t(a))}h(P,"sameSecret");function ne(n,a){for(const t of(n??"").split(";")){const i=t.indexOf("=");if(i!==-1&&t.slice(0,i).trim()===a)return t.slice(i+1).trim()}}h(ne,"cookieValue");function R(n,a,t){n.writeHead(a,{"Content-Type":"application/json; charset=utf-8"}),n.end(JSON.stringify(t))}h(R,"json");async function L(n){return await b(async a=>{const t=await N(a,n.id);if(!t||t.deleted_at||t.type!=="document")return null;const i=await $(a,{principal:T}),l=await x(a,t),o=await O(a,t),e=await Z(a,t),u=o.length===1&&await H(a,i,t);return{id:t.id,name:e,revision:l.revision,heads_key:l.heads_key,body:o.length===1?await k(a,t,C(o[0].body_hash,l.source_path)):"",editable:u,...u?{}:{readonly_reason:o.length!==1?`has ${o.length} heads and needs a merge`:await F(a,t)?"shipped by a plugin":"you cannot change this document"}}})}h(L,"snapshot");async function p(n){return await b(async a=>{const t=await $(a,{principal:T});try{const i=await Y(a,t,n);return"deleted"in i||"remote"in i||i.type!=="document"?null:i}catch(i){if(i instanceof I&&i.code==="not_found")return null;throw i}})}h(p,"resolveDocument");async function oe(n){const a=[];let t=0;for await(const i of n){if(t+=i.length,t>2e6)throw new Error("request body exceeds 2 MB");a.push(i)}return JSON.parse(Buffer.concat(a).toString("utf8"))}h(oe,"requestBody");async function ae(n){const a=await b(async t=>{const i=await $(t,{principal:T}),l=await N(t,n.id);if(!l||l.type!=="document"||l.deleted_at)return{status:404,value:{error:{code:"not_found",message:"document not found"}}};const o=await x(t,l),e=await O(t,l);if(e.length!==1||!await H(t,i,l))return{status:403,value:{error:{code:"forbidden",message:"document is read-only"}}};const u=await k(t,l,C(e[0].body_hash,o.source_path)),c=await t.prepareUncached("SELECT body_hash FROM revisions WHERE document = ? AND rev_id = ?").get(l.rowid,n.base_heads_key);if(!c||await k(t,l,C(c.body_hash,o.source_path))!==n.base_body)return{status:409,value:{saved:!1,conflict:{revision:o.revision,heads_key:o.heads_key,current_body:u,your_body:n.body}}};const r=n.base_heads_key!==o.heads_key,s=r?q(n.base_body,n.body,u):n.body;if(s===null)return{status:409,value:{saved:!1,conflict:{revision:o.revision,heads_key:o.heads_key,current_body:u,your_body:n.body}}};const d=await J(t,i,l,{body:s},n.rationale?.trim()||"edited by the person in the browser",o.heads_key,{},async w=>await X(t,w));return"stale"in d?{status:409,value:{saved:!1,conflict:{revision:d.stale.revision,heads_key:d.stale.heads_key,current_body:u,your_body:n.body}}}:{status:200,value:{saved:!0,revision:d.revision,heads_key:d.heads_key,body:s,merged:r},change:await K(t,i,[l])}});return a.change&&await Q(a.change),a}h(ae,"save");let v="the document listener has not started";function $e(){return v}h($e,"documentListenerUnavailable");function Te(n,a){const t=`crtr_doc_${n}`,i=W((o,e)=>{(async()=>{e.setHeader("Content-Security-Policy",te),e.setHeader("X-Content-Type-Options","nosniff");const u=[`127.0.0.1:${n}`,`localhost:${n}`];if(typeof o.headers.host!="string"||!u.includes(o.headers.host))return m(e,403,"forbidden","invalid Host");if(o.method==="POST"){if(!u.some(r=>o.headers.origin===`http://${r}`))return m(e,403,"forbidden","invalid Origin");if(o.headers["content-type"]!=="application/json")return m(e,415,"unsupported_media_type","Content-Type must be application/json")}const c=new URL(o.url??"/",`http://127.0.0.1:${n}`);if(!c.pathname.startsWith("/assets/")){const r=o.method==="GET"&&c.pathname.startsWith("/r/")?c.searchParams.get("t"):null;if(r!==null&&P(r,a))return c.searchParams.delete("t"),e.writeHead(303,{Location:`${c.pathname}${c.search}`,"Set-Cookie":`${t}=${a}; HttpOnly; SameSite=Strict; Path=/`,"Cache-Control":"no-store"}),e.end();const s=ne(o.headers.cookie,t);if(r!==null||s===void 0||!P(s,a))return c.pathname.startsWith("/r/")?(e.writeHead(401,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),e.end('<!doctype html><html><head><meta charset="utf-8"><title>Not authorized</title><link rel="icon" href="data:,"></head><body style="font-family:system-ui,sans-serif;max-width:40rem;margin:4rem auto;padding:0 1rem"><h1>Not authorized</h1><p>Open this document from its link in the attach viewer.</p></body></html>')):m(e,401,"unauthorized","open the document link from the attach viewer")}if(o.method==="GET"&&c.pathname.startsWith("/r/")){let r;try{r=decodeURIComponent(c.pathname.slice(3))}catch{return m(e,400,"invalid_request","ref is not valid percent-encoding")}const s=await p(r);return s?(e.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),e.end(`<!doctype html><html><head><meta charset="utf-8"><title>${S(s.name)}</title><link rel="icon" href="data:,"><link rel="stylesheet" href="/assets/${y}/editor.css"></head><body><div id="app" data-ref="${S(r)}"></div><script type="module" src="/assets/${y}/editor.js"><\/script></body></html>`)):(e.writeHead(404,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store"}),e.end(`<!doctype html><html><head><meta charset="utf-8"><title>Document not found</title><link rel="icon" href="data:,"></head><body style="font-family:system-ui,sans-serif;max-width:40rem;margin:4rem auto;padding:0 1rem"><h1>Document not found</h1><p>No document you can read is named <code>${S(r)}</code>.</p></body></html>`))}if(o.method==="GET"&&c.pathname==="/api/doc"){const r=c.searchParams.get("ref"),s=r?await p(r):null,d=s&&await L(s);return d?R(e,200,{...d,ref:r}):m(e,404,"not_found","document not found")}if(o.method==="POST"&&c.pathname==="/api/save"){const r=await oe(o);if(!r||typeof r!="object"||Array.isArray(r))return m(e,400,"invalid_request","invalid save body");const s=r;if(typeof s.id!="string"||typeof s.base_heads_key!="string"||typeof s.base_body!="string"||typeof s.body!="string"||s.rationale!==void 0&&typeof s.rationale!="string")return m(e,400,"invalid_request","invalid save body");const d=await ae(s);return R(e,d.status,d.value)}if(o.method==="GET"&&c.pathname==="/api/events"){const r=c.searchParams.get("id");if(!r||!await p(r))return m(e,404,"not_found","document not found");e.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-store",Connection:"keep-alive"}),e.write(`: connected
2
2
 
3
- `);const i=J(a,v=>{if(v==="deleted"){e.write(`event: deleted
3
+ `);const s=h(async _=>{if(_==="deleted"){e.write(`event: deleted
4
4
  data: {}
5
5
 
6
- `),e.end();return}const $=y(a),_=$&&R($);_&&e.write(`event: edited
7
- data: ${JSON.stringify({revision:_.revision,heads_key:_.heads_key})}
6
+ `),e.end();return}const f=await p(r),g=f&&await L(f);g&&e.write(`event: edited
7
+ data: ${JSON.stringify({revision:g.revision,heads_key:g.heads_key})}
8
8
 
9
- `)}),c=setInterval(()=>e.write(`: keepalive
9
+ `)},"notify"),d=await M(r,_=>{s(_).catch(f=>{V({level:"error",event:"daemon.document_events.notify_failed",error:f}),e.end()})}),w=setInterval(()=>e.write(`: keepalive
10
10
 
11
- `),3e4);e.on("close",()=>{clearInterval(c),i()});return}if(o.method==="GET"&&d.pathname.startsWith(`/assets/${f}/`)){const a=d.pathname.slice(`/assets/${f}/`.length);if(!/^[a-zA-Z0-9_.-]+$/.test(a))return m(e,404,"not_found","asset not found");const i=a==="mermaid.js"?T(N,"clients/attach/assets/mermaid.min.js"):T(N,"doc-editor",a);try{const c=U(i);return e.writeHead(200,{"Content-Type":z(a)===".css"?"text/css; charset=utf-8":"text/javascript; charset=utf-8","Cache-Control":"public, max-age=31536000, immutable"}),e.end(c)}catch(c){if(c.code==="ENOENT")return m(e,404,"not_found","asset not found");throw c}}return m(e,404,"not_found","route not found")})().catch(u=>{e.headersSent?e.destroy():m(e,500,"server_failure",u instanceof Error?u.message:String(u))})});return{ready:new Promise((o,e)=>{s.once("error",u=>{p=`the document listener could not bind 127.0.0.1:${n}: ${u.message}`,e(u)}),s.listen(n,"127.0.0.1",()=>{s.removeAllListeners("error"),p=void 0,o()})}),close:h(()=>new Promise(o=>{p="the document listener is closed",s.closeAllConnections(),s.close(()=>o())}),"close")}}h(we,"createDocumentListener");export{we as createDocumentListener,ke as documentListenerUnavailable};
11
+ `),3e4);e.on("close",()=>{clearInterval(w),d()});return}if(o.method==="GET"&&c.pathname.startsWith(`/assets/${y}/`)){const r=c.pathname.slice(`/assets/${y}/`.length);if(!/^[a-zA-Z0-9_.-]+$/.test(r))return m(e,404,"not_found","asset not found");const s=r==="mermaid.js"?E(j,"clients/attach/assets/mermaid.min.js"):E(j,"doc-editor",r);try{const d=z(s);return e.writeHead(200,{"Content-Type":B(r)===".css"?"text/css; charset=utf-8":"text/javascript; charset=utf-8","Cache-Control":"public, max-age=31536000, immutable"}),e.end(d)}catch(d){if(d.code==="ENOENT")return m(e,404,"not_found","asset not found");throw d}}return m(e,404,"not_found","route not found")})().catch(u=>{e.headersSent?e.destroy():m(e,500,"server_failure",u instanceof Error?u.message:String(u))})});return{ready:new Promise((o,e)=>{i.once("error",u=>{v=`the document listener could not bind 127.0.0.1:${n}: ${u.message}`,e(u)}),i.listen(n,"127.0.0.1",()=>{i.removeAllListeners("error"),v=void 0,o()})}),close:h(()=>new Promise(o=>{v="the document listener is closed",i.closeAllConnections(),i.close(()=>o())}),"close")}}h(Te,"createDocumentListener");export{Te as createDocumentListener,$e as documentListenerUnavailable};
@@ -1 +1 @@
1
- var y=Object.defineProperty;var n=(e,o)=>y(e,"name",{value:o,configurable:!0});import{prepared as l}from"../../../core/sqlite-statements.js";import{listNodes as h}from"../../../core/canvas/canvas.js";import{openDb as m}from"../../../core/canvas/db.js";import{listMemoryReads as g,memoryReadsStartedAt as b}from"../../../core/canvas/memory-reads.js";import{usage as a}from"../../../core/errors.js";import{computeAnalytics as R,WINDOW_MS as S}from"../../analytics/compute.js";import{scanResponses as O}from"../../analytics/scan.js";import{canReadNode as E}from"../router.js";const M=new Set(["as_of","window","project"]);async function N(e){for(const[t]of e.query)if(!M.has(t))throw a(`unknown analytics query parameter: ${t}`);const o=e.query.get("as_of")??"",i=Date.parse(o);if(!Number.isFinite(i))throw a(`as_of must be an ISO 8601 time, got "${o}"`);const r=e.query.get("window")??"";if(!Object.hasOwn(S,r))throw a(`window must be 24h or 7d, got "${r}"`);const d=e.query.get("project");if(d==="")throw a("project must be a non-empty directory path when given");const s=new Map,f=l(m(),"SELECT node_id, transcript_path FROM sessions WHERE transcript_path IS NOT NULL").all();for(const t of f)s.set(t.node_id,(s.get(t.node_id)??new Set).add(t.transcript_path));const w=new Map(l(m(),"SELECT node_id, title FROM node_rows WHERE title IS NOT NULL").all().map(t=>[t.node_id,t.title])),c=e.principal,u=h().filter(t=>t.kind!=="human"&&(c.class==="person"||E(c,t.grantee??"app:terminal",t.node_id))).map(t=>({node_id:t.node_id,name:t.name,title:w.get(t.node_id)??null,kind:t.kind,parent:t.parent??null,cwd:t.cwd,created:t.created,finalized_at:t.finalized_at??null,final_report:t.final_report??null,lifecycle:t.lifecycle,transcripts:[...s.get(t.node_id)??[]]})),p=new AbortController;return e.res.once("close",()=>p.abort()),{status:200,body:await R({asOfMs:i,window:r,project:d??null,agents:u,scan:n(t=>O(t,p.signal),"scan"),memory:n((t,_)=>({rows:g(t,_),startedAt:b()}),"memory")})}}n(N,"handleAnalytics");const D=[{method:"GET",pattern:"/v1/canvas/analytics",handler:N}];export{D as analyticsRoutes};
1
+ var u=Object.defineProperty;var o=(e,a)=>u(e,"name",{value:a,configurable:!0});import{listNodes as _}from"../../../core/canvas/canvas.js";import{openDb as l}from"../../../core/canvas/db.js";import{listMemoryReads as h,memoryReadsStartedAt as g}from"../../../core/canvas/memory-reads.js";import{usage as n}from"../../../core/errors.js";import{computeAnalytics as b,WINDOW_MS as R}from"../../analytics/compute.js";import{scanResponses as O}from"../../analytics/scan.js";import{canReadNode as S}from"../router.js";import{filterAsync as E}from"../../../core/async-array.js";const A=new Set(["as_of","window","project"]);async function M(e){for(const[t]of e.query)if(!A.has(t))throw n(`unknown analytics query parameter: ${t}`);const a=e.query.get("as_of")??"",s=Date.parse(a);if(!Number.isFinite(s))throw n(`as_of must be an ISO 8601 time, got "${a}"`);const r=e.query.get("window")??"";if(!Object.hasOwn(R,r))throw n(`window must be 24h or 7d, got "${r}"`);const d=e.query.get("project");if(d==="")throw n("project must be a non-empty directory path when given");const i=new Map,m=await(await l()).prepare("SELECT node_id, transcript_path FROM sessions WHERE transcript_path IS NOT NULL").all();for(const t of m)i.set(t.node_id,(i.get(t.node_id)??new Set).add(t.transcript_path));const w=new Map((await(await l()).prepare("SELECT node_id, title FROM node_rows WHERE title IS NOT NULL").all()).map(t=>[t.node_id,t.title])),c=e.principal,f=(await E(await _(),async t=>t.kind!=="human"&&(c.class==="person"||await S(c,t.grantee??"app:terminal",t.node_id)))).map(t=>({node_id:t.node_id,name:t.name,title:w.get(t.node_id)??null,kind:t.kind,parent:t.parent??null,cwd:t.cwd,created:t.created,finalized_at:t.finalized_at??null,final_report:t.final_report??null,lifecycle:t.lifecycle,transcripts:[...i.get(t.node_id)??[]]})),p=new AbortController;return e.res.once("close",()=>p.abort()),{status:200,body:await b({asOfMs:s,window:r,project:d??null,agents:f,scan:o(t=>O(t,p.signal),"scan"),memory:o(async(t,y)=>({rows:await h(t,y),startedAt:await g()}),"memory")})}}o(M,"handleAnalytics");const D=[{method:"GET",pattern:"/v1/canvas/analytics",handler:M}];export{D as analyticsRoutes};
@@ -1 +1 @@
1
- var c=Object.defineProperty;var i=(t,e)=>c(t,"name",{value:e,configurable:!0});import{getNode as m}from"../../../core/canvas/canvas.js";import{decideAttachRevive as k}from"../../../core/runtime/revive.js";import{viewSocketPath as l}from"../../../core/canvas/paths.js";import{waitForBrokerViewSocket as v}from"../../../core/runtime/placement-tmux.js";import{notFound as p,usage as n}from"../../../core/errors.js";import{ownerOnly as w}from"../router.js";function h(t){if(t==null)return{resume:!0,revive:!0,wakeParked:!0};if(typeof t!="object")throw n("attach body must be a JSON object { resume?, revive?, wakeParked? }");const e=t.resume,r=t.revive,o=t.wakeParked;if(e!==void 0&&typeof e!="boolean")throw n("resume must be a boolean");if(r!==void 0&&typeof r!="boolean")throw n("revive must be a boolean");if(o!==void 0&&typeof o!="boolean")throw n("wakeParked must be a boolean");return{resume:e??!0,revive:r??!0,wakeParked:o??!0}}i(h,"parseAttachBody");async function b(t){const e=t.params.id;if(m(e)===null)throw p(`unknown node: ${e}`,{received:e});const{resume:r,revive:o,wakeParked:f}=h(t.body);let u=!1,d=!1,s=!1;if(o){const a=await k(e,{resume:r,capacity:"refuse"},f);s=a.parked,a.parked||(u=a.result.launch!==void 0,d=a.result.resumed,await v(e))}return{status:200,body:{node_id:e,socket_path:l(e),revived:u,resumed:d,parked:s}}}i(b,"handleAttach");const F=w([{method:"POST",pattern:"/v1/nodes/:id/attach",handler:b}]);export{F as attachRoutes};
1
+ var c=Object.defineProperty;var i=(t,e)=>c(t,"name",{value:e,configurable:!0});import{getNode as m}from"../../../core/canvas/canvas.js";import{decideAttachRevive as k}from"../../../core/runtime/revive.js";import{viewSocketPath as l}from"../../../core/canvas/paths.js";import{waitForBrokerViewSocket as v}from"../../../core/runtime/placement-tmux.js";import{notFound as w,usage as n}from"../../../core/errors.js";import{ownerOnly as p}from"../router.js";function h(t){if(t==null)return{resume:!0,revive:!0,wakeParked:!0};if(typeof t!="object")throw n("attach body must be a JSON object { resume?, revive?, wakeParked? }");const e=t.resume,r=t.revive,o=t.wakeParked;if(e!==void 0&&typeof e!="boolean")throw n("resume must be a boolean");if(r!==void 0&&typeof r!="boolean")throw n("revive must be a boolean");if(o!==void 0&&typeof o!="boolean")throw n("wakeParked must be a boolean");return{resume:e??!0,revive:r??!0,wakeParked:o??!0}}i(h,"parseAttachBody");async function b(t){const e=t.params.id;if(await m(e)===null)throw w(`unknown node: ${e}`,{received:e});const{resume:r,revive:o,wakeParked:f}=h(t.body);let u=!1,d=!1,s=!1;if(o){const a=await k(e,{resume:r,capacity:"refuse"},f);s=a.parked,a.parked||(u=a.result.launch!==void 0,d=a.result.resumed,await v(e))}return{status:200,body:{node_id:e,socket_path:l(e),revived:u,resumed:d,parked:s}}}i(b,"handleAttach");const F=p([{method:"POST",pattern:"/v1/nodes/:id/attach",handler:b}]);export{F as attachRoutes};
@@ -1 +1 @@
1
- var B=Object.defineProperty;var h=(e,o)=>B(e,"name",{value:o,configurable:!0});import{killBashJobObject as E,recordBashJobObject as J}from"../../../core/spaces/stop.js";import{readerFor as P}from"../reader.js";import{join as $}from"node:path";import{createFileBeneath as j,existsBeneath as m,unlinkBeneath as A}from"../../../core/spaces/open-beneath.js";import{launchAppProcess as q,appProcessSandboxed as O}from"../../../core/spaces/process.js";import{BASH_JOB_SUPERVISOR_SCRIPT as N}from"../../../core/bash-job-supervisor.js";import{resolveAdmittedHostCommand as L}from"../../../core/runtime/spawn-env.js";import{requireCurrentExecution as y}from"./broker-recovery.js";import{isSafeNodeId as T}from"../../../core/canvas/paths.js";import{contextDir as v}from"../../../core/canvas/node-agent-paths.js";import{getNode as g}from"../../../core/canvas/canvas.js";import{isBrokerLive as D}from"../../../core/runtime/model-swap.js";import{assertNotFinalized as R}from"../../../core/runtime/reopen.js";import{reviveNode as C}from"../../../core/runtime/revive.js";import{activeBackgroundBashJobs as z,bashJobPaths as k,isBashJobProcessGroupAlive as F,readJobPgid as M,readJobPgidIdentity as G,isSafeBashJobId as I,readBashNiceness as H,stopBackgroundBashJob as Z}from"../../../core/bash-jobs.js";import{ApiError as i}from"../../../api/index.js";import{notFound as U}from"../../../core/errors.js";import{freshChildNodeExecPath as V}from"../../../core/runtime/branded-host.js";function f(e){const o=e.params.id;if(o===void 0||!T(o))throw new i(400,"invalid_node_id",`invalid node id: ${JSON.stringify(o)}`);if(g(o)===null)throw U(`unknown node: ${o}`,{received:o});const d=e.params.jobId;if(d!==void 0){if(!I(d))throw new i(400,"invalid_job_id",`invalid background job id: ${JSON.stringify(d)}`);return{nodeId:o,jobId:d,dir:v(o)}}return{nodeId:o,dir:v(o)}}h(f,"requireTarget");async function X(e){const{nodeId:o,dir:t}=f(e);if(e.principal.class!=="broker"||e.principal.node!==o)throw new i(403,"permission_error","only this node\u2019s broker may start a job");const d=e.body;if(!d||typeof d!="object"||Array.isArray(d))throw new i(400,"invalid_request","job.start requires a JSON body");const a=d;y(o,a.expected_execution_id);const r=a.job_id,s=a.cwd,p=a.env;if(typeof r!="string"||!I(r)||typeof s!="string"||!p||typeof p!="object"||Array.isArray(p)||Object.entries(p).some(([c,b])=>!/^[A-Za-z_][A-Za-z0-9_]*$/.test(c)||typeof b!="string"))throw new i(400,"invalid_request","invalid job id, cwd or environment");if(!O())throw new i(400,"invalid_request","job.start is only used with the root launcher");const n=k(t,r);if(!(m(n.root,n.jobRun)||m(n.root,n.jobBg))||![n.cmdSh,n.jobLog].every(c=>m(n.root,c)))throw new i(404,"job_not_found","job was not prepared by this node");const w=$(n.dir,"job.starting");try{j(n.root,w,"")}catch(c){throw c.code==="EEXIST"?new i(409,"job_already_started","job was already started"):c}let l;try{const c=p,b=L("bash",c,s),_=g(o),S=await V();return l=await q({nodeId:o,app:_.grantee??"app:terminal",isolated:_.isolated,cwd:s,env:c,capture:!1,command:[b,"-c",N,"--",n.cmdSh,n.jobLog,n.jobExit,n.jobRun,n.jobDone,b,String(H(t)),S]}),j(n.root,n.jobPgid,String(l.pid),384),j(n.root,n.jobPgidIdentity,`launcher:${l.pid}`,384),{status:201,body:{pid:l.pid}}}catch(c){if(l!==void 0)try{await l.stop()}catch(b){throw new AggregateError([c,b],`job ${r} launched but could not be recorded or stopped`)}try{A(n.root,w)}catch(b){if(b.code!=="ENOENT")throw b}throw c}}h(X,"handleStart");function x(e){const{nodeId:o,dir:t}=f(e),d=Date.now();return{status:200,body:z(t).map(r=>{const s=M(t,r.jobId)??null;return{job_id:r.jobId,command:r.command,purpose:r.purpose,started_at:new Date(r.startedAtMs).toISOString(),elapsed_ms:Math.max(0,d-r.startedAtMs),pgid:s,pgid_alive:s!==null&&F(s,G(t,r.jobId))}})}}h(x,"handleList");async function K(e){const{nodeId:o,jobId:t,dir:d}=f(e);if(t===void 0)throw new i(400,"invalid_request","a job id is required");const a=e.query.get("foreground")==="1";if(a){if(e.principal.class!=="broker"||e.principal.node!==o)throw new i(403,"permission_error","only this node\u2019s broker may abort its foreground job");y(o,e.body?.expected_execution_id)}const r=await Z(d,t,a,o);if(r.kind==="missing")throw new i(404,"job_not_found",`no background job ${t} for ${o}`);if(r.kind==="retired")throw new i(404,"job_not_found",`background job ${t} for ${o} is no longer running`,{log_path:r.logPath});if(r.kind==="not-stoppable")throw new i(409,"job_not_stoppable",`job ${t} recorded no trusted process identity`,{log_path:r.logPath});if(a)return{status:200,body:{node_id:o,job_id:t,signaled:r.signaled}};R(o),E(t,n=>{const u=P(n,e);return u.class==="person"?u.person:u.class==="app"?u.app:u.node});const s=g(o);if(s!==null&&!D(s))try{await C(o,{resume:!0,capacity:"freeze"})}catch{}return{status:200,body:{node_id:o,job_id:t,signaled:r.signaled}}}h(K,"handleStop");function Q(e){const{nodeId:o,jobId:t,dir:d}=f(e);if(t===void 0)throw new i(400,"invalid_request","a job id is required");if(e.principal.class!=="broker"||e.principal.node!==o)throw new i(403,"permission_error","only this node\u2019s broker may record its job");const a=e.body,r=k(d,t);if(typeof a?.command!="string"||a.job_dir!==r.dir||a.log_path!==r.jobLog)throw new i(400,"invalid_request",`job.background requires command, job_dir ${r.dir} and log_path ${r.jobLog}`);if(!m(r.root,r.jobBg))throw new i(404,"job_not_found",`job ${t} of ${o} is not backgrounded`);const s=a.command;return{status:201,body:{id:J(o,t,{command:s,jobDir:r.dir,logPath:r.jobLog}).id}}}h(Q,"handleBackground");const go=[{method:"POST",pattern:"/v1/nodes/:id/jobs/:jobId/background",handler:Q},{method:"POST",pattern:"/v1/nodes/:id/jobs/start",handler:X},{method:"GET",pattern:"/v1/nodes/:id/jobs",handler:x},{method:"DELETE",pattern:"/v1/nodes/:id/jobs/:jobId",handler:K}];export{go as bashJobRoutes};
1
+ var B=Object.defineProperty;var h=(t,o)=>B(t,"name",{value:o,configurable:!0});import{killBashJobObject as E,recordBashJobObject as J}from"../../../core/spaces/stop.js";import{readerFor as P}from"../reader.js";import{join as $}from"node:path";import{createFileBeneath as w,existsBeneath as m,unlinkBeneath as A}from"../../../core/spaces/open-beneath.js";import{launchAppProcess as q,appProcessSandboxed as O}from"../../../core/spaces/process.js";import{BASH_JOB_SUPERVISOR_SCRIPT as N}from"../../../core/bash-job-supervisor.js";import{resolveAdmittedHostCommand as L}from"../../../core/runtime/spawn-env.js";import{requireCurrentExecution as _}from"./broker-recovery.js";import{isSafeNodeId as T}from"../../../core/canvas/paths.js";import{contextDir as v}from"../../../core/canvas/node-agent-paths.js";import{getNode as j}from"../../../core/canvas/canvas.js";import{isBrokerLive as D}from"../../../core/runtime/model-swap.js";import{assertNotFinalized as R}from"../../../core/runtime/reopen.js";import{reviveNode as C}from"../../../core/runtime/revive.js";import{activeBackgroundBashJobs as z,bashJobPaths as k,isBashJobProcessGroupAlive as F,readJobPgid as M,readJobPgidIdentity as G,isSafeBashJobId as I,readBashNiceness as H,stopBackgroundBashJob as Z}from"../../../core/bash-jobs.js";import{ApiError as i}from"../../../api/index.js";import{notFound as U}from"../../../core/errors.js";import{freshChildNodeExecPath as V}from"../../../core/runtime/branded-host.js";async function f(t){const o=t.params.id;if(o===void 0||!T(o))throw new i(400,"invalid_node_id",`invalid node id: ${JSON.stringify(o)}`);if(await j(o)===null)throw U(`unknown node: ${o}`,{received:o});const d=t.params.jobId;if(d!==void 0){if(!I(d))throw new i(400,"invalid_job_id",`invalid background job id: ${JSON.stringify(d)}`);return{nodeId:o,jobId:d,dir:await v(o)}}return{nodeId:o,dir:await v(o)}}h(f,"requireTarget");async function X(t){const{nodeId:o,dir:e}=await f(t);if(t.principal.class!=="broker"||t.principal.node!==o)throw new i(403,"permission_error","only this node\u2019s broker may start a job");const d=t.body;if(!d||typeof d!="object"||Array.isArray(d))throw new i(400,"invalid_request","job.start requires a JSON body");const a=d;await _(o,a.expected_execution_id);const r=a.job_id,s=a.cwd,p=a.env;if(typeof r!="string"||!I(r)||typeof s!="string"||!p||typeof p!="object"||Array.isArray(p)||Object.entries(p).some(([c,b])=>!/^[A-Za-z_][A-Za-z0-9_]*$/.test(c)||typeof b!="string"))throw new i(400,"invalid_request","invalid job id, cwd or environment");if(!O())throw new i(400,"invalid_request","job.start is only used with the root launcher");const n=k(e,r);if(!(m(n.root,n.jobRun)||m(n.root,n.jobBg))||![n.cmdSh,n.jobLog].every(c=>m(n.root,c)))throw new i(404,"job_not_found","job was not prepared by this node");const g=$(n.dir,"job.starting");try{w(n.root,g,"")}catch(c){throw c.code==="EEXIST"?new i(409,"job_already_started","job was already started"):c}let l;try{const c=p,b=L("bash",c,s),y=await j(o),S=await V();return l=await q({nodeId:o,app:y.grantee??"app:terminal",isolated:y.isolated,cwd:s,env:c,capture:!1,command:[b,"-c",N,"--",n.cmdSh,n.jobLog,n.jobExit,n.jobRun,n.jobDone,b,String(H(e)),S]}),w(n.root,n.jobPgid,String(l.pid),384),w(n.root,n.jobPgidIdentity,`launcher:${l.pid}`,384),{status:201,body:{pid:l.pid}}}catch(c){if(l!==void 0)try{await l.stop()}catch(b){throw new AggregateError([c,b],`job ${r} launched but could not be recorded or stopped`)}try{A(n.root,g)}catch(b){if(b.code!=="ENOENT")throw b}throw c}}h(X,"handleStart");async function x(t){const{nodeId:o,dir:e}=await f(t),d=Date.now();return{status:200,body:z(e).map(r=>{const s=M(e,r.jobId)??null;return{job_id:r.jobId,command:r.command,purpose:r.purpose,started_at:new Date(r.startedAtMs).toISOString(),elapsed_ms:Math.max(0,d-r.startedAtMs),pgid:s,pgid_alive:s!==null&&F(s,G(e,r.jobId))}})}}h(x,"handleList");async function K(t){const{nodeId:o,jobId:e,dir:d}=await f(t);if(e===void 0)throw new i(400,"invalid_request","a job id is required");const a=t.query.get("foreground")==="1";if(a){if(t.principal.class!=="broker"||t.principal.node!==o)throw new i(403,"permission_error","only this node\u2019s broker may abort its foreground job");await _(o,t.body?.expected_execution_id)}const r=await Z(d,e,a,o);if(r.kind==="missing")throw new i(404,"job_not_found",`no background job ${e} for ${o}`);if(r.kind==="retired")throw new i(404,"job_not_found",`background job ${e} for ${o} is no longer running`,{log_path:r.logPath});if(r.kind==="not-stoppable")throw new i(409,"job_not_stoppable",`job ${e} recorded no trusted process identity`,{log_path:r.logPath});if(a)return{status:200,body:{node_id:o,job_id:e,signaled:r.signaled}};await R(o),await E(e,async n=>{const u=await P(n,t);return u.class==="person"?u.person:u.class==="app"?u.app:u.node});const s=await j(o);if(s!==null&&!D(s))try{await C(o,{resume:!0,capacity:"freeze"})}catch{}return{status:200,body:{node_id:o,job_id:e,signaled:r.signaled}}}h(K,"handleStop");async function Q(t){const{nodeId:o,jobId:e,dir:d}=await f(t);if(e===void 0)throw new i(400,"invalid_request","a job id is required");if(t.principal.class!=="broker"||t.principal.node!==o)throw new i(403,"permission_error","only this node\u2019s broker may record its job");const a=t.body,r=k(d,e);if(typeof a?.command!="string"||a.job_dir!==r.dir||a.log_path!==r.jobLog)throw new i(400,"invalid_request",`job.background requires command, job_dir ${r.dir} and log_path ${r.jobLog}`);if(!m(r.root,r.jobBg))throw new i(404,"job_not_found",`job ${e} of ${o} is not backgrounded`);const s=a.command;return{status:201,body:{id:(await J(o,e,{command:s,jobDir:r.dir,logPath:r.jobLog})).id}}}h(Q,"handleBackground");const jo=[{method:"POST",pattern:"/v1/nodes/:id/jobs/:jobId/background",handler:Q},{method:"POST",pattern:"/v1/nodes/:id/jobs/start",handler:X},{method:"GET",pattern:"/v1/nodes/:id/jobs",handler:x},{method:"DELETE",pattern:"/v1/nodes/:id/jobs/:jobId",handler:K}];export{jo as bashJobRoutes};
@@ -1 +1 @@
1
- var c=Object.defineProperty;var p=(o,t)=>c(o,"name",{value:t,configurable:!0});import{statSync as u}from"node:fs";import{isAbsolute as f}from"node:path";import{ApiError as d}from"../../../api/index.js";import{buildOperationalEnvBase as l}from"../../../core/runtime/spawn-env.js";import{runAppCommand as w}from"../../../core/runtime/run-command.js";import{getNode as _}from"../../../core/canvas/canvas.js";import{readProfileEnvVars as b}from"../../../core/profiles/env-store.js";import{readAppEnvVars as y}from"../../../core/profiles/app-env-store.js";import{usage as i}from"../../../core/errors.js";import{appOf as h}from"../router.js";const T=60,m=600,E=256*1024;function A(o){if(typeof o!="object"||o===null||Array.isArray(o))throw i("bash requires an object body");const t=o;if(typeof t.command!="string"||t.command==="")throw i("bash requires a non-empty `command`");if(typeof t.cwd!="string"||!f(t.cwd))throw new d(404,"cwd_not_found","cwd must name an absolute directory");try{if(!u(t.cwd).isDirectory())throw new Error("not a directory")}catch{throw new d(404,"cwd_not_found",`cwd not found: ${t.cwd}`)}const r=t.timeout_s??T;if(typeof r!="number"||!Number.isFinite(r)||r<=0||r>m)throw new d(422,"invalid_timeout",`timeout_s must be greater than 0 and at most ${m}`);if(t.profile!==void 0&&typeof t.profile!="string")throw i("profile must be a string");let n;if(t.env!==void 0){if(typeof t.env!="object"||t.env===null||Array.isArray(t.env))throw i("env must be an object of string values");n={};for(const[s,a]of Object.entries(t.env)){if(typeof a!="string")throw i("env must be an object of string values");n[s]=a}}return{command:t.command,cwd:t.cwd,timeout_s:r,env:n,profile:t.profile}}p(A,"parseRequest");async function g(o){const t=A(o.body),r=h(o.principal)??"app:terminal";if(r!=="app:terminal"&&t.profile!==void 0)throw new d(403,"permission_error","app bash cannot select an owner profile");const n=r==="app:terminal"?t.profile??null:null,s=l({targetCwd:t.cwd,targetProfileId:n,skipSpawnAllow:r!=="app:terminal"}),a={...s,...y(r),...r==="app:terminal"?b(n):{},...t.env,...n===null?{}:{CRTR_PROFILE_ID:n},CRTR_ADMITTED_HOST_PATH:s.CRTR_ADMITTED_HOST_PATH},e=await(await w({app:r,...o.principal.class==="broker"?{nodeId:o.principal.node,isolated:_(o.principal.node)?.isolated===!0}:{},command:t.command,cwd:t.cwd,env:a,timeoutMs:t.timeout_s*1e3,headBytes:E})).completion;if(e.processError!==null)throw e.processError;return{status:200,body:{exit_code:e.timedOut?null:e.exitCode,signal:e.signal,stdout:e.stdout,stdout_truncated:e.stdoutTruncated,stderr:e.stderr,stderr_truncated:e.stderrTruncated,timed_out:e.timedOut,duration_ms:e.durationMs}}}p(g,"handleBash");const q=[{method:"POST",pattern:"/v1/bash",scope:"crtr:act",handler:g}];export{q as bashRoutes};
1
+ var c=Object.defineProperty;var p=(o,t)=>c(o,"name",{value:t,configurable:!0});import{statSync as u}from"node:fs";import{isAbsolute as f}from"node:path";import{ApiError as d}from"../../../api/index.js";import{buildOperationalEnvBase as l}from"../../../core/runtime/spawn-env.js";import{runAppCommand as w}from"../../../core/runtime/run-command.js";import{getNode as _}from"../../../core/canvas/canvas.js";import{readProfileEnvVars as b}from"../../../core/profiles/env-store.js";import{readAppEnvVars as y}from"../../../core/profiles/app-env-store.js";import{usage as i}from"../../../core/errors.js";import{appOf as h}from"../router.js";const T=60,m=600,E=256*1024;function A(o){if(typeof o!="object"||o===null||Array.isArray(o))throw i("bash requires an object body");const t=o;if(typeof t.command!="string"||t.command==="")throw i("bash requires a non-empty `command`");if(typeof t.cwd!="string"||!f(t.cwd))throw new d(404,"cwd_not_found","cwd must name an absolute directory");try{if(!u(t.cwd).isDirectory())throw new Error("not a directory")}catch{throw new d(404,"cwd_not_found",`cwd not found: ${t.cwd}`)}const r=t.timeout_s??T;if(typeof r!="number"||!Number.isFinite(r)||r<=0||r>m)throw new d(422,"invalid_timeout",`timeout_s must be greater than 0 and at most ${m}`);if(t.profile!==void 0&&typeof t.profile!="string")throw i("profile must be a string");let n;if(t.env!==void 0){if(typeof t.env!="object"||t.env===null||Array.isArray(t.env))throw i("env must be an object of string values");n={};for(const[a,s]of Object.entries(t.env)){if(typeof s!="string")throw i("env must be an object of string values");n[a]=s}}return{command:t.command,cwd:t.cwd,timeout_s:r,env:n,profile:t.profile}}p(A,"parseRequest");async function g(o){const t=A(o.body),r=h(o.principal)??"app:terminal";if(r!=="app:terminal"&&t.profile!==void 0)throw new d(403,"permission_error","app bash cannot select an owner profile");const n=r==="app:terminal"?t.profile??null:null,a=l({targetCwd:t.cwd,targetProfileId:n,skipSpawnAllow:r!=="app:terminal"}),s={...a,...y(r),...r==="app:terminal"?b(n):{},...t.env,...n===null?{}:{CRTR_PROFILE_ID:n},CRTR_ADMITTED_HOST_PATH:a.CRTR_ADMITTED_HOST_PATH},e=await(await w({app:r,...o.principal.class==="broker"?{nodeId:o.principal.node,isolated:(await _(o.principal.node))?.isolated===!0}:{},command:t.command,cwd:t.cwd,env:s,timeoutMs:t.timeout_s*1e3,headBytes:E})).completion;if(e.processError!==null)throw e.processError;return{status:200,body:{exit_code:e.timedOut?null:e.exitCode,signal:e.signal,stdout:e.stdout,stdout_truncated:e.stdoutTruncated,stderr:e.stderr,stderr_truncated:e.stderrTruncated,timed_out:e.timedOut,duration_ms:e.durationMs}}}p(g,"handleBash");const q=[{method:"POST",pattern:"/v1/bash",scope:"crtr:act",handler:g}];export{q as bashRoutes};
@@ -1,5 +1,5 @@
1
1
  import type { BrokerExtensionNodeDTO } from '../../../api/dto/broker-ops.js';
2
2
  import { getNode } from '../../../core/canvas/canvas.js';
3
3
  import { type RouteTable } from '../router.js';
4
- export declare function extensionNode(node: NonNullable<ReturnType<typeof getNode>>): BrokerExtensionNodeDTO;
4
+ export declare function extensionNode(node: NonNullable<Awaited<ReturnType<typeof getNode>>>): Promise<BrokerExtensionNodeDTO>;
5
5
  export declare const brokerOperationRoutes: RouteTable;
@@ -1 +1 @@
1
- var A=Object.defineProperty;var i=(e,t)=>A(e,"name",{value:t,configurable:!0});import{canonicalSessionFile as F,findNodeBySessionFile as O,getNode as y,isWarmSpare as R,listNodeIdentities as T,recordRespawnAttempt as I,recordSettledTurn as $,setPresence as b,subscriptionsOf as j,updateNode as g,updateNodeTelemetry as C}from"../../../core/canvas/canvas.js";import{recordExecutionPid as q}from"../../../core/canvas/executions.js";import{bindSession as E,readLiveSession as M,transferSession as L}from"../../../core/canvas/sessions.js";import{isSafeNodeId as D}from"../../../core/canvas/paths.js";import{appForNode as G}from"../../../core/canvas/node-agent-paths.js";import{isPidAlive as J}from"../../../core/canvas/pid.js";import{editorLabel as P}from"../../../core/canvas/labels.js";import{assembleNodeSubject as W}from"../../../core/substrate/subject.js";import{withCanvasWrite as l}from"../../../core/canvas/db.js";import{notFound as v,usage as a}from"../../../core/errors.js";import{hasUnseenWakeMail as N}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as U}from"../../../core/runtime/kickoff.js";import{readRoadmap as V}from"../../../core/runtime/roadmap.js";import{forkSourceNode as Y}from"../../../core/runtime/nodes.js";import{transition as _}from"../../../core/runtime/lifecycle.js";import{focusOf as k,tearDownNode as x}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as z}from"../viewer-presence.js";import{evaluateStop as H}from"../../../core/runtime/stop-guard.js";import{clearFault as h,recordFault as K}from"../../../core/canvas/recovery.js";import{updateModelRecipe as Q}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as X}from"../../review/finish.js";import{emitEvent as Z}from"../../../core/events/emit.js";import{consumePendingPark as ee,recordPendingParkActivity as te}from"../../park-pending.js";import{shouldParkAfterSummary as ne}from"../../park-activity.js";import{ownerOnly as oe}from"../router.js";import{requireCurrentExecution as m}from"./broker-recovery.js";import{ensureRunObserver as re}from"../../runs/observer.js";import{parseNodeTelemetryRecord as ie,writeNodeTelemetryRecord as se}from"./telemetry-record.js";function p(e,t){if(typeof e!="object"||e===null||Array.isArray(e))throw a(`${t} requires a JSON body`);return e}i(p,"objectBody");function ae(e){const t=p(e,"broker session-bound");if(typeof t.executionId!="string"||t.executionId==="")throw a("executionId must be a non-empty string");if(typeof t.piSessionId!="string"||t.piSessionId==="")throw a("piSessionId must be a non-empty string");if(t.sessionFile!==null&&typeof t.sessionFile!="string")throw a("sessionFile must be a string or null");if(!Number.isSafeInteger(t.pid)||t.pid<=0)throw a("pid must be a positive safe integer");if(t.reason!==null&&typeof t.reason!="string")throw a("reason must be a string or null");if(!Array.isArray(t.reviewBoundaryIds)||!t.reviewBoundaryIds.every(n=>typeof n=="string"))throw a("reviewBoundaryIds must be an array of strings");return t}i(ae,"parseSessionBoundBody");function de(e){const t=p(e,"broker settle");if(typeof t.stopReason!="string")throw a("stopReason must be a string");for(const n of["backgroundJobsRunning","pushedFinal"])if(typeof t[n]!="boolean")throw a(`${n} must be a boolean`);return t}i(de,"parseSettleBody");function ue(e){const t=p(e,"broker park-complete");if(t.outcome!=="completed"&&t.outcome!=="failed")throw a("outcome must be completed or failed");return t}i(ue,"parseParkCompleteBody");function ce(e){const t=p(e,"broker telemetry");if(typeof t.expected_execution_id!="string"||t.expected_execution_id==="")throw a("expected_execution_id must be a non-empty string");const n=ie(t);return{...n,expected_execution_id:t.expected_execution_id,updated_at:new Date(n.updated_at).toISOString()}}i(ce,"parseTelemetryBody");function le(e){const t=p(e,"broker model");if(typeof t.spec!="string"||t.spec.trim()==="")throw a("spec must be a non-empty string");const n=t.intent;if(n!==void 0){const r=n!==null&&typeof n=="object"?n:void 0;if(r===void 0||typeof r.family!="string"||r.family===""||!["ultra","strong","medium","light"].includes(r.strength))throw a("intent must be { family, strength } with strength ultra|strong|medium|light when present")}if(typeof t.userSelected!="boolean")throw a("userSelected must be a boolean");return t}i(le,"parseModelCommitBody");function f(e){const t=y(e);if(t===null)throw v(`unknown node: ${e}`,{received:e});return t}i(f,"requireNode");function w(e){return{node_id:e.node_id,grantee:G(e.node_id),name:e.name,...e.description===void 0?{}:{description:e.description},...e.title===void 0?{}:{title:e.title},...e.icon===void 0?{}:{icon:e.icon},kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,parent:e.parent??null,fork_from:e.fork_from??null,profile_id:e.profile_id??null,...e.managed_worktree===void 0?{}:{managed_worktree:e.managed_worktree===null?null:{state:e.managed_worktree.state,...e.managed_worktree.cleanup===void 0?{}:{cleanup:e.managed_worktree.cleanup},path:e.managed_worktree.path,branch:e.managed_worktree.branch,base_ref:e.managed_worktree.base_ref,base_sha:e.managed_worktree.base_sha}},...e.review_binding===void 0?{}:{review_binding:e.review_binding??null},intent:e.intent??null,...e.persona_ack===void 0?{}:{persona_ack:e.persona_ack},created:e.created}}i(w,"extensionNode");function pe(e){const t=f(e),n=[],r=new Set([e]);let o=t.parent??null;for(;o!==null&&o!==""&&!r.has(o);){r.add(o);const c=y(o);if(c===null)break;n.unshift(w(c)),o=c.parent??null}const s=j(e).map(c=>y(c.node_id)).filter(c=>c!==null&&c.kind!=="human").sort((c,S)=>c.status===S.status?0:c.status==="active"?-1:S.status==="active"?1:0).map(w),u=typeof t.fork_source_file=="string"?Y(t.fork_source_file):null,d=W(e);if(d===null)throw v(`unknown node: ${e}`,{received:e});return{node:w(t),warm_spare:R(e),ancestors:n,children:s,fork_source:u===null?null:w(u),subject:d,report_nodes:T(),roadmap:V(e)}}i(pe,"extensionState");function B(e,t){return e?.kind===t.kind&&e?.mode===t.mode&&e?.lifecycle===t.lifecycle}i(B,"samePersona");function me(e){const t=p(e,"broker generated-name");if(t.kind!=="initial"&&t.kind!=="recap")throw a("kind must be initial or recap");if(typeof t.description!="string"||typeof t.title!="string"||typeof t.icon!="string")throw a("description, title, and icon must be strings");if(t.kind==="initial")return t;const n=t.expected;if(typeof n!="object"||n===null||Array.isArray(n)||["name","description","title","icon","kind"].some(r=>typeof n[r]!="string"))throw a("recap expected must contain name, description, title, icon, and kind strings");return t}i(me,"parseGeneratedNameBody");function fe(e){const t=p(e,"broker persona-ack"),n=i(r=>{const o=t[r];if(typeof o!="object"||o===null||Array.isArray(o)||typeof o.kind!="string"||o.mode!=="base"&&o.mode!=="orchestrator"||o.lifecycle!=="terminal"&&o.lifecycle!=="resident")throw a(`${r} must be a persona state`);return o},"parse");return{expected_execution_id:t.expected_execution_id,from:n("from"),to:n("to")}}i(fe,"parsePersonaAckBody");function he(e){const t=e.params.id,n=ae(e.body),r=n.sessionFile===null?null:F(n.sessionFile);return{status:200,body:l(()=>{const s=f(t);if(q(n.executionId,t,n.pid)==="shutdown")return{action:"shutdown"};const u=s.review_binding?.review_id;if(u!==void 0&&!n.reviewBoundaryIds.includes(u))return{action:"shutdown"};if(n.reason==="new"&&s.parent==null)return{action:"relaunch_root"};if(n.reason!=="new"&&s.fork_from!=null&&s.pi_session_id==null&&r===null)return{action:"shutdown"};const d=r===null?null:O(r);if(d!==null&&d.node_id!==t){if(J(d.pi_pid))return K(t,{link:"daemon\u2192node",op:"session-file-ownership",kind:"protocol",retry:{disposition:"fatal"},message:`refusing to bind ${r}: it is owned by live node ${d.node_id}`}),{action:"shutdown"};const c=M(d.node_id);if(c===null||L({fromNodeId:d.node_id,fromBindingId:c.bindingId,toNodeId:t,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:r})!=="transferred")return{action:"shutdown"}}else if(E(t,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:r})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(U(t),s.intent==="refresh"&&_(t,"revive")),{action:"none"}})}}i(he,"handleSessionBound");function ye(e,t){const n=y(e);if(n===null){if(t.pushedFinal)return{action:"shutdown"};throw v(`unknown node: ${e}`,{received:e})}if($(e,new Date().toISOString()),(t.stopReason==="stop"||t.stopReason==="length")&&I(e,{failures:0,notBefore:null}),t.stopReason==="quit")return(n.status==="active"||n.status==="idle")&&n.intent===null&&(_(e,"finish"),h(e),k(e)!==null&&x(e),b(e,{pane:null,tmux_session:null,window:null})),{action:"shutdown"};if(t.stopReason!=="stop"&&t.stopReason!=="length")return h(e,{link:"daemon\u2192node"}),n.intent==="refresh"?{action:"shutdown"}:{action:"stay_dormant"};const r={pushedFinal:t.pushedFinal};if(r.pushedFinal||n.status==="done")return h(e),k(e)!==null&&x(e),b(e,{pane:null,tmux_session:null,window:null}),{action:"shutdown"};if(n.intent==="refresh")return h(e),{action:"shutdown"};const o=H(e,r,t.backgroundJobsRunning);return h(e),o.action==="reprompt"?{action:"reprompt",prompt:o.message}:o.reason==="finished"?N(e)?{action:"stay_dormant"}:{action:"shutdown"}:o.reason!=="awaiting"&&o.reason!=="scheduled"?{action:"stay_dormant"}:k(e)!==null||z(e)||N(e)?{action:"stay_dormant"}:(_(e,"release"),{action:"shutdown"})}i(ye,"settleBroker");function _e(e){const t=e.params.id,n=de(e.body);m(t,n.expected_execution_id);const r=l(()=>ye(t,n));return r.action!=="reprompt"&&X(t),{status:200,body:r}}i(_e,"handleSettle");function ke(e){const t=e.params.id,n=ue(e.body);return m(t,n.expected_execution_id),{status:200,body:l(()=>{const o=ee(t);if(o===void 0)return{action:"stay_dormant"};const s=f(t);return ne(t,s,o)?(h(t),_(t,"park"),k(t)!==null&&x(t),b(t,{pane:null,tmux_session:null,window:null}),Z({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...D(t)?{node_id:t}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}})}}i(ke,"handleParkComplete");function we(e){const t=e.params.id;return m(t,p(e.body,"broker park-activity").expected_execution_id),{status:200,body:l(()=>({activity:te(t)?"recorded":"none"}))}}i(we,"handleParkActivity");function be(e){const t=e.params.id,n=ce(e.body);return m(t,n.expected_execution_id),l(()=>{C(t,{tokensIn:n.tokens_in,contextTokens:n.context_tokens,lastActivity:n.last_activity,updatedAt:n.updated_at}),se(t,n)}),{status:204}}i(be,"handleTelemetry");function ge(e){const t=e.params.id,n=le(e.body);return m(t,n.expected_execution_id),{status:200,body:{modelOverride:l(()=>Q(f(t),n.spec,n.intent,n.userSelected)).model_override}}}i(ge,"handleModelCommit");function ve(e){const t=e.params.id,n=f(t);return n.run_id&&re(t,n.run_id),{status:200,body:pe(t)}}i(ve,"handleExtensionState");function xe(e){const t=e.params.id,n=me(e.body);return m(t,n.expected_execution_id),{status:200,body:l(()=>{const o=f(t);if(n.kind==="initial"){if((o.description??"").trim()!=="")return{applied:!1};const d=g(t,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:P(d),description:d.description??"",title:d.title??"",icon:d.icon??""}}const s=n.expected;if(o.name!==s.name||(o.description??"")!==s.description||(o.title??"")!==s.title||(o.icon??"")!==s.icon||o.kind!==s.kind)return{applied:!1};const u=g(t,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:P(u),description:u.description??"",title:u.title??"",icon:u.icon??""}})}}i(xe,"handleGeneratedName");function Se(e){const t=e.params.id,n=fe(e.body);return m(t,n.expected_execution_id),{status:200,body:l(()=>{const o=f(t),s={kind:o.kind,mode:o.mode,lifecycle:o.lifecycle},u=o.persona_ack,d=u===void 0?s:{kind:u.kind??o.kind,mode:u.mode,lifecycle:u.lifecycle};return!B(s,n.to)||!B(d,n.from)?{applied:!1}:(g(t,{persona_ack:n.to}),{applied:!0})})}}i(Se,"handlePersonaAck");const et=oe([{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:he},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:_e},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:ke},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:we},{method:"POST",pattern:"/v1/nodes/:id/broker/telemetry",handler:be},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:ge},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:ve},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:xe},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:Se}]);export{et as brokerOperationRoutes,w as extensionNode};
1
+ var F=Object.defineProperty;var r=(e,t)=>F(e,"name",{value:t,configurable:!0});import{canonicalSessionFile as O,findNodeBySessionFile as R,getNode as y,isWarmSpare as T,listNodeIdentities as I,recordRespawnAttempt as $,recordSettledTurn as j,setPresence as b,subscriptionsOf as C,updateNode as g,updateNodeTelemetry as q}from"../../../core/canvas/canvas.js";import{recordExecutionPid as E}from"../../../core/canvas/executions.js";import{bindSession as M,readLiveSession as L,transferSession as D}from"../../../core/canvas/sessions.js";import{isSafeNodeId as G}from"../../../core/canvas/paths.js";import{appForNode as J}from"../../../core/canvas/node-agent-paths.js";import{isPidAlive as W}from"../../../core/canvas/pid.js";import{editorLabel as P}from"../../../core/canvas/labels.js";import{assembleNodeSubject as U}from"../../../core/substrate/subject.js";import{withCanvasWrite as l}from"../../../core/canvas/db.js";import{notFound as v,usage as s}from"../../../core/errors.js";import{hasUnseenWakeMail as N}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as V}from"../../../core/runtime/kickoff.js";import{readRoadmap as Y}from"../../../core/runtime/roadmap.js";import{forkSourceNode as z}from"../../../core/runtime/nodes.js";import{transition as h}from"../../../core/runtime/lifecycle.js";import{focusOf as _,tearDownNode as x}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as H}from"../viewer-presence.js";import{evaluateStop as K}from"../../../core/runtime/stop-guard.js";import{clearFault as w,recordFault as Q}from"../../../core/canvas/recovery.js";import{updateModelRecipe as X}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as Z}from"../../review/finish.js";import{emitEvent as ee}from"../../../core/events/emit.js";import{consumePendingPark as te,recordPendingParkActivity as ne}from"../../park-pending.js";import{shouldParkAfterSummary as ie}from"../../park-activity.js";import{ownerOnly as oe}from"../router.js";import{requireCurrentExecution as m}from"./broker-recovery.js";import{ensureRunObserver as re}from"../../runs/observer.js";import{parseNodeTelemetryRecord as ae,writeNodeTelemetryRecord as se}from"./telemetry-record.js";import{mapAsync as A}from"../../../core/async-array.js";function p(e,t){if(typeof e!="object"||e===null||Array.isArray(e))throw s(`${t} requires a JSON body`);return e}r(p,"objectBody");function de(e){const t=p(e,"broker session-bound");if(typeof t.executionId!="string"||t.executionId==="")throw s("executionId must be a non-empty string");if(typeof t.piSessionId!="string"||t.piSessionId==="")throw s("piSessionId must be a non-empty string");if(t.sessionFile!==null&&typeof t.sessionFile!="string")throw s("sessionFile must be a string or null");if(!Number.isSafeInteger(t.pid)||t.pid<=0)throw s("pid must be a positive safe integer");if(t.reason!==null&&typeof t.reason!="string")throw s("reason must be a string or null");if(!Array.isArray(t.reviewBoundaryIds)||!t.reviewBoundaryIds.every(n=>typeof n=="string"))throw s("reviewBoundaryIds must be an array of strings");return t}r(de,"parseSessionBoundBody");function ce(e){const t=p(e,"broker settle");if(typeof t.stopReason!="string")throw s("stopReason must be a string");for(const n of["backgroundJobsRunning","pushedFinal"])if(typeof t[n]!="boolean")throw s(`${n} must be a boolean`);return t}r(ce,"parseSettleBody");function ue(e){const t=p(e,"broker park-complete");if(t.outcome!=="completed"&&t.outcome!=="failed")throw s("outcome must be completed or failed");return t}r(ue,"parseParkCompleteBody");function le(e){const t=p(e,"broker telemetry");if(typeof t.expected_execution_id!="string"||t.expected_execution_id==="")throw s("expected_execution_id must be a non-empty string");const n=ae(t);return{...n,expected_execution_id:t.expected_execution_id,updated_at:new Date(n.updated_at).toISOString()}}r(le,"parseTelemetryBody");function pe(e){const t=p(e,"broker model");if(typeof t.spec!="string"||t.spec.trim()==="")throw s("spec must be a non-empty string");const n=t.intent;if(n!==void 0){const o=n!==null&&typeof n=="object"?n:void 0;if(o===void 0||typeof o.family!="string"||o.family===""||!["ultra","strong","medium","light"].includes(o.strength))throw s("intent must be { family, strength } with strength ultra|strong|medium|light when present")}if(typeof t.userSelected!="boolean")throw s("userSelected must be a boolean");return t}r(pe,"parseModelCommitBody");async function f(e){const t=await y(e);if(t===null)throw v(`unknown node: ${e}`,{received:e});return t}r(f,"requireNode");async function k(e){return{node_id:e.node_id,grantee:await J(e.node_id),name:e.name,...e.description===void 0?{}:{description:e.description},...e.title===void 0?{}:{title:e.title},...e.icon===void 0?{}:{icon:e.icon},kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,parent:e.parent??null,fork_from:e.fork_from??null,profile_id:e.profile_id??null,...e.managed_worktree===void 0?{}:{managed_worktree:e.managed_worktree===null?null:{state:e.managed_worktree.state,...e.managed_worktree.cleanup===void 0?{}:{cleanup:e.managed_worktree.cleanup},path:e.managed_worktree.path,branch:e.managed_worktree.branch,base_ref:e.managed_worktree.base_ref,base_sha:e.managed_worktree.base_sha}},...e.review_binding===void 0?{}:{review_binding:e.review_binding??null},intent:e.intent??null,...e.persona_ack===void 0?{}:{persona_ack:e.persona_ack},created:e.created}}r(k,"extensionNode");async function me(e){const t=await f(e),n=[],o=new Set([e]);let i=t.parent??null;for(;i!==null&&i!==""&&!o.has(i);){o.add(i);const u=await y(i);if(u===null)break;n.unshift(await k(u)),i=u.parent??null}const a=await A((await A(await C(e),async u=>await y(u.node_id))).filter(u=>u!==null&&u.kind!=="human").sort((u,S)=>u.status===S.status?0:u.status==="active"?-1:S.status==="active"?1:0),k),c=typeof t.fork_source_file=="string"?await z(t.fork_source_file):null,d=await U(e);if(d===null)throw v(`unknown node: ${e}`,{received:e});return{node:await k(t),warm_spare:await T(e),ancestors:n,children:a,fork_source:c===null?null:await k(c),subject:d,report_nodes:await I(),roadmap:await Y(e)}}r(me,"extensionState");function B(e,t){return e?.kind===t.kind&&e?.mode===t.mode&&e?.lifecycle===t.lifecycle}r(B,"samePersona");function fe(e){const t=p(e,"broker generated-name");if(t.kind!=="initial"&&t.kind!=="recap")throw s("kind must be initial or recap");if(typeof t.description!="string"||typeof t.title!="string"||typeof t.icon!="string")throw s("description, title, and icon must be strings");if(t.kind==="initial")return t;const n=t.expected;if(typeof n!="object"||n===null||Array.isArray(n)||["name","description","title","icon","kind"].some(o=>typeof n[o]!="string"))throw s("recap expected must contain name, description, title, icon, and kind strings");return t}r(fe,"parseGeneratedNameBody");function we(e){const t=p(e,"broker persona-ack"),n=r(o=>{const i=t[o];if(typeof i!="object"||i===null||Array.isArray(i)||typeof i.kind!="string"||i.mode!=="base"&&i.mode!=="orchestrator"||i.lifecycle!=="terminal"&&i.lifecycle!=="resident")throw s(`${o} must be a persona state`);return i},"parse");return{expected_execution_id:t.expected_execution_id,from:n("from"),to:n("to")}}r(we,"parsePersonaAckBody");async function ye(e){const t=e.params.id,n=de(e.body),o=n.sessionFile===null?null:O(n.sessionFile);return{status:200,body:await l(async()=>{const a=await f(t);if(await E(n.executionId,t,n.pid)==="shutdown")return{action:"shutdown"};const c=a.review_binding?.review_id;if(c!==void 0&&!n.reviewBoundaryIds.includes(c))return{action:"shutdown"};if(n.reason==="new"&&a.parent==null)return{action:"relaunch_root"};if(n.reason!=="new"&&a.fork_from!=null&&a.pi_session_id==null&&o===null)return{action:"shutdown"};const d=o===null?null:await R(o);if(d!==null&&d.node_id!==t){if(W(d.pi_pid))return await Q(t,{link:"daemon\u2192node",op:"session-file-ownership",kind:"protocol",retry:{disposition:"fatal"},message:`refusing to bind ${o}: it is owned by live node ${d.node_id}`}),{action:"shutdown"};const u=await L(d.node_id);if(u===null||await D({fromNodeId:d.node_id,fromBindingId:u.bindingId,toNodeId:t,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:o})!=="transferred")return{action:"shutdown"}}else if(await M(t,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:o})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(await V(t),a.intent==="refresh"&&await h(t,"revive")),{action:"none"}})}}r(ye,"handleSessionBound");async function he(e,t){const n=await y(e);if(n===null){if(t.pushedFinal)return{action:"shutdown"};throw v(`unknown node: ${e}`,{received:e})}if(await j(e,new Date().toISOString()),(t.stopReason==="stop"||t.stopReason==="length")&&await $(e,{failures:0,notBefore:null}),t.stopReason==="quit")return(n.status==="active"||n.status==="idle")&&n.intent===null&&(await h(e,"finish"),await w(e),await _(e)!==null&&await x(e),await b(e,{pane:null,tmux_session:null,window:null})),{action:"shutdown"};if(t.stopReason!=="stop"&&t.stopReason!=="length")return await w(e,{link:"daemon\u2192node"}),n.intent==="refresh"?{action:"shutdown"}:{action:"stay_dormant"};const o={pushedFinal:t.pushedFinal};if(o.pushedFinal||n.status==="done")return await w(e),await _(e)!==null&&await x(e),await b(e,{pane:null,tmux_session:null,window:null}),{action:"shutdown"};if(n.intent==="refresh")return await w(e),{action:"shutdown"};const i=await K(e,o,t.backgroundJobsRunning);return await w(e),i.action==="reprompt"?{action:"reprompt",prompt:i.message}:i.reason==="finished"?await N(e)?{action:"stay_dormant"}:{action:"shutdown"}:i.reason!=="awaiting"&&i.reason!=="scheduled"?{action:"stay_dormant"}:await _(e)!==null||H(e)||await N(e)?{action:"stay_dormant"}:(await h(e,"release"),{action:"shutdown"})}r(he,"settleBroker");async function _e(e){const t=e.params.id,n=ce(e.body);await m(t,n.expected_execution_id);const o=await l(async()=>await he(t,n));return o.action!=="reprompt"&&Z(t),{status:200,body:o}}r(_e,"handleSettle");async function ke(e){const t=e.params.id,n=ue(e.body);return await m(t,n.expected_execution_id),{status:200,body:await l(async()=>{const i=te(t);if(i===void 0)return{action:"stay_dormant"};const a=await f(t);return await ie(t,a,i)?(await w(t),await h(t,"park"),await _(t)!==null&&await x(t),await b(t,{pane:null,tmux_session:null,window:null}),ee({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...G(t)?{node_id:t}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}})}}r(ke,"handleParkComplete");async function be(e){const t=e.params.id;return await m(t,p(e.body,"broker park-activity").expected_execution_id),{status:200,body:await l(async()=>({activity:ne(t)?"recorded":"none"}))}}r(be,"handleParkActivity");async function ge(e){const t=e.params.id,n=le(e.body);return await m(t,n.expected_execution_id),await l(async()=>{await q(t,{tokensIn:n.tokens_in,contextTokens:n.context_tokens,lastActivity:n.last_activity,updatedAt:n.updated_at}),se(t,n)}),{status:204}}r(ge,"handleTelemetry");async function ve(e){const t=e.params.id,n=pe(e.body);return await m(t,n.expected_execution_id),{status:200,body:{modelOverride:(await l(async()=>await X(await f(t),n.spec,n.intent,n.userSelected))).model_override}}}r(ve,"handleModelCommit");async function xe(e){const t=e.params.id,n=await f(t);return n.run_id&&await re(t,n.run_id),{status:200,body:await me(t)}}r(xe,"handleExtensionState");async function Se(e){const t=e.params.id,n=fe(e.body);return await m(t,n.expected_execution_id),{status:200,body:await l(async()=>{const i=await f(t);if(n.kind==="initial"){if((i.description??"").trim()!=="")return{applied:!1};const d=await g(t,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:P(d),description:d.description??"",title:d.title??"",icon:d.icon??""}}const a=n.expected;if(i.name!==a.name||(i.description??"")!==a.description||(i.title??"")!==a.title||(i.icon??"")!==a.icon||i.kind!==a.kind)return{applied:!1};const c=await g(t,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:P(c),description:c.description??"",title:c.title??"",icon:c.icon??""}})}}r(Se,"handleGeneratedName");async function Pe(e){const t=e.params.id,n=we(e.body);return await m(t,n.expected_execution_id),{status:200,body:await l(async()=>{const i=await f(t),a={kind:i.kind,mode:i.mode,lifecycle:i.lifecycle},c=i.persona_ack,d=c===void 0?a:{kind:c.kind??i.kind,mode:c.mode,lifecycle:c.lifecycle};return!B(a,n.to)||!B(d,n.from)?{applied:!1}:(await g(t,{persona_ack:n.to}),{applied:!0})})}}r(Pe,"handlePersonaAck");const nt=oe([{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:ye},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:_e},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:ke},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:be},{method:"POST",pattern:"/v1/nodes/:id/broker/telemetry",handler:ge},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:ve},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:xe},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:Se},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:Pe}]);export{nt as brokerOperationRoutes,k as extensionNode};
@@ -1,4 +1,4 @@
1
1
  import { type RouteTable } from '../router.js';
2
- export declare function requireCurrentExecution(nodeId: string, expectedExecutionId: unknown): void;
2
+ export declare function requireCurrentExecution(nodeId: string, expectedExecutionId: unknown): Promise<void>;
3
3
  export declare const brokerRecoveryRoutes: RouteTable;
4
4
  export declare const nodeFaultRoutes: RouteTable;
@@ -1 +1 @@
1
- var w=Object.defineProperty;var i=(r,e)=>w(r,"name",{value:e,configurable:!0});import{ApiError as E}from"../../../api/errors.js";import{getNode as I}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as S}from"../../../core/canvas/executions.js";import{admitEpisode as T,clearEpisode as q,clearFault as h,closeTurn as P,invalidateEpisode as R,openTurn as v,parseProviderError as F,readEpisode as A,readFault as l,recordFault as b,recordPendingEpisode as N,recordTransportPoisonVerdict as O,recordTurnProgress as j,reopenEpisode as L}from"../../../core/canvas/recovery.js";import{notFound as D,usage as n}from"../../../core/errors.js";import{hasPresentedViewer as B}from"../viewer-presence.js";import{ownerOnly as g}from"../router.js";const f=new Set(["pi\u2192provider","viewer\u2194broker","relay\u2194broker","viewer\u2194crtrd","daemon\u2192node","crtr\u2192pi"]),$=new Set(["rate-limit","overloaded","connection","auth","protocol","context-overflow","other","wedged","model-not-found"]),C=new Set(["auto","manual","fatal"]),K=new Set(["sdk","daemon","client"]);function d(r,e){if(typeof r!="object"||r===null||Array.isArray(r))throw n(`${e} requires a JSON object`);return r}i(d,"objectBody");function a(r){if(I(r)===null)throw D(`unknown node: ${r}`,{received:r})}i(a,"requireNode");function u(r,e){if(typeof e!="string"||e==="")throw n("expected_execution_id must be a non-empty string");const t=S(r);if(t===null||t.executionId!==e)throw new E(409,"stale_execution","broker execution is no longer current")}i(u,"requireCurrentExecution");function x(r){if(typeof r!="object"||r===null||Array.isArray(r))throw n("retry must be an object");const e=r;if(!C.has(e.disposition))throw n("retry.disposition must be auto, manual, or fatal");if(e.by!==void 0&&!K.has(e.by))throw n("retry.by must be sdk, daemon, or client");for(const t of["attempt","max"])if(e[t]!==void 0&&(!Number.isSafeInteger(e[t])||e[t]<0))throw n(`retry.${t} must be a non-negative safe integer`);if(e.nextAt!==void 0&&typeof e.nextAt!="string")throw n("retry.nextAt must be a string");return e}i(x,"parseRetry");function _(r){const e=d(r,"fault input");if(!f.has(e.link))throw n("fault link is invalid");if(typeof e.op!="string"||e.op==="")throw n("fault op must be a non-empty string");if(!$.has(e.kind))throw n("fault kind is invalid");if(typeof e.message!="string")throw n("fault message must be a string");if(e.operation_id!==void 0&&(typeof e.operation_id!="string"||e.operation_id===""))throw n("operation_id must be a non-empty string");if(e.since!==void 0&&typeof e.since!="string")throw n("since must be a string");if(e.anchor_entry_id!==void 0&&(typeof e.anchor_entry_id!="string"||e.anchor_entry_id===""))throw n("anchor_entry_id must be a non-empty string");const t=e.provider_error===void 0?void 0:F(e.provider_error);if(e.provider_error!==void 0&&t===void 0)throw n("provider_error is invalid");return{...e,...t===void 0?{}:{provider_error:t},retry:x(e.retry)}}i(_,"parseFaultInput");function y(r){return{link:r.link,op:r.op,kind:r.kind,retry:r.retry,message:r.message,...r.operation_id===void 0?{}:{operation_id:r.operation_id},...r.since===void 0?{}:{since:r.since},...r.anchor_entry_id===void 0?{}:{anchorEntryId:r.anchor_entry_id},...r.provider_error===void 0?{}:{providerError:r.provider_error}}}i(y,"faultInput");function c(r){return{fault_id:r.faultId,link:r.link,op:r.op,kind:r.kind,retry:r.retry,message:r.message,since:r.since,operation_id:r.operation_id,...r.anchorEntryId===void 0?{}:{anchor_entry_id:r.anchorEntryId},...r.providerError===void 0?{}:{provider_error:r.providerError}}}i(c,"faultDto");function k(r){const e=l(r),t=A(r);return{fault:e===null?null:c(e),episode:t===null?null:{state:t.state,session_id:t.sessionId,fault:c(t.fault)}}}i(k,"recoveryState");function U(r){const e=d(r,"broker turn"),t=e.event;if(t!=="started"&&t!=="progress"&&t!=="closed"&&t!=="interrupted"&&t!=="exit-diagnostic")throw n("event is invalid");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw n("expected_execution_id must be a non-empty string");if(t==="closed"){if(e.end_reason!=="settled"&&e.end_reason!=="teardown-aborted")throw n("closed turn requires end_reason settled or teardown-aborted")}else if(e.end_reason!==void 0)throw n("end_reason is valid only for closed turns");if(t==="exit-diagnostic"){const o=d(e.exit_diagnostic,"exit_diagnostic"),s=d(o.transport_poison,"exit_diagnostic.transport_poison");if(o.schema!=="crtr.execution-exit-diagnostic/v1"||!Number.isSafeInteger(s.consecutive_passes)||s.consecutive_passes<1||!Array.isArray(s.routes)||s.routes.length===0||!s.routes.every(p=>typeof p=="string"&&p!==""))throw n("exit_diagnostic is invalid")}else if(e.exit_diagnostic!==void 0)throw n("exit_diagnostic is valid only for exit-diagnostic turns");return e}i(U,"parseTurn");function V(r){const e=r.params.id;a(e);const t=U(r.body);u(e,t.expected_execution_id);let o;switch(t.event){case"started":o=v(t.expected_execution_id,{reason:"agent-start"});break;case"interrupted":o=v(t.expected_execution_id,{reason:"prompt-unsettled"});break;case"progress":o=j(t.expected_execution_id);break;case"closed":o=P(t.expected_execution_id,{endReason:t.end_reason,viewerPresent:B(e)});break;case"exit-diagnostic":{const m=t.exit_diagnostic.transport_poison;o=O(t.expected_execution_id,{consecutivePasses:m.consecutive_passes,routes:m.routes});break}}const s=l(e)?.link;return{status:200,body:{applied:o,fault_link:s==="daemon\u2192node"||s==="pi\u2192provider"?s:null}}}i(V,"handleTurn");function Y(r){const e=d(r,"provider retry");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw n("expected_execution_id must be a non-empty string");if(!["record-pending","admit","reopen","invalidate","clear"].includes(e.op))throw n("provider retry op is invalid");if(typeof e.session_id!="string"||e.session_id==="")throw n("session_id must be a non-empty string");if(e.op==="record-pending"&&(e.input=_(e.input)),e.op==="admit"){if(typeof e.fault_id!="string"||e.fault_id==="")throw n("admit requires fault_id");e.retry=x(e.retry)}return e}i(Y,"parseProviderRetry");function G(r){const e=r.params.id;a(e);const t=Y(r.body);u(e,t.expected_execution_id);let o;switch(t.op){case"record-pending":o=N(e,{sessionId:t.session_id,input:y(t.input)})!==null;break;case"admit":o=T(e,{sessionId:t.session_id,faultId:t.fault_id,retry:t.retry});break;case"reopen":o=L(e,{sessionId:t.session_id});break;case"invalidate":o=R(e,{sessionId:t.session_id});break;case"clear":o=q(e,{sessionId:t.session_id});break}return{status:200,body:{applied:o,episode:k(e).episode}}}i(G,"handleProviderRetry");function J(r){const e=d(r,"broker fault");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw n("expected_execution_id must be a non-empty string");if(e.op!=="record"&&e.op!=="clear")throw n("fault op must be record or clear");if(e.op==="record"&&(e.input=_(e.input)),e.op==="clear"&&e.link!==void 0&&!f.has(e.link))throw n("fault link is invalid");if(e.preserve_episode!==void 0&&typeof e.preserve_episode!="boolean")throw n("preserve_episode must be boolean");return e}i(J,"parseBrokerFault");function W(r){const e=r.params.id;a(e);const t=J(r.body);u(e,t.expected_execution_id);const o=t.op==="record"?b(e,y(t.input)):(h(e,{...t.link===void 0?{}:{link:t.link},...t.preserve_episode===void 0?{}:{preserveEpisode:t.preserve_episode}}),l(e));return{status:200,body:{fault:o===null?null:c(o)}}}i(W,"handleBrokerFault");function z(r){const e=r.params.id;return a(e),u(e,r.query.get("expected_execution_id")),{status:200,body:k(e)}}i(z,"handleRecovery");function H(r){const e=r.params.id;a(e);const t=b(e,y(_(r.body)));return{status:200,body:{fault:t===null?null:c(t)}}}i(H,"handleNodeFaultRecord");function M(r){const e=r.params.id;a(e);const t=r.query.get("link");if(t!==null&&!f.has(t))throw n("fault link is invalid");const o=r.query.get("preserve_episode");if(o!==null&&o!=="true"&&o!=="false")throw n("preserve_episode must be true or false");return{status:200,body:{cleared:h(e,{...t===null?{}:{link:t},...o===null?{}:{preserveEpisode:o==="true"}})}}}i(M,"handleNodeFaultClear");const ie=g([{method:"POST",pattern:"/v1/broker/:id/turn",handler:V},{method:"POST",pattern:"/v1/broker/:id/provider-retry",handler:G},{method:"POST",pattern:"/v1/broker/:id/fault",handler:W},{method:"GET",pattern:"/v1/broker/:id/recovery",handler:z}]),se=g([{method:"POST",pattern:"/v1/nodes/:id/fault",handler:H},{method:"DELETE",pattern:"/v1/nodes/:id/fault",handler:M}]);export{ie as brokerRecoveryRoutes,se as nodeFaultRoutes,u as requireCurrentExecution};
1
+ var k=Object.defineProperty;var o=(r,e)=>k(r,"name",{value:e,configurable:!0});import{ApiError as E}from"../../../api/errors.js";import{getNode as I}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as S}from"../../../core/canvas/executions.js";import{admitEpisode as T,clearEpisode as q,clearFault as m,closeTurn as P,invalidateEpisode as R,openTurn as h,parseProviderError as F,readEpisode as A,readFault as l,recordFault as v,recordPendingEpisode as N,recordTransportPoisonVerdict as O,recordTurnProgress as j,reopenEpisode as L}from"../../../core/canvas/recovery.js";import{notFound as D,usage as n}from"../../../core/errors.js";import{hasPresentedViewer as B}from"../viewer-presence.js";import{ownerOnly as b}from"../router.js";const f=new Set(["pi\u2192provider","viewer\u2194broker","relay\u2194broker","viewer\u2194crtrd","daemon\u2192node","crtr\u2192pi"]),$=new Set(["rate-limit","overloaded","connection","auth","protocol","context-overflow","other","wedged","model-not-found"]),C=new Set(["auto","manual","fatal"]),K=new Set(["sdk","daemon","client"]);function d(r,e){if(typeof r!="object"||r===null||Array.isArray(r))throw n(`${e} requires a JSON object`);return r}o(d,"objectBody");async function a(r){if(await I(r)===null)throw D(`unknown node: ${r}`,{received:r})}o(a,"requireNode");async function c(r,e){if(typeof e!="string"||e==="")throw n("expected_execution_id must be a non-empty string");const t=await S(r);if(t===null||t.executionId!==e)throw new E(409,"stale_execution","broker execution is no longer current")}o(c,"requireCurrentExecution");function g(r){if(typeof r!="object"||r===null||Array.isArray(r))throw n("retry must be an object");const e=r;if(!C.has(e.disposition))throw n("retry.disposition must be auto, manual, or fatal");if(e.by!==void 0&&!K.has(e.by))throw n("retry.by must be sdk, daemon, or client");for(const t of["attempt","max"])if(e[t]!==void 0&&(!Number.isSafeInteger(e[t])||e[t]<0))throw n(`retry.${t} must be a non-negative safe integer`);if(e.nextAt!==void 0&&typeof e.nextAt!="string")throw n("retry.nextAt must be a string");return e}o(g,"parseRetry");function _(r){const e=d(r,"fault input");if(!f.has(e.link))throw n("fault link is invalid");if(typeof e.op!="string"||e.op==="")throw n("fault op must be a non-empty string");if(!$.has(e.kind))throw n("fault kind is invalid");if(typeof e.message!="string")throw n("fault message must be a string");if(e.operation_id!==void 0&&(typeof e.operation_id!="string"||e.operation_id===""))throw n("operation_id must be a non-empty string");if(e.since!==void 0&&typeof e.since!="string")throw n("since must be a string");if(e.anchor_entry_id!==void 0&&(typeof e.anchor_entry_id!="string"||e.anchor_entry_id===""))throw n("anchor_entry_id must be a non-empty string");const t=e.provider_error===void 0?void 0:F(e.provider_error);if(e.provider_error!==void 0&&t===void 0)throw n("provider_error is invalid");return{...e,...t===void 0?{}:{provider_error:t},retry:g(e.retry)}}o(_,"parseFaultInput");function y(r){return{link:r.link,op:r.op,kind:r.kind,retry:r.retry,message:r.message,...r.operation_id===void 0?{}:{operation_id:r.operation_id},...r.since===void 0?{}:{since:r.since},...r.anchor_entry_id===void 0?{}:{anchorEntryId:r.anchor_entry_id},...r.provider_error===void 0?{}:{providerError:r.provider_error}}}o(y,"faultInput");function u(r){return{fault_id:r.faultId,link:r.link,op:r.op,kind:r.kind,retry:r.retry,message:r.message,since:r.since,operation_id:r.operation_id,...r.anchorEntryId===void 0?{}:{anchor_entry_id:r.anchorEntryId},...r.providerError===void 0?{}:{provider_error:r.providerError}}}o(u,"faultDto");async function x(r){const e=await l(r),t=await A(r);return{fault:e===null?null:u(e),episode:t===null?null:{state:t.state,session_id:t.sessionId,fault:u(t.fault)}}}o(x,"recoveryState");function U(r){const e=d(r,"broker turn"),t=e.event;if(t!=="started"&&t!=="progress"&&t!=="closed"&&t!=="interrupted"&&t!=="exit-diagnostic")throw n("event is invalid");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw n("expected_execution_id must be a non-empty string");if(t==="closed"){if(e.end_reason!=="settled"&&e.end_reason!=="teardown-aborted")throw n("closed turn requires end_reason settled or teardown-aborted")}else if(e.end_reason!==void 0)throw n("end_reason is valid only for closed turns");if(t==="exit-diagnostic"){const i=d(e.exit_diagnostic,"exit_diagnostic"),s=d(i.transport_poison,"exit_diagnostic.transport_poison");if(i.schema!=="crtr.execution-exit-diagnostic/v1"||!Number.isSafeInteger(s.consecutive_passes)||s.consecutive_passes<1||!Array.isArray(s.routes)||s.routes.length===0||!s.routes.every(p=>typeof p=="string"&&p!==""))throw n("exit_diagnostic is invalid")}else if(e.exit_diagnostic!==void 0)throw n("exit_diagnostic is valid only for exit-diagnostic turns");return e}o(U,"parseTurn");async function V(r){const e=r.params.id;await a(e);const t=U(r.body);await c(e,t.expected_execution_id);let i;switch(t.event){case"started":i=await h(t.expected_execution_id,{reason:"agent-start"});break;case"interrupted":i=await h(t.expected_execution_id,{reason:"prompt-unsettled"});break;case"progress":i=await j(t.expected_execution_id);break;case"closed":i=await P(t.expected_execution_id,{endReason:t.end_reason,viewerPresent:B(e)});break;case"exit-diagnostic":{const w=t.exit_diagnostic.transport_poison;i=await O(t.expected_execution_id,{consecutivePasses:w.consecutive_passes,routes:w.routes});break}}const s=(await l(e))?.link;return{status:200,body:{applied:i,fault_link:s==="daemon\u2192node"||s==="pi\u2192provider"?s:null}}}o(V,"handleTurn");function Y(r){const e=d(r,"provider retry");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw n("expected_execution_id must be a non-empty string");if(!["record-pending","admit","reopen","invalidate","clear"].includes(e.op))throw n("provider retry op is invalid");if(typeof e.session_id!="string"||e.session_id==="")throw n("session_id must be a non-empty string");if(e.op==="record-pending"&&(e.input=_(e.input)),e.op==="admit"){if(typeof e.fault_id!="string"||e.fault_id==="")throw n("admit requires fault_id");e.retry=g(e.retry)}return e}o(Y,"parseProviderRetry");async function G(r){const e=r.params.id;await a(e);const t=Y(r.body);await c(e,t.expected_execution_id);let i;switch(t.op){case"record-pending":i=await N(e,{sessionId:t.session_id,input:y(t.input)})!==null;break;case"admit":i=await T(e,{sessionId:t.session_id,faultId:t.fault_id,retry:t.retry});break;case"reopen":i=await L(e,{sessionId:t.session_id});break;case"invalidate":i=await R(e,{sessionId:t.session_id});break;case"clear":i=await q(e,{sessionId:t.session_id});break}return{status:200,body:{applied:i,episode:(await x(e)).episode}}}o(G,"handleProviderRetry");function J(r){const e=d(r,"broker fault");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw n("expected_execution_id must be a non-empty string");if(e.op!=="record"&&e.op!=="clear")throw n("fault op must be record or clear");if(e.op==="record"&&(e.input=_(e.input)),e.op==="clear"&&e.link!==void 0&&!f.has(e.link))throw n("fault link is invalid");if(e.preserve_episode!==void 0&&typeof e.preserve_episode!="boolean")throw n("preserve_episode must be boolean");return e}o(J,"parseBrokerFault");async function W(r){const e=r.params.id;await a(e);const t=J(r.body);await c(e,t.expected_execution_id);const i=t.op==="record"?await v(e,y(t.input)):(await m(e,{...t.link===void 0?{}:{link:t.link},...t.preserve_episode===void 0?{}:{preserveEpisode:t.preserve_episode}}),await l(e));return{status:200,body:{fault:i===null?null:u(i)}}}o(W,"handleBrokerFault");async function z(r){const e=r.params.id;return await a(e),await c(e,r.query.get("expected_execution_id")),{status:200,body:await x(e)}}o(z,"handleRecovery");async function H(r){const e=r.params.id;await a(e);const t=await v(e,y(_(r.body)));return{status:200,body:{fault:t===null?null:u(t)}}}o(H,"handleNodeFaultRecord");async function M(r){const e=r.params.id;await a(e);const t=r.query.get("link");if(t!==null&&!f.has(t))throw n("fault link is invalid");const i=r.query.get("preserve_episode");if(i!==null&&i!=="true"&&i!=="false")throw n("preserve_episode must be true or false");return{status:200,body:{cleared:await m(e,{...t===null?{}:{link:t},...i===null?{}:{preserveEpisode:i==="true"}})}}}o(M,"handleNodeFaultClear");const oe=b([{method:"POST",pattern:"/v1/broker/:id/turn",handler:V},{method:"POST",pattern:"/v1/broker/:id/provider-retry",handler:G},{method:"POST",pattern:"/v1/broker/:id/fault",handler:W},{method:"GET",pattern:"/v1/broker/:id/recovery",handler:z}]),se=b([{method:"POST",pattern:"/v1/nodes/:id/fault",handler:H},{method:"DELETE",pattern:"/v1/nodes/:id/fault",handler:M}]);export{oe as brokerRecoveryRoutes,se as nodeFaultRoutes,c as requireCurrentExecution};
@@ -9,10 +9,10 @@ export declare class BrokerSignalStreams {
9
9
  pingMs: number;
10
10
  blockedMs: number;
11
11
  });
12
- open(nodeId: string, res: ServerResponse, hello: BrokerSignalLineDTO, req: RequestContext['req']): void;
12
+ open(nodeId: string, res: ServerResponse, hello: BrokerSignalLineDTO, req: RequestContext['req']): Promise<void>;
13
13
  /** Hint the node's broker to re-run its retry scheduling. False when no
14
14
  * broker stream is open (it resyncs on reconnect instead). */
15
- nudgeFaultRetry(nodeId: string): boolean;
15
+ nudgeFaultRetry(nodeId: string): Promise<boolean>;
16
16
  close(): void;
17
17
  }
18
18
  export declare const brokerSignalStreams: BrokerSignalStreams;
@@ -1,2 +1,2 @@
1
- var D=Object.defineProperty;var r=(l,e)=>D(l,"name",{value:e,configurable:!0});import{ApiError as M}from"../../../api/errors.js";import{getNode as b}from"../../../core/canvas/canvas.js";import{brokerSignalBus as E}from"../../broker-signals/bus.js";import{boundDaemonControl as T}from"../../control.js";import{requireCurrentExecution as v}from"./broker-recovery.js";import{extensionNode as _}from"./broker-ops.js";const R=15e3,C=3e4;class N{static{r(this,"BrokerSignalStreams")}timing;streams=new Map;constructor(e={pingMs:R,blockedMs:C}){this.timing=e}open(e,t,u,d){this.streams.get(e)?.close();let n=!1,s=!1,h=!1,g=!1,y=!1,a,m,w;const o=r((i=!1)=>{n||(n=!0,m!==void 0&&clearInterval(m),a!==void 0&&clearTimeout(a),t.off("drain",k),t.off("close",c),t.off("error",c),d.off("aborted",c),w?.(),this.streams.get(e)===S&&this.streams.delete(e),i?t.destroy():t.writableEnded||t.end())},"close"),f=r(i=>{n||s||t.write(`${JSON.stringify(i)}
2
- `)||(s=!0,a=setTimeout(()=>o(!0),this.timing.blockedMs),a.unref())},"send"),p=r(()=>{if(!(n||s)&&(h&&(h=!1,f({type:"mail",channel:"wake",at:Date.now()})),y&&!s&&(y=!1,f({type:"fault-retry",at:Date.now()})),g&&!s)){g=!1;const i=b(e);i!==null&&f({type:"node",node:_(i),at:Date.now()})}},"flush"),k=r(()=>{s=!1,a!==void 0&&clearTimeout(a),a=void 0;try{p()}catch{o()}},"drain"),c=r(()=>o(),"onClosed"),S={close:o,nudgeFaultRetry:r(()=>{if(!n){y=!0;try{p()}catch{o()}}},"nudgeFaultRetry")};this.streams.set(e,S),t.on("drain",k),t.once("close",c),t.once("error",c),w=E.subscribe((i,x)=>{if(!(i!==e||n)){x==="mail"?h=!0:g=!0;try{p()}catch{o()}}}),m=setInterval(()=>{if(!(s||n))try{f({type:"ping",at:Date.now()})}catch{o()}},this.timing.pingMs),m.unref(),d.once("aborted",c);try{f(u),p()}catch{o()}}nudgeFaultRetry(e){const t=this.streams.get(e);return t===void 0?!1:(t.nudgeFaultRetry(),!0)}close(){for(const e of[...this.streams.values()])e.close()}}const B=new N;function F(l){const e=l.params.id??"",t=b(e);if(t===null)throw new M(404,"node_not_found",`no node ${e}`);const u=l.query.get("execution_id");v(e,u);const{req:d,res:n}=l;n.writeHead(200,{"content-type":"application/x-ndjson; charset=utf-8","cache-control":"no-cache",connection:"keep-alive"});try{B.open(e,n,{type:"hello",epoch:T()?.epoch??"",execution_id:u,node:_(b(e)??t),at:Date.now()},d)}catch{n.writableEnded||n.end()}return{status:200}}r(F,"handleSignals");const J=[{method:"GET",pattern:"/v1/nodes/:id/broker/signals",handler:F}];export{N as BrokerSignalStreams,J as brokerSignalRoutes,B as brokerSignalStreams};
1
+ var D=Object.defineProperty;var r=(c,e)=>D(c,"name",{value:e,configurable:!0});import{ApiError as M}from"../../../api/errors.js";import{getNode as y}from"../../../core/canvas/canvas.js";import{brokerSignalBus as E}from"../../broker-signals/bus.js";import{boundDaemonControl as T}from"../../control.js";import{requireCurrentExecution as v}from"./broker-recovery.js";import{extensionNode as _}from"./broker-ops.js";const R=15e3,C=3e4;class N{static{r(this,"BrokerSignalStreams")}timing;streams=new Map;constructor(e={pingMs:R,blockedMs:C}){this.timing=e}async open(e,t,u,d){this.streams.get(e)?.close();let n=!1,i=!1,h=!1,w=!1,g=!1,s,m,b;const a=r((o=!1)=>{n||(n=!0,m!==void 0&&clearInterval(m),s!==void 0&&clearTimeout(s),t.off("drain",k),t.off("close",l),t.off("error",l),d.off("aborted",l),b?.(),this.streams.get(e)===S&&this.streams.delete(e),o?t.destroy():t.writableEnded||t.end())},"close"),f=r(o=>{n||i||t.write(`${JSON.stringify(o)}
2
+ `)||(i=!0,s=setTimeout(()=>a(!0),this.timing.blockedMs),s.unref())},"send"),p=r(async()=>{if(!(n||i)&&(h&&(h=!1,f({type:"mail",channel:"wake",at:Date.now()})),g&&!i&&(g=!1,f({type:"fault-retry",at:Date.now()})),w&&!i)){w=!1;const o=await y(e);o!==null&&f({type:"node",node:await _(o),at:Date.now()})}},"flush"),k=r(()=>{i=!1,s!==void 0&&clearTimeout(s),s=void 0,p().catch(()=>a())},"drain"),l=r(()=>a(),"onClosed"),S={close:a,nudgeFaultRetry:r(async()=>{if(!n){g=!0;try{await p()}catch{a()}}},"nudgeFaultRetry")};this.streams.set(e,S),t.on("drain",k),t.once("close",l),t.once("error",l),b=await E.subscribe((o,x)=>{o!==e||n||(x==="mail"?h=!0:w=!0,p().catch(()=>a()))}),m=setInterval(()=>{if(!(i||n))try{f({type:"ping",at:Date.now()})}catch{a()}},this.timing.pingMs),m.unref(),d.once("aborted",l);try{f(u),await p()}catch{a()}}async nudgeFaultRetry(e){const t=this.streams.get(e);return t===void 0?!1:(await t.nudgeFaultRetry(),!0)}close(){for(const e of[...this.streams.values()])e.close()}}const B=new N;async function F(c){const e=c.params.id??"",t=await y(e);if(t===null)throw new M(404,"node_not_found",`no node ${e}`);const u=c.query.get("execution_id");await v(e,u);const{req:d,res:n}=c;n.writeHead(200,{"content-type":"application/x-ndjson; charset=utf-8","cache-control":"no-cache",connection:"keep-alive"});try{await B.open(e,n,{type:"hello",epoch:T()?.epoch??"",execution_id:u,node:await _(await y(e)??t),at:Date.now()},d)}catch{n.writableEnded||n.end()}return{status:200}}r(F,"handleSignals");const J=[{method:"GET",pattern:"/v1/nodes/:id/broker/signals",handler:F}];export{N as BrokerSignalStreams,J as brokerSignalRoutes,B as brokerSignalStreams};
@@ -3,5 +3,5 @@ import { type HandlerResult, type RequestContext, type RouteTable } from '../rou
3
3
  * application/gzip, not HTTP content-encoding: the local socket fetch returns a
4
4
  * byte stream without automatic decompression. Build from selected columns so
5
5
  * the daemon does not materialize or serialize outcome/activity/placement. */
6
- export declare function handleBrowse(ctx: RequestContext): HandlerResult;
6
+ export declare function handleBrowse(ctx: RequestContext): Promise<HandlerResult>;
7
7
  export declare const canvasRoutes: RouteTable;