@north-light/cli 0.3.561 → 0.3.562

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 (573) hide show
  1. package/dist/api/client.d.ts +27 -4
  2. package/dist/api/client.js +3 -3
  3. package/dist/api/contract.d.ts +1 -1
  4. package/dist/api/contract.js +1 -1
  5. package/dist/api/dto/bash-jobs.d.ts +5 -1
  6. package/dist/api/dto/broker-ops.d.ts +25 -1
  7. package/dist/api/dto/charges.d.ts +9 -2
  8. package/dist/api/dto/delivery.d.ts +26 -2
  9. package/dist/api/dto/execution-start.d.ts +57 -0
  10. package/dist/api/dto/execution-start.js +0 -0
  11. package/dist/api/dto/modelauth.d.ts +5 -0
  12. package/dist/api/dto/node-records.d.ts +16 -0
  13. package/dist/api/dto/objects.d.ts +1 -1
  14. package/dist/api/dto/reports.d.ts +0 -3
  15. package/dist/api/dto/run-events.d.ts +7 -1
  16. package/dist/api/dto/settings.d.ts +55 -0
  17. package/dist/api/dto/settings.js +0 -0
  18. package/dist/api/index.d.ts +2 -0
  19. package/dist/api/index.js +1 -1
  20. package/dist/api/routes.d.ts +11 -0
  21. package/dist/api/routes.js +1 -1
  22. package/dist/builtin-memory/crouter-sdk/release-notes.md +4 -0
  23. package/dist/cli.js +7 -7
  24. package/dist/clients/attach/chrome/bash-jobs.d.ts +11 -1
  25. package/dist/clients/attach/chrome/bash-jobs.js +1 -1
  26. package/dist/clients/attach/chrome/canvas-panels.d.ts +1 -1
  27. package/dist/clients/attach/chrome/roster.js +6 -4
  28. package/dist/clients/attach/overlays/auth.js +2 -2
  29. package/dist/clients/attach/render/chat-view.js +1 -1
  30. package/dist/clients/attach/viewer.js +550 -567
  31. package/dist/commands/canvas-config.js +2 -2
  32. package/dist/commands/canvas-use.js +1 -1
  33. package/dist/commands/human.js +2 -2
  34. package/dist/commands/node/bash.js +3 -3
  35. package/dist/commands/node/create.js +2 -2
  36. package/dist/commands/person-settings.d.ts +1 -0
  37. package/dist/commands/person-settings.js +1 -0
  38. package/dist/commands/pkg/market-manage.d.ts +2 -2
  39. package/dist/commands/pkg/market-manage.js +1 -1
  40. package/dist/commands/pkg/plugin-manage.js +13 -13
  41. package/dist/commands/pkg/shared.js +1 -1
  42. package/dist/commands/profile/default.js +1 -1
  43. package/dist/commands/push.js +2 -3
  44. package/dist/commands/sys/config.js +1 -1
  45. package/dist/commands/sys/connect.js +1 -1
  46. package/dist/commands/sys/context/sysprompt.js +2 -2
  47. package/dist/commands/sys/doctor.js +1 -1
  48. package/dist/commands/sys/panels/broker-limits-panel.js +1 -1
  49. package/dist/commands/sys/panels/keybindings-panel.js +1 -1
  50. package/dist/commands/sys/panels/models-panel.d.ts +8 -2
  51. package/dist/commands/sys/panels/models-panel.js +1 -1
  52. package/dist/commands/sys/panels/prefs-panel.d.ts +1 -0
  53. package/dist/commands/sys/panels/prefs-panel.js +1 -1
  54. package/dist/commands/sys/panels/profiles-panel.js +1 -1
  55. package/dist/commands/sys/panels/provider-panel.d.ts +4 -0
  56. package/dist/commands/sys/panels/provider-panel.js +1 -1
  57. package/dist/commands/sys/provider-login.js +5 -5
  58. package/dist/commands/sys/setup-core.js +3 -3
  59. package/dist/commands/sys/setup-settings-runner.js +1 -1
  60. package/dist/commands/sys/spend.js +3 -3
  61. package/dist/commands/sys/update.js +1 -1
  62. package/dist/core/auth-file.d.ts +11 -19
  63. package/dist/core/auth-file.js +1 -2
  64. package/dist/core/auto-update.d.ts +1 -1
  65. package/dist/core/auto-update.js +4 -4
  66. package/dist/core/bash-jobs.d.ts +29 -71
  67. package/dist/core/bash-jobs.js +9 -10
  68. package/dist/core/blobs/directory.d.ts +3 -0
  69. package/dist/core/blobs/directory.js +1 -0
  70. package/dist/core/blobs/fault.d.ts +3 -0
  71. package/dist/core/blobs/fault.js +1 -0
  72. package/dist/core/blobs/index.d.ts +21 -0
  73. package/dist/core/blobs/index.js +1 -0
  74. package/dist/core/blobs/r2.d.ts +9 -0
  75. package/dist/core/blobs/r2.js +4 -0
  76. package/dist/core/bootstrap.d.ts +1 -1
  77. package/dist/core/bootstrap.js +2 -2
  78. package/dist/core/canvas/canvas.d.ts +9 -7
  79. package/dist/core/canvas/canvas.js +8 -8
  80. package/dist/core/canvas/crons.d.ts +3 -2
  81. package/dist/core/canvas/crons.js +3 -3
  82. package/dist/core/canvas/daemon-owner.d.ts +5 -0
  83. package/dist/core/canvas/daemon-owner.js +1 -1
  84. package/dist/core/canvas/db.d.ts +10 -9
  85. package/dist/core/canvas/db.js +4 -4
  86. package/dist/core/canvas/executions.d.ts +100 -4
  87. package/dist/core/canvas/executions.js +1 -1
  88. package/dist/core/canvas/export-sqlite.js +1 -1
  89. package/dist/core/canvas/focuses.d.ts +4 -0
  90. package/dist/core/canvas/focuses.js +1 -1
  91. package/dist/core/canvas/history.js +9 -9
  92. package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +2 -1
  93. package/dist/core/canvas/managed-worktree-sweep-candidates.js +3 -2
  94. package/dist/core/canvas/node-tokens.d.ts +1 -4
  95. package/dist/core/canvas/node-tokens.js +3 -3
  96. package/dist/core/canvas/paths.d.ts +0 -1
  97. package/dist/core/canvas/paths.js +1 -1
  98. package/dist/core/canvas/person-state.d.ts +26 -0
  99. package/dist/core/canvas/person-state.js +1 -0
  100. package/dist/core/canvas/person.d.ts +3 -10
  101. package/dist/core/canvas/person.js +7 -7
  102. package/dist/core/canvas/reconciler-leases.d.ts +12 -0
  103. package/dist/core/canvas/reconciler-leases.js +8 -0
  104. package/dist/core/canvas/recovery.d.ts +4 -0
  105. package/dist/core/canvas/recovery.js +1 -1
  106. package/dist/core/canvas/schema-pg/003-fleet-removals.sql +1 -1
  107. package/dist/core/canvas/schema-pg/005-fleet-blobs.sql +13 -0
  108. package/dist/core/canvas/schema-pg/006-job-rows.sql +20 -0
  109. package/dist/core/canvas/schema-pg/007-ledger-check.sql +117 -0
  110. package/dist/core/canvas/schema-version.d.ts +1 -1
  111. package/dist/core/canvas/schema-version.js +1 -1
  112. package/dist/core/canvas/sessions.d.ts +8 -11
  113. package/dist/core/canvas/sessions.js +1 -4
  114. package/dist/core/canvas/tree.d.ts +4 -2
  115. package/dist/core/canvas/tree.js +6 -6
  116. package/dist/core/canvas/types.d.ts +7 -0
  117. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  118. package/dist/core/command-plugins/bundle.d.ts +1 -1
  119. package/dist/core/command-plugins/bundle.js +1 -1
  120. package/dist/core/command-plugins/compose.d.ts +1 -1
  121. package/dist/core/command-plugins/discovery.d.ts +0 -1
  122. package/dist/core/command-plugins/discovery.js +1 -1
  123. package/dist/core/command-plugins/help-addenda.js +1 -1
  124. package/dist/core/command-plugins/presence.d.ts +2 -0
  125. package/dist/core/command-plugins/presence.js +1 -1
  126. package/dist/core/config.d.ts +16 -15
  127. package/dist/core/config.js +1 -1
  128. package/dist/core/conversation-store/client-worker.js +1 -1
  129. package/dist/core/conversation-store/client.js +2 -2
  130. package/dist/core/conversation-store/index.d.ts +9 -11
  131. package/dist/core/conversation-store/index.js +1 -1
  132. package/dist/core/conversation-store/patch.js +1 -1
  133. package/dist/core/conversation-store/row-store.d.ts +14 -0
  134. package/dist/core/conversation-store/row-store.js +13 -0
  135. package/dist/core/directory/join.js +1 -1
  136. package/dist/core/env-name.d.ts +1 -0
  137. package/dist/core/env-name.js +1 -1
  138. package/dist/core/environment-recipe.d.ts +15 -0
  139. package/dist/core/environment-recipe.js +1 -0
  140. package/dist/core/environments.js +1 -1
  141. package/dist/core/events/emit.js +2 -2
  142. package/dist/core/events/run-event-chunks.d.ts +25 -0
  143. package/dist/core/events/run-event-chunks.js +5 -0
  144. package/dist/core/feed/messages.js +5 -5
  145. package/dist/core/grants/mirror.d.ts +15 -0
  146. package/dist/core/grants/mirror.js +15 -3
  147. package/dist/core/grants/on-sync.d.ts +9 -5
  148. package/dist/core/grants/on-sync.js +1 -1
  149. package/dist/core/grants/remove.d.ts +1 -6
  150. package/dist/core/grants/remove.js +1 -1
  151. package/dist/core/grants/sync.js +1 -1
  152. package/dist/core/grants/watch.d.ts +15 -9
  153. package/dist/core/grants/watch.js +1 -1
  154. package/dist/core/graph/custom.js +8 -8
  155. package/dist/core/graph/jobs.d.ts +83 -5
  156. package/dist/core/graph/jobs.js +11 -2
  157. package/dist/core/graph/kinds/job.js +2 -2
  158. package/dist/core/graph/names.js +7 -7
  159. package/dist/core/graph/objects.d.ts +5 -1
  160. package/dist/core/graph/objects.js +11 -11
  161. package/dist/core/graph/reader.d.ts +3 -0
  162. package/dist/core/graph/reader.js +3 -3
  163. package/dist/core/graph/repo-sync/identity.d.ts +3 -1
  164. package/dist/core/graph/repo-sync/identity.js +1 -1
  165. package/dist/core/graph/repo-sync/repos.d.ts +1 -1
  166. package/dist/core/graph/repo-sync/repos.js +2 -2
  167. package/dist/core/graph/repo-sync/sync.js +2 -2
  168. package/dist/core/installed-plugins.js +1 -1
  169. package/dist/core/keybindings/persistence.d.ts +1 -1
  170. package/dist/core/keybindings/persistence.js +1 -1
  171. package/dist/core/layout-migrate/loose-keys.d.ts +1 -1
  172. package/dist/core/layout-migrate/loose-keys.js +1 -1
  173. package/dist/core/ledger/account.d.ts +12 -0
  174. package/dist/core/ledger/account.js +2 -0
  175. package/dist/core/ledger/charges.d.ts +2 -2
  176. package/dist/core/ledger/charges.js +1 -1
  177. package/dist/core/ledger/check.d.ts +5 -1
  178. package/dist/core/ledger/check.js +1 -7
  179. package/dist/core/ledger/chunks.d.ts +8 -0
  180. package/dist/core/ledger/chunks.js +2 -0
  181. package/dist/core/ledger/index.d.ts +2 -1
  182. package/dist/core/ledger/index.js +1 -1
  183. package/dist/core/ledger/infra-allowance.d.ts +9 -0
  184. package/dist/core/ledger/infra-allowance.js +1 -0
  185. package/dist/core/ledger/limits.js +3 -3
  186. package/dist/core/ledger/payer.d.ts +1 -1
  187. package/dist/core/ledger/payer.js +1 -1
  188. package/dist/core/ledger/read.d.ts +14 -4
  189. package/dist/core/ledger/read.js +2 -3
  190. package/dist/core/ledger/totals.d.ts +5 -16
  191. package/dist/core/ledger/totals.js +4 -4
  192. package/dist/core/ledger/types.d.ts +12 -3
  193. package/dist/core/llm/run.js +2 -2
  194. package/dist/core/managed-providers.d.ts +72 -0
  195. package/dist/core/managed-providers.js +1 -0
  196. package/dist/core/model-auth/api-credential-store.d.ts +10 -0
  197. package/dist/core/model-auth/api-credential-store.js +1 -0
  198. package/dist/core/model-auth/daemon-login.d.ts +1 -1
  199. package/dist/core/model-auth/daemon-login.js +1 -1
  200. package/dist/core/model-auth/flows.d.ts +5 -4
  201. package/dist/core/model-auth/flows.js +1 -1
  202. package/dist/core/model-auth/handoff-jti.d.ts +3 -4
  203. package/dist/core/model-auth/handoff-jti.js +1 -1
  204. package/dist/core/model-auth/readiness.js +1 -1
  205. package/dist/core/model-config.d.ts +1 -1
  206. package/dist/core/model-config.js +1 -1
  207. package/dist/core/model-routes-pool.d.ts +14 -0
  208. package/dist/core/model-routes-pool.js +1 -0
  209. package/dist/core/model-routes.d.ts +11 -16
  210. package/dist/core/model-routes.js +1 -1
  211. package/dist/core/peer/ingest.d.ts +2 -0
  212. package/dist/core/peer/ingest.js +1 -1
  213. package/dist/core/peer/stubs.d.ts +8 -0
  214. package/dist/core/peer/stubs.js +1 -1
  215. package/dist/core/permissions/evaluator.d.ts +7 -2
  216. package/dist/core/permissions/evaluator.js +2 -2
  217. package/dist/core/plugin-env.js +1 -1
  218. package/dist/core/pool-credential-store.d.ts +2 -5
  219. package/dist/core/pool-credential-store.js +1 -1
  220. package/dist/core/profiles/app-env-store.d.ts +5 -5
  221. package/dist/core/profiles/app-env-store.js +1 -2
  222. package/dist/core/profiles/default-binding.d.ts +5 -5
  223. package/dist/core/profiles/default-binding.js +1 -1
  224. package/dist/core/profiles/env-store.d.ts +10 -21
  225. package/dist/core/profiles/env-store.js +1 -2
  226. package/dist/core/profiles/manifest.d.ts +14 -18
  227. package/dist/core/profiles/manifest.js +1 -1
  228. package/dist/core/profiles/relocate.js +1 -1
  229. package/dist/core/profiles/select.js +21 -21
  230. package/dist/core/provider-credential.d.ts +1 -1
  231. package/dist/core/provider-credential.js +1 -1
  232. package/dist/core/provider-management.d.ts +3 -4
  233. package/dist/core/provider-management.js +1 -1
  234. package/dist/core/providers/bundles.js +2 -2
  235. package/dist/core/providers/call.d.ts +3 -34
  236. package/dist/core/providers/description.d.ts +34 -0
  237. package/dist/core/providers/description.js +0 -0
  238. package/dist/core/providers/token-cache.d.ts +14 -14
  239. package/dist/core/providers/token-cache.js +1 -1
  240. package/dist/core/review/companion.js +1 -1
  241. package/dist/core/runs/activity.d.ts +1 -1
  242. package/dist/core/runs/activity.js +1 -1
  243. package/dist/core/runs/events.d.ts +7 -5
  244. package/dist/core/runs/events.js +2 -6
  245. package/dist/core/runs/operations.d.ts +1 -1
  246. package/dist/core/runs/operations.js +6 -6
  247. package/dist/core/runtime/bearings.js +1 -1
  248. package/dist/core/runtime/broker/attachments-fetch.d.ts +5 -0
  249. package/dist/core/runtime/broker/attachments-fetch.js +1 -0
  250. package/dist/core/runtime/broker/bash-job-launch.d.ts +4 -2
  251. package/dist/core/runtime/broker/bash-job-launch.js +1 -1
  252. package/dist/core/runtime/broker/boot-state.d.ts +9 -0
  253. package/dist/core/runtime/broker/boot-state.js +1 -0
  254. package/dist/core/runtime/broker/cli-relay.d.ts +2 -1
  255. package/dist/core/runtime/broker/cli-relay.js +1 -1
  256. package/dist/core/runtime/broker/client-registry.d.ts +3 -3
  257. package/dist/core/runtime/broker/daemon-ops.d.ts +10 -1
  258. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  259. package/dist/core/runtime/broker/fault-retry.d.ts +2 -0
  260. package/dist/core/runtime/broker/fault-retry.js +1 -1
  261. package/dist/core/runtime/broker/frame-engine-control.js +1 -1
  262. package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -0
  263. package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
  264. package/dist/core/runtime/broker/job-reporter.d.ts +18 -0
  265. package/dist/core/runtime/broker/job-reporter.js +2 -0
  266. package/dist/core/runtime/broker/model-adapter.d.ts +3 -0
  267. package/dist/core/runtime/broker/model-adapter.js +3 -2
  268. package/dist/core/runtime/broker/signal-stream.js +1 -1
  269. package/dist/core/runtime/broker/spilled-body.d.ts +5 -0
  270. package/dist/core/runtime/broker/spilled-body.js +1 -0
  271. package/dist/core/runtime/broker/summaries-post.d.ts +5 -0
  272. package/dist/core/runtime/broker/summaries-post.js +1 -0
  273. package/dist/core/runtime/broker/tool-groups.d.ts +3 -0
  274. package/dist/core/runtime/broker/tool-groups.js +1 -1
  275. package/dist/core/runtime/broker/turn-replies.d.ts +1 -0
  276. package/dist/core/runtime/broker/turn-replies.js +1 -1
  277. package/dist/core/runtime/broker-persona-guidance.js +2 -2
  278. package/dist/core/runtime/broker.js +1 -1
  279. package/dist/core/runtime/deliver-live.js +1 -1
  280. package/dist/core/runtime/first-boot-rows.d.ts +8 -0
  281. package/dist/core/runtime/first-boot-rows.js +2 -0
  282. package/dist/core/runtime/fleet.d.ts +13 -12
  283. package/dist/core/runtime/front-door-login.js +1 -1
  284. package/dist/core/runtime/front-door.js +6 -6
  285. package/dist/core/runtime/headless-pi.js +1 -1
  286. package/dist/core/runtime/host.d.ts +14 -3
  287. package/dist/core/runtime/host.js +3 -3
  288. package/dist/core/runtime/invocation.d.ts +6 -0
  289. package/dist/core/runtime/kickoff.d.ts +2 -14
  290. package/dist/core/runtime/kickoff.js +17 -19
  291. package/dist/core/runtime/launch-config-worker.js +1 -1
  292. package/dist/core/runtime/launch.js +2 -2
  293. package/dist/core/runtime/model-registry.js +1 -1
  294. package/dist/core/runtime/node-read.d.ts +4 -6
  295. package/dist/core/runtime/node-read.js +3 -3
  296. package/dist/core/runtime/nodes.js +1 -1
  297. package/dist/core/runtime/outcome-document.d.ts +0 -1
  298. package/dist/core/runtime/outcome-document.js +1 -1
  299. package/dist/core/runtime/output-result.d.ts +15 -0
  300. package/dist/core/runtime/output-result.js +5 -0
  301. package/dist/core/runtime/placement.d.ts +17 -1
  302. package/dist/core/runtime/placement.js +1 -1
  303. package/dist/core/runtime/provider-credential-gate.d.ts +6 -2
  304. package/dist/core/runtime/provider-credential-gate.js +2 -2
  305. package/dist/core/runtime/recovery-hold.d.ts +21 -2
  306. package/dist/core/runtime/recovery-hold.js +2 -1
  307. package/dist/core/runtime/recycle.js +1 -1
  308. package/dist/core/runtime/reset.js +1 -1
  309. package/dist/core/runtime/revive.d.ts +2 -2
  310. package/dist/core/runtime/revive.js +2 -2
  311. package/dist/core/runtime/runner/blaxel/client.d.ts +81 -0
  312. package/dist/core/runtime/runner/blaxel/client.js +1 -0
  313. package/dist/core/runtime/runner/blaxel/image-build.d.ts +74 -0
  314. package/dist/core/runtime/runner/blaxel/image-build.js +5 -0
  315. package/dist/core/runtime/runner/blaxel/runner.d.ts +41 -0
  316. package/dist/core/runtime/runner/blaxel/runner.js +3 -0
  317. package/dist/core/runtime/runner/index.d.ts +8 -0
  318. package/dist/core/runtime/runner/index.js +1 -0
  319. package/dist/core/runtime/runner/process.d.ts +11 -0
  320. package/dist/core/runtime/runner/process.js +1 -0
  321. package/dist/core/runtime/runner/types.d.ts +95 -0
  322. package/dist/core/runtime/runner/types.js +0 -0
  323. package/dist/core/runtime/situational-context.d.ts +3 -6
  324. package/dist/core/runtime/situational-context.js +2 -2
  325. package/dist/core/runtime/situational-live.js +1 -1
  326. package/dist/core/runtime/spawn-env-rows.d.ts +5 -0
  327. package/dist/core/runtime/spawn-env-rows.js +1 -0
  328. package/dist/core/runtime/spawn-env.d.ts +4 -18
  329. package/dist/core/runtime/spawn-env.js +1 -1
  330. package/dist/core/runtime/spawn.js +2 -2
  331. package/dist/core/runtime/stop-guard.d.ts +1 -1
  332. package/dist/core/runtime/stop-guard.js +2 -8
  333. package/dist/core/runtime/structured-output.d.ts +0 -67
  334. package/dist/core/runtime/structured-output.js +3 -8
  335. package/dist/core/runtime/tmux-driver.d.ts +8 -0
  336. package/dist/core/runtime/tmux-driver.js +6 -6
  337. package/dist/core/runtime/view-socket.d.ts +20 -0
  338. package/dist/core/runtime/view-socket.js +3 -1
  339. package/dist/core/runtime/warm-pool.d.ts +13 -1
  340. package/dist/core/runtime/warm-pool.js +1 -1
  341. package/dist/core/scoped-state/legacy-profiles.d.ts +11 -0
  342. package/dist/core/scoped-state/legacy-profiles.js +1 -0
  343. package/dist/core/scoped-state/materialized-plugins.d.ts +18 -0
  344. package/dist/core/scoped-state/materialized-plugins.js +1 -0
  345. package/dist/core/scoped-state/migrate.d.ts +8 -1
  346. package/dist/core/scoped-state/migrate.js +3 -3
  347. package/dist/core/scoped-state/person-rows.d.ts +10 -0
  348. package/dist/core/scoped-state/person-rows.js +6 -0
  349. package/dist/core/scoped-state/person-store.d.ts +72 -0
  350. package/dist/core/scoped-state/person-store.js +1 -0
  351. package/dist/core/secrets/blaxel-launch.d.ts +24 -0
  352. package/dist/core/secrets/blaxel-launch.js +4 -0
  353. package/dist/core/secrets/blaxel-register.d.ts +2 -0
  354. package/dist/core/secrets/blaxel-register.js +1 -0
  355. package/dist/core/secrets/env-rows.d.ts +17 -0
  356. package/dist/core/secrets/env-rows.js +4 -0
  357. package/dist/core/secrets/environment-owner.d.ts +8 -0
  358. package/dist/core/secrets/environment-owner.js +1 -0
  359. package/dist/core/secrets/environment-secrets.d.ts +14 -0
  360. package/dist/core/secrets/environment-secrets.js +1 -0
  361. package/dist/core/secrets/index.d.ts +2 -0
  362. package/dist/core/secrets/index.js +1 -0
  363. package/dist/core/secrets/key.d.ts +3 -0
  364. package/dist/core/secrets/key.js +2 -0
  365. package/dist/core/secrets/seal.d.ts +18 -0
  366. package/dist/core/secrets/seal.js +1 -0
  367. package/dist/core/spaces/mounts.d.ts +1 -1
  368. package/dist/core/spaces/mounts.js +1 -1
  369. package/dist/core/spaces/process.d.ts +1 -1
  370. package/dist/core/spaces/stop.d.ts +7 -5
  371. package/dist/core/spaces/stop.js +2 -2
  372. package/dist/core/spaces/users.d.ts +2 -1
  373. package/dist/core/spaces/users.js +1 -1
  374. package/dist/core/storage/attachments.d.ts +11 -8
  375. package/dist/core/storage/attachments.js +1 -1
  376. package/dist/core/storage/tables.d.ts +4 -0
  377. package/dist/core/storage/tables.js +3 -3
  378. package/dist/core/subscription-state.d.ts +34 -72
  379. package/dist/core/subscription-state.js +1 -4
  380. package/dist/core/substrate/delivery/plan.js +1 -1
  381. package/dist/core/user-settings.js +1 -1
  382. package/dist/daemon/api/app-listener.js +10 -10
  383. package/dist/daemon/api/auth/person-bearer.d.ts +14 -0
  384. package/dist/daemon/api/auth/person-bearer.js +1 -0
  385. package/dist/daemon/api/bridge.js +4 -4
  386. package/dist/daemon/api/document-listener.js +3 -3
  387. package/dist/daemon/api/environment-of.d.ts +18 -0
  388. package/dist/daemon/api/environment-of.js +5 -0
  389. package/dist/daemon/api/handlers/analytics.js +1 -1
  390. package/dist/daemon/api/handlers/app-profiles.d.ts +2 -2
  391. package/dist/daemon/api/handlers/app-profiles.js +1 -1
  392. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  393. package/dist/daemon/api/handlers/bash.js +1 -1
  394. package/dist/daemon/api/handlers/broker-ops.d.ts +3 -0
  395. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  396. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  397. package/dist/daemon/api/handlers/broker-signals.d.ts +0 -3
  398. package/dist/daemon/api/handlers/broker-signals.js +2 -2
  399. package/dist/daemon/api/handlers/canvas.js +4 -4
  400. package/dist/daemon/api/handlers/charges.d.ts +1 -1
  401. package/dist/daemon/api/handlers/charges.js +1 -1
  402. package/dist/daemon/api/handlers/conversations.d.ts +2 -0
  403. package/dist/daemon/api/handlers/conversations.js +3 -0
  404. package/dist/daemon/api/handlers/crons.js +1 -1
  405. package/dist/daemon/api/handlers/daemon.js +1 -1
  406. package/dist/daemon/api/handlers/delivery.d.ts +1 -1
  407. package/dist/daemon/api/handlers/delivery.js +1 -1
  408. package/dist/daemon/api/handlers/docs.js +1 -1
  409. package/dist/daemon/api/handlers/exec.js +1 -1
  410. package/dist/daemon/api/handlers/execution-start.d.ts +2 -0
  411. package/dist/daemon/api/handlers/execution-start.js +2 -0
  412. package/dist/daemon/api/handlers/files.js +1 -1
  413. package/dist/daemon/api/handlers/git-credential.d.ts +11 -0
  414. package/dist/daemon/api/handlers/git-credential.js +1 -0
  415. package/dist/daemon/api/handlers/hook-exec.d.ts +1 -1
  416. package/dist/daemon/api/handlers/hook-exec.js +1 -1
  417. package/dist/daemon/api/handlers/human-requests.js +1 -1
  418. package/dist/daemon/api/handlers/inbox.js +1 -1
  419. package/dist/daemon/api/handlers/messages.js +1 -1
  420. package/dist/daemon/api/handlers/model-config.js +1 -1
  421. package/dist/daemon/api/handlers/modelauth.d.ts +1 -1
  422. package/dist/daemon/api/handlers/modelauth.js +1 -1
  423. package/dist/daemon/api/handlers/node-events.d.ts +6 -0
  424. package/dist/daemon/api/handlers/node-events.js +3 -3
  425. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  426. package/dist/daemon/api/handlers/node-records.js +3 -2
  427. package/dist/daemon/api/handlers/nodes.js +1 -1
  428. package/dist/daemon/api/handlers/objects.js +3 -3
  429. package/dist/daemon/api/handlers/profiles.js +1 -1
  430. package/dist/daemon/api/handlers/providers.js +1 -1
  431. package/dist/daemon/api/handlers/reports.js +9 -13
  432. package/dist/daemon/api/handlers/reviews.js +1 -1
  433. package/dist/daemon/api/handlers/runs.js +1 -1
  434. package/dist/daemon/api/handlers/settings.d.ts +2 -0
  435. package/dist/daemon/api/handlers/settings.js +1 -0
  436. package/dist/daemon/api/handlers/structured-requests.js +1 -1
  437. package/dist/daemon/api/handlers/vendor-status.d.ts +1 -1
  438. package/dist/daemon/api/handlers/vendor-status.js +1 -1
  439. package/dist/daemon/api/handlers/worktree.js +1 -1
  440. package/dist/daemon/api/map.d.ts +2 -2
  441. package/dist/daemon/api/map.js +2 -2
  442. package/dist/daemon/api/operations.js +1 -1
  443. package/dist/daemon/api/reader.d.ts +8 -1
  444. package/dist/daemon/api/reader.js +1 -1
  445. package/dist/daemon/api/router.d.ts +4 -2
  446. package/dist/daemon/api/router.js +1 -1
  447. package/dist/daemon/api/server.d.ts +15 -3
  448. package/dist/daemon/api/server.js +1 -1
  449. package/dist/daemon/api/vendor-signin.d.ts +2 -1
  450. package/dist/daemon/api/vendor-signin.js +19 -19
  451. package/dist/daemon/api/viewer-presence.d.ts +20 -6
  452. package/dist/daemon/api/viewer-presence.js +2 -1
  453. package/dist/daemon/broker-signals/bus.d.ts +48 -11
  454. package/dist/daemon/broker-signals/bus.js +1 -1
  455. package/dist/daemon/cron/armed-context.js +1 -1
  456. package/dist/daemon/cron/lease-recovery.js +1 -1
  457. package/dist/daemon/cron/live-runs.d.ts +6 -0
  458. package/dist/daemon/cron/live-runs.js +1 -1
  459. package/dist/daemon/cron/run-socket.js +1 -1
  460. package/dist/daemon/cron-run.js +2 -2
  461. package/dist/daemon/crtrd-cli.js +1 -1
  462. package/dist/daemon/crtrd.d.ts +10 -0
  463. package/dist/daemon/crtrd.js +18 -17
  464. package/dist/daemon/delivery/run-delivery.d.ts +1 -1
  465. package/dist/daemon/delivery/run-delivery.js +1 -1
  466. package/dist/daemon/due-sources.d.ts +1 -1
  467. package/dist/daemon/due-sources.js +1 -1
  468. package/dist/daemon/due.js +7 -6
  469. package/dist/daemon/fleet.d.ts +6 -6
  470. package/dist/daemon/fleet.js +9 -9
  471. package/dist/daemon/park-activity.d.ts +2 -1
  472. package/dist/daemon/park-activity.js +1 -1
  473. package/dist/daemon/park-pending.d.ts +20 -13
  474. package/dist/daemon/park-pending.js +3 -1
  475. package/dist/daemon/profile-delete.js +1 -1
  476. package/dist/daemon/reconcilers/bash-deadline.d.ts +15 -10
  477. package/dist/daemon/reconcilers/bash-deadline.js +1 -3
  478. package/dist/daemon/reconcilers/broker-supervision.d.ts +13 -3
  479. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  480. package/dist/daemon/reconcilers/cron-lane.d.ts +0 -1
  481. package/dist/daemon/reconcilers/cron-lane.js +1 -1
  482. package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +2 -9
  483. package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
  484. package/dist/daemon/reconcilers/grant-effects.d.ts +8 -0
  485. package/dist/daemon/reconcilers/grant-effects.js +1 -0
  486. package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +1 -3
  487. package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
  488. package/dist/daemon/reconcilers/ledger-r2.d.ts +27 -0
  489. package/dist/daemon/reconcilers/ledger-r2.js +7 -0
  490. package/dist/daemon/reconcilers/ledger-sandbox.d.ts +55 -0
  491. package/dist/daemon/reconcilers/ledger-sandbox.js +9 -0
  492. package/dist/daemon/reconcilers/ledger-storage.d.ts +22 -0
  493. package/dist/daemon/reconcilers/ledger-storage.js +5 -0
  494. package/dist/daemon/reconcilers/live-obligation.d.ts +3 -2
  495. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  496. package/dist/daemon/reconcilers/managed-worktree-sweep.d.ts +0 -5
  497. package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
  498. package/dist/daemon/reconcilers/node-deadline.d.ts +2 -1
  499. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  500. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -2
  501. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  502. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +31 -0
  503. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -0
  504. package/dist/daemon/reconcilers/node-lifecycle/requested-stops.d.ts +5 -0
  505. package/dist/daemon/reconcilers/node-lifecycle/requested-stops.js +2 -0
  506. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  507. package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
  508. package/dist/daemon/reconcilers/recipe-image.d.ts +49 -0
  509. package/dist/daemon/reconcilers/recipe-image.js +7 -0
  510. package/dist/daemon/reconcilers/row-claim.d.ts +19 -0
  511. package/dist/daemon/reconcilers/row-claim.js +2 -0
  512. package/dist/daemon/reconcilers/storage-due-work.d.ts +18 -3
  513. package/dist/daemon/reconcilers/storage-due-work.js +2 -1
  514. package/dist/daemon/reconcilers/storage-maintenance.d.ts +5 -13
  515. package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
  516. package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
  517. package/dist/daemon/reconcilers/throttled-lane.d.ts +11 -0
  518. package/dist/daemon/reconcilers/throttled-lane.js +1 -0
  519. package/dist/daemon/review/finish.js +1 -1
  520. package/dist/daemon/run-notices.d.ts +3 -0
  521. package/dist/daemon/run-notices.js +1 -1
  522. package/dist/daemon/runs/append-section.d.ts +4 -1
  523. package/dist/daemon/runs/append-section.js +2 -2
  524. package/dist/daemon/runs/observer.d.ts +3 -2
  525. package/dist/daemon/runs/observer.js +3 -2
  526. package/dist/daemon/runs/view-transport.d.ts +19 -0
  527. package/dist/daemon/runs/view-transport.js +1 -0
  528. package/dist/daemon/structured-requests/boot.d.ts +2 -1
  529. package/dist/daemon/structured-requests/boot.js +1 -1
  530. package/dist/daemon/structured-requests/effects.d.ts +4 -3
  531. package/dist/daemon/structured-requests/effects.js +1 -1
  532. package/dist/daemon/structured-requests/notifier.d.ts +2 -0
  533. package/dist/daemon/structured-requests/notifier.js +1 -1
  534. package/dist/daemon/structured-requests/sidecar.d.ts +4 -3
  535. package/dist/daemon/structured-requests/sidecar.js +1 -1
  536. package/dist/launcher/validate.js +1 -1
  537. package/dist/migrations/004-canvas-documents/index.js +2 -2
  538. package/dist/pi-extensions/broker-local.d.ts +3 -3
  539. package/dist/pi-extensions/broker-local.js +1 -2
  540. package/dist/pi-extensions/canvas-bash-valve.js +6 -6
  541. package/dist/pi-extensions/canvas-context-intro.js +2 -2
  542. package/dist/pi-extensions/canvas-elapsed.js +2 -2
  543. package/dist/pi-extensions/canvas-goal-capture.js +1 -1
  544. package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
  545. package/dist/pi-extensions/canvas-review-boundary.d.ts +11 -1
  546. package/dist/pi-extensions/canvas-review-boundary.js +3 -3
  547. package/dist/pi-extensions/canvas-stophook.js +1 -1
  548. package/dist/pi-extensions/canvas-structured-output.d.ts +5 -3
  549. package/dist/pi-extensions/canvas-structured-output.js +6 -11
  550. package/dist/pi-extensions/canvas-tool-guide.d.ts +9 -2
  551. package/dist/pi-extensions/canvas-tool-guide.js +6 -6
  552. package/dist/shared/inbox-entry-body.js +7 -7
  553. package/dist/types.d.ts +12 -0
  554. package/docs/sdk/release-notes.md +4 -0
  555. package/package.json +7 -4
  556. package/packages/crouter-identity/package.json +1 -1
  557. package/runtime.lock.json +13 -13
  558. package/scripts/git-credential-crtr +33 -0
  559. package/scripts/sandbox-bootstrap.sh +54 -0
  560. package/scripts/sandbox-start.mjs +320 -0
  561. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +0 -78
  562. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +0 -1179
  563. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +0 -1406
  564. package/dist/core/conversation-store/file-store.d.ts +0 -37
  565. package/dist/core/conversation-store/file-store.js +0 -9
  566. package/dist/core/conversation-store/listener.d.ts +0 -4
  567. package/dist/core/conversation-store/listener.js +0 -8
  568. package/dist/core/scoped-state/profiles.d.ts +0 -27
  569. package/dist/core/scoped-state/profiles.js +0 -1
  570. package/dist/core/scoped-state/providers.d.ts +0 -24
  571. package/dist/core/scoped-state/providers.js +0 -1
  572. package/dist/core/scoped-state/settings.d.ts +0 -28
  573. package/dist/core/scoped-state/settings.js +0 -1
@@ -1,24 +1,24 @@
1
- var Q=Object.defineProperty;var s=(e,n)=>Q(e,"name",{value:n,configurable:!0});import{randomUUID as W}from"node:crypto";import{createServer as q}from"node:http";import{Router as V,causedByOf as K}from"./router.js";import{toErrorBody as Z}from"./map.js";import{objectRoutes as ee}from"./handlers/objects.js";import{customObjectRoutes as te}from"./handlers/custom-objects.js";import{checkRoutes as re}from"./handlers/check.js";import{chargeRoutes as ne}from"./handlers/charges.js";import{docRoutes as ae}from"./handlers/docs.js";import{relationRoutes as oe}from"./handlers/relations.js";import{schemaRoutes as ie}from"./handlers/schemas.js";import{OPERATIONS as se}from"./operations.js";import{runtimeReadiness as ue}from"../readiness.js";import{errorCodes as X}from"../../api/error-codes.js";import{MINIMUM_RUNTIME_VERSION_HEADER as ce,RUNTIME_VERSION_HEADER as de,minimumRuntimeRefusal as le}from"../../api/runtime-version.js";import{CONTRACT_HEADER as me,CONTRACT_LEVEL as $,REQUIRED_CONTRACT_HEADER as fe,contractRefusal as pe}from"../../api/contract.js";import{crtrVersion as J}from"../../shared/crtr-version.js";import{newTraceId as he,parseTraceparent as we}from"../../shared/traceparent.js";import{AppPrincipalResolver as ye}from"./principal.js";import{isDaemonRoute as _e,runtimeOwner as ve,servePeer as z}from"../peer/ingress.js";import{applySyncNotice as ge}from"./sync-notice.js";import{ownMachineId as Re}from"../../core/peer/directory.js";import{handleRunOperation as Oe,integer as Ee}from"./handlers/runs.js";import{llmCallerOf as be,parseLlmRequest as Ae,runLlm as Te}from"../../core/llm/run.js";import{parseUsageMonth as Se,usageFor as Ne}from"../../core/ledger/index.js";import{capFields as Ce}from"./handlers/llm.js";import{CONTROL_BODY_MAX_BYTES as Ie,MODEL_CONTEXT_BODY_MAX_BYTES as Pe}from"../../core/llm/body-limits.js";import{RunError as m,runIsRunning as ke}from"../../core/runs/operations.js";import{requireRun as L}from"./router.js";import{deferHead as Me}from"./deferred-head.js";import{readRunEvents as G,registerGrantStream as De,subscribeRunEvents as He}from"../../core/runs/events.js";import{activeGrant as Y,payerOfGrant as xe}from"../../core/grants/mirror.js";async function Be(e){if(await xe(e)==="app")throw new m(401,"grant_revoked","this app-paid grant is no longer active");return null}s(Be,"appPaidGone");import{releaseGrantWaiters as je}from"../../core/grants/watch.js";import{emitEvent as Je}from"../../core/events/emit.js";import{runNotices as Le}from"../run-notices.js";import{handleVendorSignIn as Ue,isVendorSignInPath as Ve}from"./vendor-signin.js";import{listAppProfiles as Xe}from"./handlers/app-profiles.js";import{handleTransferDownload as $e,handleTransferOperation as ze,TRANSFER_OPERATIONS as Ge}from"./handlers/transfer.js";import{handleQuestionOperation as Ye,QUESTION_OPERATIONS as Fe}from"./handlers/questions.js";import{removeVendorAccount as Qe,vendorStatus as We}from"./handlers/vendor-status.js";import{handleMemoryOperation as qe,MEMORY_OPERATIONS as Ke}from"./handlers/memory.js";import{EXEC_BODY_MAX_BYTES as Ze,handleExec as et}from"./handlers/exec.js";import{abortOnClose as F,callerFromApp as tt,handleProviderOperation as rt,PROVIDER_OPERATIONS as nt,providerFailure as at}from"./handlers/providers.js";function ot(e){return Object.prototype.hasOwnProperty.call(X,e)?X[e]:void 0}s(ot,"fixedRow");function it(e){const n=ot(e);return n?n.type:e==="stream_gap"||e==="provider_error"||e==="runtime_version_unsupported"?"invalid_request_error":"server_error"}s(it,"errorType");function st(e){if(!e||typeof e!="object"||Array.isArray(e)||!("rate_limit"in e))return e;const{rate_limit:n,...o}=e;return o}s(st,"appDetails");function j(e,n,o){const p=st(e.details);return{error:{code:e.code,message:e.message,...p===void 0?{}:{details:p},type:it(e.code),...e.param?{param:e.param}:{},origin:"runtime",retryable:e.retryable||e.code==="stream_dropped",request_id:n,...o?{run_id:o}:{},...e.scope?{scope:e.scope}:{},...e.code==="unauthorized"?{user_action:"reconnect"}:{},...Ce(e),...e.code==="all_routes_exhausted"?{retry_after_s:e.details.retry_after_s}:{}}}}s(j,"envelope");function ut(e,n,o,p,f){const d=n instanceof m?n:new m(500,"server_failure","runtime request failed");if(n instanceof m||console.error("[app-listener]",`trace_id=${p}`,n),e.headersSent&&!String(e.getHeader("Content-Type")??"").startsWith("text/event-stream")){e.destroy();return}if(e.headersSent){e.end(`event: error
1
+ var Q=Object.defineProperty;var s=(e,n)=>Q(e,"name",{value:n,configurable:!0});import{AsyncResource as W}from"node:async_hooks";import{randomUUID as q}from"node:crypto";import{createServer as K}from"node:http";import{Router as V,causedByOf as Z}from"./router.js";import{toErrorBody as ee}from"./map.js";import{objectRoutes as te}from"./handlers/objects.js";import{customObjectRoutes as re}from"./handlers/custom-objects.js";import{checkRoutes as ne}from"./handlers/check.js";import{chargeRoutes as ae}from"./handlers/charges.js";import{docRoutes as oe}from"./handlers/docs.js";import{relationRoutes as ie}from"./handlers/relations.js";import{schemaRoutes as se}from"./handlers/schemas.js";import{OPERATIONS as ue}from"./operations.js";import{runtimeReadiness as ce}from"../readiness.js";import{errorCodes as X}from"../../api/error-codes.js";import{MINIMUM_RUNTIME_VERSION_HEADER as de,RUNTIME_VERSION_HEADER as le,minimumRuntimeRefusal as me}from"../../api/runtime-version.js";import{CONTRACT_HEADER as fe,CONTRACT_LEVEL as $,REQUIRED_CONTRACT_HEADER as pe,contractRefusal as he}from"../../api/contract.js";import{crtrVersion as J}from"../../shared/crtr-version.js";import{newTraceId as we,parseTraceparent as ye}from"../../shared/traceparent.js";import{AppPrincipalResolver as _e}from"./principal.js";import{isDaemonRoute as ve,runtimeOwner as ge,servePeer as z}from"../peer/ingress.js";import{applySyncNotice as Re}from"./sync-notice.js";import{ownMachineId as Oe}from"../../core/peer/directory.js";import{handleRunOperation as Ee,integer as be}from"./handlers/runs.js";import{llmCallerOf as Ae,parseLlmRequest as Te,runLlm as Se}from"../../core/llm/run.js";import{parseUsageMonth as Ne,usageFor as Ce}from"../../core/ledger/index.js";import{capFields as Ie}from"./handlers/llm.js";import{CONTROL_BODY_MAX_BYTES as Pe,MODEL_CONTEXT_BODY_MAX_BYTES as ke}from"../../core/llm/body-limits.js";import{RunError as m,runIsRunning as Me}from"../../core/runs/operations.js";import{requireRun as L}from"./router.js";import{deferHead as De}from"./deferred-head.js";import{readRunEvents as G,registerGrantStream as He,subscribeRunEvents as xe}from"../../core/runs/events.js";import{activeGrant as Y,payerOfGrant as Be}from"../../core/grants/mirror.js";async function je(e){if(await Be(e)==="app")throw new m(401,"grant_revoked","this app-paid grant is no longer active");return null}s(je,"appPaidGone");import{releaseGrantWaiters as Je}from"../../core/grants/watch.js";import{emitEvent as Le}from"../../core/events/emit.js";import{runNotices as Ue}from"../run-notices.js";import{handleVendorSignIn as Ve,isVendorSignInPath as Xe}from"./vendor-signin.js";import{listAppProfiles as $e}from"./handlers/app-profiles.js";import{handleTransferDownload as ze,handleTransferOperation as Ge,TRANSFER_OPERATIONS as Ye}from"./handlers/transfer.js";import{handleQuestionOperation as Fe,QUESTION_OPERATIONS as Qe}from"./handlers/questions.js";import{removeVendorAccount as We,vendorStatus as qe}from"./handlers/vendor-status.js";import{handleMemoryOperation as Ke,MEMORY_OPERATIONS as Ze}from"./handlers/memory.js";import{EXEC_BODY_MAX_BYTES as et,handleExec as tt}from"./handlers/exec.js";import{abortOnClose as F,callerFromApp as rt,handleProviderOperation as nt,PROVIDER_OPERATIONS as at,providerFailure as ot}from"./handlers/providers.js";function it(e){return Object.prototype.hasOwnProperty.call(X,e)?X[e]:void 0}s(it,"fixedRow");function st(e){const n=it(e);return n?n.type:e==="stream_gap"||e==="provider_error"||e==="runtime_version_unsupported"?"invalid_request_error":"server_error"}s(st,"errorType");function ut(e){if(!e||typeof e!="object"||Array.isArray(e)||!("rate_limit"in e))return e;const{rate_limit:n,...o}=e;return o}s(ut,"appDetails");function j(e,n,o){const p=ut(e.details);return{error:{code:e.code,message:e.message,...p===void 0?{}:{details:p},type:st(e.code),...e.param?{param:e.param}:{},origin:"runtime",retryable:e.retryable||e.code==="stream_dropped",request_id:n,...o?{run_id:o}:{},...e.scope?{scope:e.scope}:{},...e.code==="unauthorized"?{user_action:"reconnect"}:{},...Ie(e),...e.code==="all_routes_exhausted"?{retry_after_s:e.details.retry_after_s}:{}}}}s(j,"envelope");function ct(e,n,o,p,f){const d=n instanceof m?n:new m(500,"server_failure","runtime request failed");if(n instanceof m||console.error("[app-listener]",`trace_id=${p}`,n),e.headersSent&&!String(e.getHeader("Content-Type")??"").startsWith("text/event-stream")){e.destroy();return}if(e.headersSent){e.end(`event: error
2
2
  data: ${JSON.stringify(j(d,o,f))}
3
3
 
4
- `);return}e.writeHead(d.status,{"Content-Type":"application/json; charset=utf-8","Request-Id":o,"X-Content-Type-Options":"nosniff",...d.code==="all_routes_exhausted"?{"Retry-After":String(d.details.retry_after_s)}:{}}),e.end(JSON.stringify(j(d,o,f)))}s(ut,"fail");function U(e){return Array.isArray(e)?e[0]:e}s(U,"headerValue");function g(e,n,o){e.writeHead(n,{"Content-Type":"application/json; charset=utf-8"}),e.end(JSON.stringify(o))}s(g,"json");async function C(e,n=Ie){const o=[];let p=0;for await(const f of e){if(p+=f.length,p>n)throw new m(400,"invalid_request","request body too large");o.push(f)}if(p)try{return JSON.parse(Buffer.concat(o).toString("utf8"))}catch{throw new m(400,"invalid_request","invalid JSON body")}}s(C,"bodyOf");function ct(e,n){const o=e.headers["last-event-id"]??n.get("after");if(Array.isArray(o))throw new m(400,"invalid_request","invalid cursor","after");return Ee(o??null,"after",0,Number.MAX_SAFE_INTEGER,0)}s(ct,"cursor");function dt(e){return`id: ${e.sequence_number}
4
+ `);return}e.writeHead(d.status,{"Content-Type":"application/json; charset=utf-8","Request-Id":o,"X-Content-Type-Options":"nosniff",...d.code==="all_routes_exhausted"?{"Retry-After":String(d.details.retry_after_s)}:{}}),e.end(JSON.stringify(j(d,o,f)))}s(ct,"fail");function U(e){return Array.isArray(e)?e[0]:e}s(U,"headerValue");function g(e,n,o){e.writeHead(n,{"Content-Type":"application/json; charset=utf-8"}),e.end(JSON.stringify(o))}s(g,"json");async function C(e,n=Pe){const o=[];let p=0;for await(const f of e){if(p+=f.length,p>n)throw new m(400,"invalid_request","request body too large");o.push(f)}if(p)try{return JSON.parse(Buffer.concat(o).toString("utf8"))}catch{throw new m(400,"invalid_request","invalid JSON body")}}s(C,"bodyOf");function dt(e,n){const o=e.headers["last-event-id"]??n.get("after");if(Array.isArray(o))throw new m(400,"invalid_request","invalid cursor","after");return be(o??null,"after",0,Number.MAX_SAFE_INTEGER,0)}s(dt,"cursor");function lt(e){return`id: ${e.sequence_number}
5
5
  event: ${e.type}
6
6
  data: ${JSON.stringify(e)}
7
7
 
8
- `}s(dt,"frame");const lt=6e4;async function mt(e,n,o,p,f,d,b,I={},D){await L(p,o);let w=await G(o,f);if(f>w.latest_sequence)throw new m(400,"invalid_request","cursor is beyond the run","after");if(f<w.latest_sequence&&(w.earliest_sequence===null||f<w.earliest_sequence-1))throw new m(409,"stream_gap","events have expired",void 0,{earliest_sequence:w.earliest_sequence,latest_sequence:w.latest_sequence});if(n.destroyed||e.destroyed)return n.destroy(),Promise.resolve();n.writeHead(200,{"Content-Type":b==="sse"?"text/event-stream":"application/x-ndjson","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),b==="sse"?n.write(`: connected
8
+ `}s(lt,"frame");const mt=6e4;async function ft(e,n,o,p,f,d,b,I={},D){await L(p,o);let w=await G(o,f);if(f>w.latest_sequence)throw new m(400,"invalid_request","cursor is beyond the run","after");if(f<w.latest_sequence&&(w.earliest_sequence===null||f<w.earliest_sequence-1))throw new m(409,"stream_gap","events have expired",void 0,{earliest_sequence:w.earliest_sequence,latest_sequence:w.latest_sequence});if(n.destroyed)return n.destroy(),Promise.resolve();n.writeHead(200,{"Content-Type":b==="sse"?"text/event-stream":"application/x-ndjson","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),b==="sse"?n.write(`: connected
9
9
 
10
- `):n.flushHeaders();let T=f;const r=await Le().streamOpened(o);let t=!1,y=!1,E=!1,A;const P=new Promise(c=>{A=c}),v=s(()=>{t||(t=!0,r(T).catch(c=>console.error("[app-listener]",...D===void 0?[]:[`trace_id=${D}`],c)),clearInterval(N),clearInterval(O),M(),x(),n.off("close",v),n.off("drain",h),n.end(),A())},"end"),h=s(()=>{E=!1,a()},"onDrain"),R=s(c=>{t||n.write(b==="sse"?`event: error
10
+ `):n.flushHeaders();let T=f;const r=await Ue().streamOpened(o);let t=!1,y=!1,E=!1,A;const P=new Promise(c=>{A=c}),v=s(()=>{t||(t=!0,r(T).catch(c=>console.error("[app-listener]",...D===void 0?[]:[`trace_id=${D}`],c)),clearInterval(N),clearInterval(O),M(),x(),n.off("close",v),n.off("drain",h),n.end(),A())},"end"),h=s(()=>{E=!1,a()},"onDrain"),R=s(c=>{t||n.write(b==="sse"?`event: error
11
11
  data: ${JSON.stringify(j(c,d,o))}
12
12
 
13
13
  `:`${JSON.stringify({type:"error",...j(c,d,o)})}
14
- `),v()},"error"),a=s(async()=>{if(!(t||y)){y=!0;try{if(!await S()){H();return}if(await L(p,o),w=await G(o,T),w.backlog_count>1e3||w.backlog_bytes>32*1024*1024){R(new m(503,"stream_dropped","stream reader fell behind",void 0,{last_sequence:T}));return}for(const c of w.events){if(E)break;E=!n.write(b==="sse"?dt(c):`${JSON.stringify(c)}
15
- `),T=c.sequence_number}}catch(c){R(c instanceof m?c:new m(500,"server_failure","stream failed"))}finally{y=!1}}},"flush"),H=s(()=>R(new m(401,"grant_revoked","grant is not active")),"revoked"),S=s(async()=>"class"in p||await Y(p.grant)!==null,"grantActive"),M=await He(o,a),x="class"in p?()=>{}:De(p.grant,H),N=setInterval(()=>{!t&&!E&&b==="sse"&&n.write(`: keepalive
14
+ `),v()},"error"),a=s(async()=>{if(!(t||y)){y=!0;try{if(!await S()){H();return}if(await L(p,o),w=await G(o,T),w.backlog_count>1e3||w.backlog_bytes>32*1024*1024){R(new m(503,"stream_dropped","stream reader fell behind",void 0,{last_sequence:T}));return}for(const c of w.events){if(E)break;E=!n.write(b==="sse"?lt(c):`${JSON.stringify(c)}
15
+ `),T=c.sequence_number}}catch(c){R(c instanceof m?c:new m(500,"server_failure","stream failed"))}finally{y=!1}}},"flush"),H=s(()=>R(new m(401,"grant_revoked","grant is not active")),"revoked"),S=s(async()=>"class"in p||await Y(p.grant)!==null,"grantActive"),M=await xe(o,W.bind(a)),x="class"in p?()=>{}:He(p.grant,H),N=setInterval(()=>{!t&&!E&&b==="sse"&&n.write(`: keepalive
16
16
 
17
- `)},15e3),u=I.idleMs??lt,B=I.isRunning??ke;let i=Date.now(),_=T;const l=s(async()=>{if(t||b!=="sse")return;const c=Date.now();let k=!0;try{k=await B(o)}catch{}if(!t){if(k||T!==_){i=c,_=T;return}c-i<u||E||(n.write(`event: idle
17
+ `)},15e3),u=I.idleMs??mt,B=I.isRunning??Me;let i=Date.now(),_=T;const l=s(async()=>{if(t||b!=="sse")return;const c=Date.now();let k=!0;try{k=await B(o)}catch{}if(!t){if(k||T!==_){i=c,_=T;return}c-i<u||E||(n.write(`event: idle
18
18
  data: {}
19
19
 
20
- `),v())}},"checkIdle"),O=setInterval(()=>{l().catch(c=>Je({level:"error",event:"api.run_stream.idle_check_failed",error:c}))},I.idleCheckMs??1e3);return O.unref(),n.on("drain",h),n.on("close",v),await a(),P}s(mt,"streamRunEvents");async function nr(e,n,o,p={}){const f=e.listener;if(!e.issuer||!e.audience||!f?.address||!Number.isInteger(f.port)||f.port<1||f.port>65535)throw new Error("runtime issuer, audience and listener address/port are required");if(["0.0.0.0","::","[::]"].includes(f.address))throw new Error("runtime listener must bind a specific address");const d=new ye(e.issuer,e.audience,o,e.jwksUrl),b=new V,I=new Map;for(const r of se.filter(t=>t.stage!==void 0)){const t=s(()=>({status:500}),"handler");b.register({method:r.method,pattern:r.path,handler:t}),I.set(t,r)}const D=new V().registerAll(ee).registerAll(te).registerAll(ae).registerAll(ie).registerAll(oe).registerAll(re).registerAll(ne),w=q((r,t)=>{(async()=>{Me(r,t,p.deferHead);const y=W();t.setHeader("Request-Id",y);const E=we(U(r.headers.traceparent))??he();t.setHeader(de,J()),t.setHeader(me,$);let A;try{const P=U(r.headers[ce.toLowerCase()]),v=le(P,J())??pe(U(r.headers[fe.toLowerCase()]),$,{legacyMinimum:P,runtimeVersion:J()});if(v!==null)throw v.status===400?new m(400,v.code,v.message,v.param):new m(426,v.code,v.message,void 0,v.details);const h=new URL(r.url??"/","http://runtime.local");if(Ve(h.pathname)){await Ue(r,t,h,d);return}const R=b.match(r.method??"GET",h.pathname),a=R?I.get(R.handler):void 0,H=a?.name==="runtime.sync-notice"||a?.name==="runtime.vendor-status"||a?.name==="runtime.vendor-account-remove";let S,M;if(!H&&r.headers.authorization!==void 0)try{S=await d.verifyCall(r.headers.authorization)}catch(i){M=i}const x={issuer:e.issuer,jwks:d.jwks,audience:s(async()=>e.audience,"audience"),owner:ve,self:Re,syncGrants:o,ready:s(async()=>d.isReady()&&await n(),"ready")};if(S?.chain[0]?.sub.startsWith("runtime:")){await z(r,t,x,S);return}if(S===void 0&&a===void 0&&await _e(r.method??"GET",h.pathname)){await z(r,t,x,{status:401,code:"unauthorized",message:M===void 0?"a machine token is required":"invalid machine token"});return}if(a?.name==="ready"){const i=await n(),_=await ue({jwksReady:d.isReady(),grantsReady:s(()=>i,"grantsReady")});g(t,_.ready?200:503,_);return}if((r.method!=="GET"||h.pathname!=="/v1/health")&&(!d.isReady()||!await n()))throw new m(503,"runtime_starting","runtime_starting");if(!R||!a)throw new m(404,"not_found","unknown operation");A=R.params.run_id;const N=K(r.headers);if(a.name==="health"){g(t,200,{status:"ok",api_version:"2026-09-23"});return}if(a.name==="runtime.sync-notice"){await ge(await d.verifySyncNotice(r.headers.authorization),o,y),t.writeHead(204),t.end();return}if(a.name==="runtime.vendor-status"){await d.verifyDirectoryRead(r.headers.authorization,"vendor_status"),g(t,200,We());return}if(a.name==="runtime.vendor-account-remove"){await d.verifyDirectoryRead(r.headers.authorization,"vendor_account_remove"),g(t,200,await Qe(await C(r)));return}if(S===void 0)throw M??new m(401,"unauthorized","a directory access token is required");const u=await d.resolveVerified(S,a.scope);if(t.setHeader("Request-Id",y),A&&await L(u,A,["run.message","run.interrupt","run.cancel","run.rename","run.delete"].includes(a.name),a.name==="run.delete"),a.stage==="objects"){const i=D.match(a.method,h.pathname);if(!i)throw new m(404,"not_found","unknown operation");const _={...N===void 0?{}:{causedBy:N},method:a.method,path:h.pathname,params:i.params,query:h.searchParams,body:await C(r,i.maxBodyBytes),ceiling:u.resolved,principal:{class:"app",app:u.grantee,scopes:u.resolved,sub:u.sub},req:r,res:t};let l;try{l=await i.handler(_)}catch(O){const{status:c,body:k}=Z(O);throw c>=500&&console.error("[app-listener]",`trace_id=${E}`,O),new m(c,k.error.code,k.error.message,void 0,k.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 $e(r,t,u,h.searchParams);return}if(a.stream){await mt(r,t,A,u,ct(r,h.searchParams),y,"sse",p.stream,E);return}if(a.name==="llm"){const i=Ae(await C(r,Pe)),_=new AbortController,l=s(()=>_.abort(),"abort");t.on("close",l);try{const O=await Te(i,_.signal,i.stream?c=>{t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.write(`data: ${JSON.stringify(c)}
20
+ `),v())}},"checkIdle"),O=setInterval(()=>{l().catch(c=>Le({level:"error",event:"api.run_stream.idle_check_failed",error:c}))},I.idleCheckMs??1e3);return O.unref(),n.on("drain",h),n.on("close",v),await a(),P}s(ft,"streamRunEvents");async function or(e,n,o,p={}){const f=e.listener;if(!e.issuer||!e.audience||!f?.address||!Number.isInteger(f.port)||f.port<1||f.port>65535)throw new Error("runtime issuer, audience and listener address/port are required");if(["0.0.0.0","::","[::]"].includes(f.address))throw new Error("runtime listener must bind a specific address");const d=new _e(e.issuer,e.audience,o,e.jwksUrl),b=new V,I=new Map;for(const r of ue.filter(t=>t.stage!==void 0)){const t=s(()=>({status:500}),"handler");b.register({method:r.method,pattern:r.path,handler:t}),I.set(t,r)}const D=new V().registerAll(te).registerAll(re).registerAll(oe).registerAll(se).registerAll(ie).registerAll(ne).registerAll(ae),w=K((r,t)=>{(async()=>{De(r,t,p.deferHead);const y=q();t.setHeader("Request-Id",y);const E=ye(U(r.headers.traceparent))??we();t.setHeader(le,J()),t.setHeader(fe,$);let A;try{const P=U(r.headers[de.toLowerCase()]),v=me(P,J())??he(U(r.headers[pe.toLowerCase()]),$,{legacyMinimum:P,runtimeVersion:J()});if(v!==null)throw v.status===400?new m(400,v.code,v.message,v.param):new m(426,v.code,v.message,void 0,v.details);const h=new URL(r.url??"/","http://runtime.local");if(Xe(h.pathname)){await Ve(r,t,h,d);return}const R=b.match(r.method??"GET",h.pathname),a=R?I.get(R.handler):void 0,H=a?.name==="runtime.sync-notice"||a?.name==="runtime.vendor-status"||a?.name==="runtime.vendor-account-remove";let S,M;if(!H&&r.headers.authorization!==void 0)try{S=await d.verifyCall(r.headers.authorization)}catch(i){M=i}const x={issuer:e.issuer,jwks:d.jwks,audience:s(async()=>e.audience,"audience"),owner:ge,self:Oe,syncGrants:o,ready:s(async()=>d.isReady()&&await n(),"ready")};if(S?.chain[0]?.sub.startsWith("runtime:")){await z(r,t,x,S);return}if(S===void 0&&a===void 0&&await ve(r.method??"GET",h.pathname)){await z(r,t,x,{status:401,code:"unauthorized",message:M===void 0?"a machine token is required":"invalid machine token"});return}if(a?.name==="ready"){const i=await n(),_=await ce({jwksReady:d.isReady(),grantsReady:s(()=>i,"grantsReady")});g(t,_.ready?200:503,_);return}if((r.method!=="GET"||h.pathname!=="/v1/health")&&(!d.isReady()||!await n()))throw new m(503,"runtime_starting","runtime_starting");if(!R||!a)throw new m(404,"not_found","unknown operation");A=R.params.run_id;const N=Z(r.headers);if(a.name==="health"){g(t,200,{status:"ok",api_version:"2026-09-23"});return}if(a.name==="runtime.sync-notice"){await Re(await d.verifySyncNotice(r.headers.authorization),o,y),t.writeHead(204),t.end();return}if(a.name==="runtime.vendor-status"){await d.verifyDirectoryRead(r.headers.authorization,"vendor_status"),g(t,200,await qe());return}if(a.name==="runtime.vendor-account-remove"){await d.verifyDirectoryRead(r.headers.authorization,"vendor_account_remove"),g(t,200,await We(await C(r)));return}if(S===void 0)throw M??new m(401,"unauthorized","a directory access token is required");const u=await d.resolveVerified(S,a.scope);if(t.setHeader("Request-Id",y),A&&await L(u,A,["run.message","run.interrupt","run.cancel","run.rename","run.delete"].includes(a.name),a.name==="run.delete"),a.stage==="objects"){const i=D.match(a.method,h.pathname);if(!i)throw new m(404,"not_found","unknown operation");const _={...N===void 0?{}:{causedBy:N},method:a.method,path:h.pathname,params:i.params,query:h.searchParams,body:await C(r,i.maxBodyBytes),ceiling:u.resolved,principal:{class:"app",app:u.grantee,scopes:u.resolved,sub:u.sub},req:r,res:t};let l;try{l=await i.handler(_)}catch(O){const{status:c,body:k}=ee(O);throw c>=500&&console.error("[app-listener]",`trace_id=${E}`,O),new m(c,k.error.code,k.error.message,void 0,k.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 ze(r,t,u,h.searchParams);return}if(a.stream){await ft(r,t,A,u,dt(r,h.searchParams),y,"sse",p.stream,E);return}if(a.name==="llm"){const i=Te(await C(r,ke)),_=new AbortController,l=s(()=>_.abort(),"abort");t.on("close",l);try{const O=await Se(i,_.signal,i.stream?c=>{t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.write(`data: ${JSON.stringify(c)}
21
21
 
22
- `)}:void 0,void 0,{grantee:u.grantee,sub:u.sub,spend_cap:u.spend_cap,request:y},be(await Y(u.grant)??await Be(u.grant)),N);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:u.grantee,sub:u.sub,spend_cap:u.spend_cap,request:y},Ae(await Y(u.grant)??await je(u.grant)),N);i.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
- `)):g(t,200,O.completion)}finally{t.off("close",l)}return}if(a.name==="exec"){const{signal:i,release:_}=F(t);try{g(t,200,await et(u,await C(r,Ze),i))}finally{_()}return}if(a.name==="usage.get"){g(t,200,await Ne(u.grantee,Se(h.searchParams.get("month"))));return}if(a.name==="profile.list"){g(t,200,Xe(u));return}if(Fe.has(a.name)){const i=await Ye(a.name,u,R.params.question_id,a.method==="POST"?await C(r):void 0);g(t,i.status,i.body);return}if(nt.has(a.name)){const{signal:i,release:_}=F(t);try{const l=await rt(a.name,tt(u),{params:R.params,body:a.method==="POST"?await C(r):void 0,query:h.searchParams},{requestId:y,traceId:E,signal:i,...N===void 0?{}:{causedBy:N}});g(t,l.status,l.body)}catch(l){const O=at(l,y,!0);t.writeHead(O.status,{"Content-Type":"application/json; charset=utf-8","X-Content-Type-Options":"nosniff",...O.headers}),t.end(JSON.stringify(O.body))}finally{_()}return}if(Ke.has(a.name)){const i=await qe(a.name,{class:"app",app:u.grantee,scopes:u.resolved},h.searchParams);g(t,i.status,i.body);return}if(Ge.has(a.name)){const i=await ze(a,u,R.params,h.searchParams,await C(r));g(t,i.status,i.body);return}const B=await Oe(a,u,A,h.searchParams,await C(r),r.headers["idempotency-key"],N);g(t,B.status,B.body)}catch(P){ut(t,P,y,E,A)}})()});return{ready:new Promise((r,t)=>{w.once("error",t),w.listen(f.port,f.address,()=>{w.off("error",t),r()})}),close:s(async()=>{d.close(),je(),w.closeAllConnections(),await new Promise((r,t)=>w.close(y=>y?t(y):r()))},"close")}}s(nr,"createAppListener");export{lt as RUN_STREAM_IDLE_MS,nr as createAppListener,ct as cursor,mt as streamRunEvents};
24
+ `)):g(t,200,O.completion)}finally{t.off("close",l)}return}if(a.name==="exec"){const{signal:i,release:_}=F(t);try{g(t,200,await tt(u,await C(r,et),i))}finally{_()}return}if(a.name==="usage.get"){g(t,200,await Ce(u.grantee,Ne(h.searchParams.get("month"))));return}if(a.name==="profile.list"){g(t,200,await $e(u));return}if(Qe.has(a.name)){const i=await Fe(a.name,u,R.params.question_id,a.method==="POST"?await C(r):void 0);g(t,i.status,i.body);return}if(at.has(a.name)){const{signal:i,release:_}=F(t);try{const l=await nt(a.name,rt(u),{params:R.params,body:a.method==="POST"?await C(r):void 0,query:h.searchParams},{requestId:y,traceId:E,signal:i,...N===void 0?{}:{causedBy:N}});g(t,l.status,l.body)}catch(l){const O=ot(l,y,!0);t.writeHead(O.status,{"Content-Type":"application/json; charset=utf-8","X-Content-Type-Options":"nosniff",...O.headers}),t.end(JSON.stringify(O.body))}finally{_()}return}if(Ze.has(a.name)){const i=await Ke(a.name,{class:"app",app:u.grantee,scopes:u.resolved},h.searchParams);g(t,i.status,i.body);return}if(Ye.has(a.name)){const i=await Ge(a,u,R.params,h.searchParams,await C(r));g(t,i.status,i.body);return}const B=await Ee(a,u,A,h.searchParams,await C(r),r.headers["idempotency-key"],N);g(t,B.status,B.body)}catch(P){ct(t,P,y,E,A)}})()});return{ready:new Promise((r,t)=>{w.once("error",t),w.listen(f.port,f.address,()=>{w.off("error",t),r()})}),close:s(async()=>{d.close(),Je(),w.closeAllConnections(),await new Promise((r,t)=>w.close(y=>y?t(y):r()))},"close")}}s(or,"createAppListener");export{mt as RUN_STREAM_IDLE_MS,or as createAppListener,dt as cursor,ft as streamRunEvents};
@@ -0,0 +1,14 @@
1
+ export declare class PersonBearerVerifier {
2
+ readonly issuer: string;
3
+ readonly audience: string;
4
+ private readonly jwks;
5
+ constructor(issuer: string, audience: string, fetcher?: typeof fetch, jwksUrl?: string);
6
+ /** The `user:<id>` a valid person bearer names, or null. A JWKS that cannot be fetched throws (the listener logs it and answers 401). */
7
+ verify(token: string): Promise<string | null>;
8
+ /** The `user:<id>` a valid directory token for exactly `purpose` names, or null: a token with no `user:` sub is refused. */
9
+ verifyPurpose(token: string, purpose: string): Promise<string | null>;
10
+ /** The claims of a token this directory signed for this API with no `act`, or null. */
11
+ private claims;
12
+ }
13
+ /** The verifier `CRTR_DIRECTORY_URL` (issuer) and `CRTR_PUBLIC_API_URL` (audience) configure, built once; null when either is unset. */
14
+ export declare function personBearerVerifier(): PersonBearerVerifier | null;
@@ -0,0 +1 @@
1
+ var c=Object.defineProperty;var i=(n,e)=>c(n,"name",{value:e,configurable:!0});import{JwksCache as l}from"@north-light/identity";import{createLocalJWKSet as o,decodeProtectedHeader as d,jwtVerify as f}from"jose";const p=/^user:[a-z0-9][a-z0-9._-]*$/;class h{static{i(this,"PersonBearerVerifier")}issuer;audience;jwks;constructor(e,r,s=fetch,t){this.issuer=e,this.audience=r,this.jwks=new l(e,s,t)}async verify(e){const r=await this.claims(e);return r===null||r.purpose!==void 0?null:a(r)}async verifyPurpose(e,r){const s=await this.claims(e);return s===null||s.purpose!==r?null:a(s)}async claims(e){let r;try{r=d(e)}catch{return null}if(r.alg!=="ES256")return null;const s=await this.jwks.forKid(r.kid);let t;try{({payload:t}=await f(e,o(s),{issuer:this.issuer,audience:this.audience,algorithms:["ES256"],requiredClaims:["exp","sub"]}))}catch{return null}return t.act===void 0?t:null}}function a(n){const e=n.sub;return typeof e=="string"&&p.test(e)?e:null}i(a,"personOf");let u;function R(){if(u!==void 0)return u;const n=process.env.CRTR_DIRECTORY_URL||void 0,e=process.env.CRTR_PUBLIC_API_URL||void 0;return u=n===void 0||e===void 0?null:new h(n,e),u}i(R,"personBearerVerifier");export{h as PersonBearerVerifier,R as personBearerVerifier};
@@ -1,8 +1,8 @@
1
- var M=Object.defineProperty;var n=(r,e)=>M(r,"name",{value:e,configurable:!0});import{WebSocketServer as W}from"ws";import{isSafeNodeId as x}from"../../core/canvas/paths.js";import{getNode as B}from"../../core/canvas/index.js";import{BROKER_READ_CAPS as J,CLIENT_READ_CAPS as j,FrameDecoder as q,FrameOverflowError as z}from"../../core/runtime/broker-protocol.js";import{emitEvent as K}from"../../core/events/emit.js";import{classify as S}from"../../core/fault-classifier.js";import{clearFault as v,markNodeRead as Q,recordFault as A}from"../../core/canvas/recovery.js";import{decideAttachRevive as G}from"../../core/runtime/revive.js";import{connectViewSocket as X,probeViewSocket as Y,waitForBrokerViewSocket as Z}from"../../core/runtime/view-socket.js";import{isBeneathRefusal as I}from"../../core/spaces/open-beneath.js";import{attachViewer as N,detachViewer as ee,presentViewer as re}from"./viewer-presence.js";const te=new W({noServer:!0,maxPayload:J.maxLineBytes}),ae=25e3,oe=6e4;function ne(r,e=ae,l=oe){let a=!0,u=!1,o=Date.now();const i=n(()=>{a=!0},"acknowledge"),s=n(()=>{u||(u=!0,clearInterval(y),r.off("pong",i))},"stop");r.on("pong",i);const y=setInterval(()=>{if(Date.now()-o>l){a=!0;return}if(!a){s(),r.terminate();return}a=!1;try{r.ping()}catch{s(),r.terminate()}},e);return y.unref(),{stop:s,noteActivity:n(()=>{o=Date.now()},"noteActivity")}}n(ne,"startRemoteAttachHeartbeat");function R(r){const e=Buffer.from(r,"utf8");return e.byteLength<=123?r:e.subarray(0,123).toString("utf8")}n(R,"clampReason");function d(r,e,l,a,u){const o=JSON.stringify({error:{code:a,message:u,origin:"runtime"}}),i=`HTTP/1.1 ${e} ${l}\r
1
+ var q=Object.defineProperty;var n=(r,e)=>q(r,"name",{value:e,configurable:!0});import{WebSocketServer as z}from"ws";import{isSafeNodeId as N,viewSocketPath as K}from"../../core/canvas/paths.js";import{getNode as T}from"../../core/canvas/index.js";import{BROKER_READ_CAPS as Q,CLIENT_READ_CAPS as G,FrameDecoder as X,FrameOverflowError as Y}from"../../core/runtime/broker-protocol.js";import{emitEvent as O}from"../../core/events/emit.js";import{classify as A}from"../../core/fault-classifier.js";import{clearFault as v,markNodeRead as Z,recordFault as R}from"../../core/canvas/recovery.js";import{decideAttachRevive as I}from"../../core/runtime/revive.js";import{connectViewSocket as ee,connectWssView as re,probeViewSocket as te,waitForBrokerViewSocket as ae,waitForWssView as V}from"../../core/runtime/view-socket.js";import{liveExecutionForNode as ne}from"../../core/canvas/executions.js";import{runnerForExecution as oe}from"../../core/runtime/runner/index.js";import{isBeneathRefusal as ie}from"../../core/spaces/open-beneath.js";import{attachViewer as F,detachViewer as ce,holdViewerForRedial as se,presentViewer as le}from"./viewer-presence.js";const fe=new z({noServer:!0,maxPayload:Q.maxLineBytes}),ue=25e3,me=6e4;function de(r,e=ue,l=me){let a=!0,d=!1,o=Date.now();const i=n(()=>{a=!0},"acknowledge"),p=n(()=>{d||(d=!0,clearInterval(c),r.off("pong",i))},"stop");r.on("pong",i);const c=setInterval(()=>{if(Date.now()-o>l){a=!0;return}if(!a){p(),r.terminate();return}a=!1;try{r.ping()}catch{p(),r.terminate()}},e);return c.unref(),{stop:p,noteActivity:n(()=>{o=Date.now()},"noteActivity")}}n(de,"startRemoteAttachHeartbeat");function $(r){const e=Buffer.from(r,"utf8");return e.byteLength<=123?r:e.subarray(0,123).toString("utf8")}n($,"clampReason");function h(r,e,l,a,d){const o=JSON.stringify({error:{code:a,message:d,origin:"runtime"}}),i=`HTTP/1.1 ${e} ${l}\r
2
2
  content-type: application/json; charset=utf-8\r
3
3
  content-length: ${Buffer.byteLength(o)}\r
4
4
  connection: close\r
5
5
  \r
6
- `+o;try{r.end(i)}catch{try{r.destroy()}catch{}}}n(d,"refuseUpgrade");function ie(r){if(new URL(r.url??"/","http://127.0.0.1").searchParams.get("revive")==="0")return!0;const l=r.headers["x-crtr-attach-revive"];return(Array.isArray(l)?l[0]:l)==="0"}n(ie,"reviveOptedOut");function ce(r){return new URL(r.url??"/","http://127.0.0.1").searchParams.get("wakeParked")==="1"}n(ce,"wakeParkedRequested");function O(r){return r===1e3||r===1001||r===1005}n(O,"isCleanViewerClose");function h(r,e,l){l.catch(a=>K({level:"error",event:e,node_id:r,error:a}))}n(h,"detach");async function se(r,e,l){const a=[];let u=n(t=>{a.push(t)},"relayMessage");if(r.on("message",t=>u(t)),!x(e)){try{r.close(1008,R(`invalid node id: ${e}`))}catch{}return}if(await B(e)===null){try{r.close(1011,R(`no node ${e}`))}catch{}return}await v(e,{link:"viewer\u2194crtrd"});const o=X(e),i=new q(j);let s=!1,y=!1,g,$=!1,C=!1,w="controller",T=Promise.resolve(),k=!1;const b=[];let _=!1;o.on("connect",()=>{$=!0,!s&&k&&N(e,r),h(e,"daemon.bridge.connect_failed",v(e,{link:"relay\u2194broker"}))});const m=n((t,f)=>{if(!s){if(s=!0,ee(e,r),g?.stop(),!o.destroyed)try{o.destroy()}catch{}try{r.close(t,R(f))}catch{}}},"teardown");g=ne(r);const P=n(async t=>{g?.noteActivity();let f;try{f=i.push(t)}catch(c){const p=c instanceof z?`broker sent an oversized frame (${c.message})`:`failed to decode a broker frame for ${e}`;m(1009,p);return}b.push(...f),_||await D()},"onData"),D=n(async()=>{_=!0;try{for(;b.length>0&&!s;){const t=b.splice(0);let f;try{f=await l(w)}catch{m(1011,"revoked");return}if(s)return;if(!f){m(1008,"revoked");return}for(const c of t)if(r.readyState===r.OPEN&&(r.send(JSON.stringify(c)),k&&c?.type==="welcome"&&re(e,r)))try{await Q(e)}catch{}}}finally{_=!1}},"drainOutbound");o.on("data",t=>h(e,"daemon.bridge.data_failed",P(t)));const F=n(async t=>{const f=S("relay\u2194broker",t);await A(e,{link:"relay\u2194broker",op:"bridge socket",kind:f.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}`;m(1011,c)},"onSocketError");o.on("error",t=>h(e,"daemon.bridge.socket_error_failed",F(t)));const U=n(async t=>{s||t||(await v(e,{link:"relay\u2194broker"}),m(1e3,"broker socket closed"))},"onSocketClose");o.on("close",t=>h(e,"daemon.bridge.socket_close_failed",U(t)));const V=n(async(t,f)=>{const c=f.toString("utf8");if(s){O(t)&&await v(e,{link:"viewer\u2194crtrd"});return}if(O(t))await v(e,{link:"viewer\u2194crtrd"});else if(!y){y=!0;const p=S("viewer\u2194crtrd",{code:t,reason:c});await A(e,{link:"viewer\u2194crtrd",op:"remote attach websocket",kind:p.kind,retry:{disposition:"auto"},message:c||`remote attach closed (${t})`})}m(t,c||`remote attach closed (${t})`)},"onWsClose");r.on("close",(t,f)=>h(e,"daemon.bridge.ws_close_failed",V(t,f)));const L=n(async()=>{if(!y){y=!0;const t=S("viewer\u2194crtrd",{code:1006,reason:"remote attach websocket error"});await A(e,{link:"viewer\u2194crtrd",op:"remote attach websocket",kind:t.kind,retry:{disposition:"auto"},message:"remote attach websocket error"})}m(1011,"remote attach websocket error")},"onWsError");r.on("error",()=>h(e,"daemon.bridge.ws_error_failed",L())),u=n(t=>{if(s||o.destroyed)return;g?.noteActivity();const c=(Array.isArray(t)?Buffer.concat(t):Buffer.isBuffer(t)?t:Buffer.from(new Uint8Array(t))).toString("utf8");if(!C)try{const E=JSON.parse(c);E?.type==="hello"&&(C=!0,w=E.role==="observer"?"observer":"controller",k=E.attends!==!1,k&&$&&N(e,r))}catch{}const p=c.endsWith(`
7
- `)?c:c+`
8
- `,H=n(()=>{try{o.write(p)}catch{}},"write");T=T.then(async()=>{s||(await l(w)?H():m(1008,"revoked"))}).catch(()=>m(1011,"revoked"))},"relayMessage");for(const t of a.splice(0))u(t)}n(se,"bridgeConnection");async function be(r,e,l,a,u){e.on("error",()=>{});try{if(!x(a)){d(e,400,"Bad Request","invalid_node_id",`invalid node id: ${a}`);return}if(await B(a)===null){d(e,404,"Not Found","node_not_found",`no node ${a}`);return}if(ie(r)){if(!await Y(a,250)){d(e,409,"Conflict","node_dormant",`node ${a} is dormant and revive was opted out (?revive=0)`);return}}else{let o;try{const i=await G(a,{resume:!0,capacity:"refuse"},ce(r));if(i.parked){d(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 s=i instanceof Error?i.message:String(i);d(e,409,"Conflict","attach_revive_failed",`attach revive failed: ${s}`);return}if(!await Z(a,o)){d(e,409,"Conflict","broker_not_ready",`broker view socket for ${a} did not become listenable after revive`);return}}if(e.destroyed)return;te.handleUpgrade(r,e,l,o=>h(a,"daemon.bridge.connection_failed",se(o,a,u)))}catch(o){const i=o instanceof Error?o.message:String(o);if(I(o)){d(e,400,"Bad Request","invalid_request",i);return}d(e,500,"Internal Server Error","internal",`attach upgrade failed: ${i}`)}}n(be,"handleAttachUpgrade");export{ae as REMOTE_ATTACH_HEARTBEAT_MS,oe as REMOTE_ATTACH_QUIET_MS,be as handleAttachUpgrade,O as isCleanViewerClose,d as refuseUpgrade,ne as startRemoteAttachHeartbeat};
6
+ `+o;try{r.end(i)}catch{try{r.destroy()}catch{}}}n(h,"refuseUpgrade");function ye(r){if(new URL(r.url??"/","http://127.0.0.1").searchParams.get("revive")==="0")return!0;const l=r.headers["x-crtr-attach-revive"];return(Array.isArray(l)?l[0]:l)==="0"}n(ye,"reviveOptedOut");function he(r){return new URL(r.url??"/","http://127.0.0.1").searchParams.get("wakeParked")==="1"}n(he,"wakeParkedRequested");function P(r){return r===1e3||r===1001||r===1005}n(P,"isCleanViewerClose");function m(r,e,l){l.catch(a=>O({level:"error",event:e,node_id:r,error:a}))}n(m,"detach");async function D(r){const e=await ne(r);return e===null||e.runner==="process"?{kind:"unix",path:K(r)}:oe(e.runner).viewerAddress(e)}n(D,"brokerViewAddress");function pe(r,e){return e.kind==="wss"?re(e.url,e.headers):ee(r)}n(pe,"connectBrokerView");function we(r,e,l){return e.kind==="wss"?V(e.url,e.headers,void 0,l):te(r,l)}n(we,"probeBrokerView");async function ve(r,e,l,a){const d=[];let o=n(t=>{d.push(t)},"relayMessage");if(r.on("message",t=>o(t)),!N(e)){try{r.close(1008,$(`invalid node id: ${e}`))}catch{}return}if(await T(e)===null){try{r.close(1011,$(`no node ${e}`))}catch{}return}await v(e,{link:"viewer\u2194crtrd"});const i=pe(e,l),p=new X(G);let c=!1,w=!1,k,x=!1,C=!1,b="controller",B=Promise.resolve(),g=!1;const _=[];let E=!1;i.on("connect",()=>{x=!0,!c&&g&&m(e,"daemon.bridge.presence_failed",F(e,r)),m(e,"daemon.bridge.connect_failed",v(e,{link:"relay\u2194broker"}))});const y=n((t,f,s=!1)=>{if(!c){if(c=!0,m(e,"daemon.bridge.presence_failed",s?se(e,r):ce(e,r)),k?.stop(),!i.destroyed)try{i.destroy()}catch{}try{r.close(t,$(f))}catch{}}},"teardown");k=de(r);const U=n(async t=>{k?.noteActivity();let f;try{f=p.push(t)}catch(s){const u=s instanceof Y?`broker sent an oversized frame (${s.message})`:`failed to decode a broker frame for ${e}`;y(1009,u);return}_.push(...f),E||await L()},"onData"),L=n(async()=>{E=!0;try{for(;_.length>0&&!c;){const t=_.splice(0);let f;try{f=await a(b)}catch{y(1011,"revoked");return}if(c)return;if(!f){y(1008,"revoked");return}let s=!1;for(const u of t)r.readyState===r.OPEN&&(r.send(JSON.stringify(u)),u?.type==="welcome"&&(s=!0));if(g&&s)try{await le(e,r)&&await Z(e)}catch(u){O({level:"warn",event:"daemon.bridge.present_failed",node_id:e,error:u})}}}finally{E=!1}},"drainOutbound");i.on("data",t=>m(e,"daemon.bridge.data_failed",U(t)));const W=n(async t=>{const f=A("relay\u2194broker",t);await R(e,{link:"relay\u2194broker",op:"bridge socket",kind:f.kind,retry:{disposition:"manual"},message:t.message});const s=t.code==="ECONNREFUSED"||t.code==="ENOENT"?`no running broker for ${e}`:`view socket error for ${e}: ${t.message}`;y(1011,s,!0)},"onSocketError");i.on("error",t=>m(e,"daemon.bridge.socket_error_failed",W(t)));const H=n(async t=>{c||t||(await v(e,{link:"relay\u2194broker"}),y(1e3,"broker socket closed",!0))},"onSocketClose");i.on("close",t=>m(e,"daemon.bridge.socket_close_failed",H(t)));const J=n(async(t,f)=>{const s=f.toString("utf8");if(c){P(t)&&await v(e,{link:"viewer\u2194crtrd"});return}if(P(t))await v(e,{link:"viewer\u2194crtrd"});else if(!w){w=!0;const u=A("viewer\u2194crtrd",{code:t,reason:s});await R(e,{link:"viewer\u2194crtrd",op:"remote attach websocket",kind:u.kind,retry:{disposition:"auto"},message:s||`remote attach closed (${t})`})}y(t,s||`remote attach closed (${t})`)},"onWsClose");r.on("close",(t,f)=>m(e,"daemon.bridge.ws_close_failed",J(t,f)));const M=n(async()=>{if(!w){w=!0;const t=A("viewer\u2194crtrd",{code:1006,reason:"remote attach websocket error"});await R(e,{link:"viewer\u2194crtrd",op:"remote attach websocket",kind:t.kind,retry:{disposition:"auto"},message:"remote attach websocket error"})}y(1011,"remote attach websocket error")},"onWsError");r.on("error",()=>m(e,"daemon.bridge.ws_error_failed",M())),o=n(t=>{if(c||i.destroyed)return;k?.noteActivity();const s=(Array.isArray(t)?Buffer.concat(t):Buffer.isBuffer(t)?t:Buffer.from(new Uint8Array(t))).toString("utf8");if(!C)try{const S=JSON.parse(s);S?.type==="hello"&&(C=!0,b=S.role==="observer"?"observer":"controller",g=S.attends!==!1,g&&x&&m(e,"daemon.bridge.presence_failed",F(e,r)))}catch{}const u=s.endsWith(`
7
+ `)?s:s+`
8
+ `,j=n(()=>{try{i.write(u)}catch{}},"write");B=B.then(async()=>{c||(await a(b)?j():y(1008,"revoked"))}).catch(()=>y(1011,"revoked"))},"relayMessage");for(const t of d.splice(0))o(t)}n(ve,"bridgeConnection");async function Oe(r,e,l,a,d){e.on("error",()=>{});try{if(!N(a)){h(e,400,"Bad Request","invalid_node_id",`invalid node id: ${a}`);return}if(await T(a)===null){h(e,404,"Not Found","node_not_found",`no node ${a}`);return}let o;if(ye(r)){if(o=await D(a),!await we(a,o,250)){h(e,409,"Conflict","node_dormant",`node ${a} is dormant and revive was opted out (?revive=0)`);return}}else{let i;try{const c=await I(a,{resume:!0,capacity:"refuse"},he(r));if(c.parked){h(e,409,"Conflict","node_dormant",`node ${a} is parked; attach with ?wakeParked=1 to wake it`);return}i=c.result.launch?.exited}catch(c){const w=c instanceof Error?c.message:String(c);h(e,409,"Conflict","attach_revive_failed",`attach revive failed: ${w}`);return}if(o=await D(a),!(o.kind==="wss"?await V(o.url,o.headers,i):await ae(a,i))){h(e,409,"Conflict","broker_not_ready",`broker view socket for ${a} did not become listenable after revive`);return}}if(e.destroyed)return;fe.handleUpgrade(r,e,l,i=>m(a,"daemon.bridge.connection_failed",ve(i,a,o,d)))}catch(o){const i=o instanceof Error?o.message:String(o);if(ie(o)){h(e,400,"Bad Request","invalid_request",i);return}h(e,500,"Internal Server Error","internal",`attach upgrade failed: ${i}`)}}n(Oe,"handleAttachUpgrade");export{ue as REMOTE_ATTACH_HEARTBEAT_MS,me as REMOTE_ATTACH_QUIET_MS,Oe as handleAttachUpgrade,P as isCleanViewerClose,h as refuseUpgrade,de as startRemoteAttachHeartbeat};
@@ -1,11 +1,11 @@
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.id,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
1
+ var L=Object.defineProperty;var h=(n,a)=>L(n,"name",{value:a,configurable:!0});import{createHash as W,timingSafeEqual as A}from"node:crypto";import{createServer as U}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,warmDocumentWatchers as q}from"./reader.js";import{mergeDocumentLines as ee}from"./document-merge.js";import{crtrVersion as te}from"../../shared/crtr-version.js";const ne="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(te()),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=>W("sha256").update(i).digest(),"digest");return A(t(n),t(a))}h(P,"sameSecret");function oe(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(oe,"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 D(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(D,"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 ae(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(ae,"requestBody");async function re(n){await q(n.id);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.id,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?ee(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(re,"save");let v="the document listener has not started";function Te(){return v}h(Te,"documentListenerUnavailable");function Ee(n,a){const t=`crtr_doc_${n}`,i=U((o,e)=>{(async()=>{e.setHeader("Content-Security-Policy",ne),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=oe(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 D(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 ae(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 re(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
3
  `);const s=h(async _=>{if(_==="deleted"){e.write(`event: deleted
4
4
  data: {}
5
5
 
6
- `),e.end();return}const f=await p(r),g=f&&await L(f);g&&e.write(`event: edited
6
+ `),e.end();return}const f=await p(r),g=f&&await D(f);g&&e.write(`event: edited
7
7
  data: ${JSON.stringify({revision:g.revision,heads_key:g.heads_key})}
8
8
 
9
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(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};
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(Ee,"createDocumentListener");export{Ee as createDocumentListener,Te as documentListenerUnavailable};
@@ -0,0 +1,18 @@
1
+ import type { StartBundleRecipeDTO } from '../../api/index.js';
2
+ /** The environment object id a node runs in: its profile's `environment_id`, or the machine environment when it has none. */
3
+ export declare function environmentOfNode(profileId: string | null): Promise<string>;
4
+ /** SQL predicate over `environments`: the recipe has content (a repository, a setup script or pi packages). A recipe cleared back to nothing
5
+ * has none, whatever its `recipe_revision` counter says: the counter only orders edits, it does not say whether a recipe exists. */
6
+ export declare const RECIPE_HAS_CONTENT_SQL = "(btrim(COALESCE(environments.setup_script, '')) <> '' OR btrim(COALESCE(environments.pi_packages, '')) <> ''\n OR EXISTS (SELECT 1 FROM environment_repos r WHERE r.environment = environments.object))";
7
+ /** The environment's recipe; null when it has no content (no repositories, no setup script, no packages). One statement, so the revision,
8
+ * script, packages and repositories all come from one snapshot, never from either side of a concurrent `setEnvironmentRecipe`. */
9
+ export declare function recipeOf(environmentId: string): Promise<StartBundleRecipeDTO | null>;
10
+ /** True when the node runs in a Blaxel environment, where its sandbox is its worktree (D102). */
11
+ export declare function runsOnBlaxel(profileId: string | null): Promise<boolean>;
12
+ /** The worktree request a Blaxel node carries in its launch recipe: the recipe repository whose `/work/<name>` holds `cwd`,
13
+ * a branch `crtr/<node id>`, and the base (the caller's, else that repository's default branch). */
14
+ export declare function sandboxWorktreeRequest(profileId: string | null, cwd: string, nodeId: string, base: string | undefined): Promise<{
15
+ repository: string;
16
+ branch: string;
17
+ base: string;
18
+ }>;
@@ -0,0 +1,5 @@
1
+ var m=Object.defineProperty;var r=(n,e)=>m(n,"name",{value:e,configurable:!0});import{ApiError as E}from"../../api/errors.js";import{openDb as i}from"../../core/canvas/db.js";import{machineEnvironmentId as s}from"../../core/environments.js";async function a(n){return n===null?s():(await(await i()).prepare("SELECT environment_id FROM profiles WHERE id = ?").get(n))?.environment_id??s()}r(a,"environmentOfNode");const u=`(btrim(COALESCE(environments.setup_script, '')) <> '' OR btrim(COALESCE(environments.pi_packages, '')) <> ''
2
+ OR EXISTS (SELECT 1 FROM environment_repos r WHERE r.environment = environments.object))`;async function _(n){const e=await(await i()).prepare(`SELECT recipe_revision, setup_script, pi_packages, ${u} AS has_content,
3
+ (SELECT COALESCE(json_agg(json_build_object('name', r.name, 'github_full_name', r.github_full_name, 'default_branch', r.default_branch) ORDER BY r.position), '[]'::json)
4
+ FROM environment_repos r WHERE r.environment = environments.object) AS repositories
5
+ FROM environments WHERE object = ?`).get(n);return e===void 0||!e.has_content?null:{revision:Number(e.recipe_revision),repositories:JSON.parse(e.repositories),setup_script:e.setup_script,pi_packages:e.pi_packages}}r(_,"recipeOf");async function l(n){return(await(await i()).prepare("SELECT kind FROM environments WHERE object = ?").get(await a(n)))?.kind==="blaxel"}r(l,"runsOnBlaxel");async function O(n,e,p,c){const t=((await _(await a(n)))?.repositories??[]).find(o=>e===`/work/${o.name}`||e.startsWith(`/work/${o.name}/`));if(t===void 0)throw new E(400,"invalid_request",`--worktree needs a cwd inside one of the environment's repositories under /work, not ${e}`,{param:"worktree"});return{repository:t.name,branch:`crtr/${p}`,base:c??t.default_branch}}r(O,"sandboxWorktreeRequest");export{u as RECIPE_HAS_CONTENT_SQL,a as environmentOfNode,_ as recipeOf,l as runsOnBlaxel,O as sandboxWorktreeRequest};
@@ -1 +1 @@
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
+ 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{actsAsPerson as S,canReadNode as A}from"../router.js";import{filterAsync as E}from"../../../core/async-array.js";const M=new Set(["as_of","window","project"]);async function N(e){for(const[t]of e.query)if(!M.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"&&(S(c)||await A(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(N,"handleAnalytics");const F=[{method:"GET",pattern:"/v1/canvas/analytics",handler:N}];export{F as analyticsRoutes};
@@ -6,7 +6,7 @@ import type { AppPrincipal } from '../principal.js';
6
6
  * `GET /v1/profiles` for an app. `default` marks the caller's own default
7
7
  * profile. Creates, changes, and selects nothing beyond that default profile,
8
8
  * which `run.start` without `profile` would create the same way. */
9
- export declare function listAppProfiles(caller: AppPrincipal): {
9
+ export declare function listAppProfiles(caller: AppPrincipal): Promise<{
10
10
  profiles: Array<{
11
11
  profile_id: string;
12
12
  name: string;
@@ -14,4 +14,4 @@ export declare function listAppProfiles(caller: AppPrincipal): {
14
14
  default_kind: string;
15
15
  default: boolean;
16
16
  }>;
17
- };
17
+ }>;
@@ -1 +1 @@
1
- var s=Object.defineProperty;var t=(r,o)=>s(r,"name",{value:o,configurable:!0});import{covers as m}from"@north-light/identity";import{ensureAppProfile as a,listProfiles as l}from"../../../core/profiles/manifest.js";import{resolveRunKind as d}from"../../../core/runtime/launch-target.js";function P(r){const o=a(r.grantee).profileId;return{profiles:l().filter(({profileId:e,manifest:p})=>{const i=p.grantee??"app:terminal";if(i===r.grantee)return!0;const n=`crtr:memory:rw:${i}:profile:${e}`;return r.resolved.some(f=>m(f,n))}).map(e=>({profile_id:e.profileId,name:e.manifest.name,grantee:e.manifest.grantee??"app:terminal",default_kind:d(e),default:e.profileId===o}))}}t(P,"listAppProfiles");export{P as listAppProfiles};
1
+ var s=Object.defineProperty;var t=(r,o)=>s(r,"name",{value:o,configurable:!0});import{covers as a}from"@north-light/identity";import{ensureAppProfile as m,listProfiles as l}from"../../../core/profiles/manifest.js";import{resolveRunKind as d}from"../../../core/runtime/launch-target.js";async function I(r){const o=(await m(r.grantee)).profileId;return{profiles:l().filter(({profileId:e,manifest:n})=>{const i=n.grantee??"app:terminal";if(i===r.grantee)return!0;const p=`crtr:memory:rw:${i}:profile:${e}`;return r.resolved.some(f=>a(f,p))}).map(e=>({profile_id:e.profileId,name:e.manifest.name,grantee:e.manifest.grantee??"app:terminal",default_kind:d(e),default:e.profileId===o}))}}t(I,"listAppProfiles");export{I as listAppProfiles};
@@ -1 +1 @@
1
- var B=Object.defineProperty;var l=(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 A}from"node:path";import{createFileBeneath as g,existsBeneath as m,unlinkBeneath as $}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 f}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{checkStart as z}from"../../../core/runtime/start-check.js";import{activeBackgroundBashJobs as F,bashJobPaths as k,isBashJobProcessGroupAlive as M,readJobPgid as G,readJobPgidIdentity as H,isSafeBashJobId as I,readBashNiceness as Z,stopBackgroundBashJob as U}from"../../../core/bash-jobs.js";import{ApiError as i}from"../../../api/index.js";import{notFound as V}from"../../../core/errors.js";import{freshChildNodeExecPath as X}from"../../../core/runtime/branded-host.js";async function w(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(await f(o)===null)throw V(`unknown node: ${o}`,{received:o});const a=e.params.jobId;if(a!==void 0){if(!I(a))throw new i(400,"invalid_job_id",`invalid background job id: ${JSON.stringify(a)}`);return{nodeId:o,jobId:a,dir:await v(o)}}return{nodeId:o,dir:await v(o)}}l(w,"requireTarget");async function x(e){const{nodeId:o,dir:n}=await w(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 a=e.body;if(!a||typeof a!="object"||Array.isArray(a))throw new i(400,"invalid_request","job.start requires a JSON body");const d=a;await _(o,d.expected_execution_id);const r=d.job_id,s=d.cwd,p=d.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");const h=await f(o);if(await z({grantee:h.grantee??"app:terminal",sub:h.sub,grant_id:h.grant_id}),!O())throw new i(400,"invalid_request","job.start is only used with the root launcher");const t=k(n,r);if(!(m(t.root,t.jobRun)||m(t.root,t.jobBg))||![t.cmdSh,t.jobLog].every(c=>m(t.root,c)))throw new i(404,"job_not_found","job was not prepared by this node");const j=A(t.dir,"job.starting");try{g(t.root,j,"")}catch(c){throw c.code==="EEXIST"?new i(409,"job_already_started","job was already started"):c}let u;try{const c=p,b=L("bash",c,s),y=await f(o),S=await X();return u=await q({nodeId:o,app:y.grantee??"app:terminal",isolated:y.isolated,cwd:s,env:c,capture:!1,command:[b,"-c",N,"--",t.cmdSh,t.jobLog,t.jobExit,t.jobRun,t.jobDone,b,String(Z(n)),S,t.jobActivity]}),g(t.root,t.jobPgid,String(u.pid),384),g(t.root,t.jobPgidIdentity,`launcher:${u.pid}`,384),{status:201,body:{pid:u.pid}}}catch(c){if(u!==void 0)try{await u.stop()}catch(b){throw new AggregateError([c,b],`job ${r} launched but could not be recorded or stopped`)}try{$(t.root,j)}catch(b){if(b.code!=="ENOENT")throw b}throw c}}l(x,"handleStart");async function K(e){const{nodeId:o,dir:n}=await w(e),a=Date.now();return{status:200,body:F(n).map(r=>{const s=G(n,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,a-r.startedAtMs),pgid:s,pgid_alive:s!==null&&M(s,H(n,r.jobId))}})}}l(K,"handleList");async function Q(e){const{nodeId:o,jobId:n,dir:a}=await w(e);if(n===void 0)throw new i(400,"invalid_request","a job id is required");const d=e.query.get("foreground")==="1";if(d){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");await _(o,e.body?.expected_execution_id)}const r=await U(a,n,d,o);if(r.kind==="missing")throw new i(404,"job_not_found",`no background job ${n} for ${o}`);if(r.kind==="retired")throw new i(404,"job_not_found",`background job ${n} for ${o} is no longer running`,{log_path:r.logPath});if(r.kind==="not-stoppable")throw new i(409,"job_not_stoppable",`job ${n} recorded no trusted process identity`,{log_path:r.logPath});if(d)return{status:200,body:{node_id:o,job_id:n,signaled:r.signaled}};await R(o),await E(n,async h=>{const t=await P(h,e);return t.class==="person"?t.person:t.class==="app"?t.app:t.node});const s=await f(o);if(s!==null&&!D(s))try{await C(o,{resume:!0,capacity:"freeze"})}catch{}return{status:200,body:{node_id:o,job_id:n,signaled:r.signaled}}}l(Q,"handleStop");async function W(e){const{nodeId:o,jobId:n,dir:a}=await w(e);if(n===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 d=e.body,r=k(a,n);if(typeof d?.command!="string"||d.job_dir!==r.dir||d.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 ${n} of ${o} is not backgrounded`);const s=d.command;return{status:201,body:{id:(await J(o,n,{command:s,jobDir:r.dir,logPath:r.jobLog})).id}}}l(W,"handleBackground");const _o=[{method:"POST",pattern:"/v1/nodes/:id/jobs/:jobId/background",handler:W},{method:"POST",pattern:"/v1/nodes/:id/jobs/start",handler:x},{method:"GET",pattern:"/v1/nodes/:id/jobs",handler:K},{method:"DELETE",pattern:"/v1/nodes/:id/jobs/:jobId",handler:Q}];export{_o as bashJobRoutes};
1
+ var O=Object.defineProperty;var w=(o,e)=>O(o,"name",{value:e,configurable:!0});import{killBashJobObject as P,recordBashJobObject as R}from"../../../core/spaces/stop.js";import{readerFor as T}from"../reader.js";import{join as F}from"node:path";import{createFileBeneath as v,existsBeneath as _,unlinkBeneath as C}from"../../../core/spaces/open-beneath.js";import{launchAppProcess as M,appProcessSandboxed as D}from"../../../core/spaces/process.js";import{BASH_JOB_SUPERVISOR_SCRIPT as L}from"../../../core/bash-job-supervisor.js";import{resolveAdmittedHostCommand as z}from"../../../core/runtime/spawn-env.js";import{requireCurrentExecution as k}from"./broker-recovery.js";import{isSafeNodeId as H}from"../../../core/canvas/paths.js";import{contextDir as I}from"../../../core/canvas/node-agent-paths.js";import{getNode as g}from"../../../core/canvas/canvas.js";import{isBrokerLive as x}from"../../../core/runtime/model-swap.js";import{assertNotFinalized as G}from"../../../core/runtime/reopen.js";import{reviveNode as K}from"../../../core/runtime/revive.js";import{checkStart as W}from"../../../core/runtime/start-check.js";import{bashJobPaths as $,isBashJobProcessGroupAlive as Z,isSafeBashJobId as A,readBashNiceness as Q,signalBashJob as U,stopBackgroundBashJob as V}from"../../../core/bash-jobs.js";import{applyJobReport as X,ownerRunsRemotely as B,runningJobs as j,setJobDeadline as E,markJobQuietOk as Y}from"../../../core/graph/jobs.js";import{withCanvasWrite as S,openDb as m}from"../../../core/canvas/db.js";import{getById as J}from"../../../core/graph/objects.js";import{blobStore as ee}from"../../../core/blobs/index.js";import{ApiError as r}from"../../../api/index.js";import{notFound as te}from"../../../core/errors.js";import{freshChildNodeExecPath as oe}from"../../../core/runtime/branded-host.js";async function y(o){const e=o.params.id;if(e===void 0||!H(e))throw new r(400,"invalid_node_id",`invalid node id: ${JSON.stringify(e)}`);if(await g(e)===null)throw te(`unknown node: ${e}`,{received:e});const i=o.params.jobId;if(i!==void 0){if(!A(i))throw new r(400,"invalid_job_id",`invalid background job id: ${JSON.stringify(i)}`);return{nodeId:e,jobId:i,dir:await I(e)}}return{nodeId:e,dir:await I(e)}}w(y,"requireTarget");async function ne(o){const{nodeId:e,dir:n}=await y(o);if(o.principal.class!=="broker"||o.principal.node!==e)throw new r(403,"permission_error","only this node\u2019s broker may start a job");const i=o.body;if(!i||typeof i!="object"||Array.isArray(i))throw new r(400,"invalid_request","job.start requires a JSON body");const u=i;await k(e,u.expected_execution_id);const t=u.job_id,a=u.cwd,d=u.env;if(typeof t!="string"||!A(t)||typeof a!="string"||!d||typeof d!="object"||Array.isArray(d)||Object.entries(d).some(([p,b])=>!/^[A-Za-z_][A-Za-z0-9_]*$/.test(p)||typeof b!="string"))throw new r(400,"invalid_request","invalid job id, cwd or environment");const c=await g(e);if(await W({grantee:c.grantee??"app:terminal",sub:c.sub,grant_id:c.grant_id}),!D())throw new r(400,"invalid_request","job.start is only used with the root launcher");const s=$(n,t);if(!(_(s.root,s.jobRun)||_(s.root,s.jobBg))||![s.cmdSh,s.jobLog].every(p=>_(s.root,p)))throw new r(404,"job_not_found","job was not prepared by this node");const f=F(s.dir,"job.starting");try{v(s.root,f,"")}catch(p){throw p.code==="EEXIST"?new r(409,"job_already_started","job was already started"):p}let h;try{const p=d,b=z("bash",p,a),q=await g(e),N=await oe();return h=await M({nodeId:e,app:q.grantee??"app:terminal",isolated:q.isolated,cwd:a,env:p,capture:!1,command:[b,"-c",L,"--",s.cmdSh,s.jobLog,s.jobExit,s.jobRun,s.jobDone,b,String(Q(n)),N,s.jobActivity]}),v(s.root,s.jobPgid,String(h.pid),384),v(s.root,s.jobPgidIdentity,`launcher:${h.pid}`,384),{status:201,body:{pid:h.pid}}}catch(p){if(h!==void 0)try{await h.stop()}catch(b){throw new AggregateError([p,b],`job ${t} launched but could not be recorded or stopped`)}try{C(s.root,f)}catch(b){if(b.code!=="ENOENT")throw b}throw p}}w(ne,"handleStart");async function ie(o){const{nodeId:e}=await y(o),n=Date.now(),i=await B(await m(),e);return{status:200,body:(await j(await m(),e)).map(t=>({job_id:t.jobId,command:t.command,purpose:t.purpose,started_at:new Date(t.startedAtMs).toISOString(),elapsed_ms:Math.max(0,n-t.startedAtMs),output_key:t.outputKey,deadline_at:t.deadlineAtMs===null?null:new Date(t.deadlineAtMs).toISOString(),pgid:t.pgid,pgid_alive:!i&&t.pgid!==null&&t.pgidIdentity!==null&&Z(t.pgid,t.pgidIdentity)}))}}w(ie,"handleList");async function re(o){const{nodeId:e,jobId:n,dir:i}=await y(o);if(n===void 0)throw new r(400,"invalid_request","a job id is required");if(o.query.get("foreground")==="1"){if(o.principal.class!=="broker"||o.principal.node!==e)throw new r(403,"permission_error","only this node\u2019s broker may abort its foreground job");await k(e,o.body?.expected_execution_id);const l=await V(i,n,!0,e);if(l.kind==="missing")throw new r(404,"job_not_found",`no job ${n} for ${e}`);if(l.kind==="retired")throw new r(404,"job_not_found",`job ${n} for ${e} is no longer running`);if(l.kind==="not-stoppable")throw new r(409,"job_not_stoppable",`job ${n} recorded no trusted process identity`);return{status:200,body:{node_id:e,job_id:n,signaled:l.signaled}}}const t=(await j(await m(),e)).find(l=>l.jobId===n);if(t===void 0)throw new r(404,"job_not_found",`no running background job ${n} for ${e}`);const a=await B(await m(),e);if(!a&&(t.pgid===null||t.pgidIdentity===null))throw new r(409,"job_not_stoppable",`job ${n} reported no trusted process identity`);await G(e);const d=a?!0:await U(t.pgid,t.pgidIdentity,e);await P(n,async l=>{const f=await T(l,o);return f.class==="person"?f.person:f.class==="app"?f.app:f.node});const c=await g(e);if(c!==null&&!x(c))try{await K(e,{resume:!0,capacity:"freeze"})}catch{}return{status:200,body:{node_id:e,job_id:n,signaled:d}}}w(re,"handleStop");async function ae(o){const{nodeId:e,jobId:n,dir:i}=await y(o);if(n===void 0)throw new r(400,"invalid_request","a job id is required");if(o.principal.class!=="broker"||o.principal.node!==e)throw new r(403,"permission_error","only this node\u2019s broker may record its job");const u=o.body,t=$(i,n),a=u?.purpose,d=u?.deadline_at_ms;if(typeof u?.command!="string"||a!=null&&typeof a!="string"||d!=null&&!Number.isFinite(d))throw new r(400,"invalid_request","job.background requires command, and optionally purpose and deadline_at_ms");if(!_(t.root,t.jobBg))throw new r(404,"job_not_found",`job ${n} of ${e} is not backgrounded`);return{status:201,body:{id:(await R(e,n,{command:u.command,purpose:a??null,deadlineAtMs:d??null})).id}}}w(ae,"handleBackground");async function de(o,e){if(e===void 0)throw new r(400,"invalid_request","a job id is required");const n=await J(await m(),e);if(n===null||n.type!=="job"||n.owner!==o)throw new r(404,"job_not_found",`no job ${e} for ${o}`);if(!(await j(await m(),o)).some(i=>i.jobId===e))throw new r(409,"job_not_running",`job ${e} for ${o} is no longer running`);return e}w(de,"requireRunningJob");async function se(o){const{nodeId:e,jobId:n}=await y(o);if(o.principal.class!=="broker"||o.principal.node!==e)throw new r(403,"permission_error","only this node\u2019s broker may report its job");const i=o.body;if(!i||typeof i!="object"||Array.isArray(i))throw new r(400,"invalid_request","job.report requires a JSON body");await k(e,i.expected_execution_id);const u=await J(await m(),n??"");if(u===null||u.type!=="job"||u.owner!==e)throw new r(404,"job_not_found",`no job ${String(n)} for ${e}`);if(!(await j(await m(),e)).some(d=>d.jobId===n))throw new r(409,"job_not_running",`job ${String(n)} for ${e} is no longer running`);const t=i.output;if(t!==void 0){if(!Number.isSafeInteger(t.seq)||t.seq<0||typeof t.data_base64!="string")throw new r(400,"invalid_request","output requires seq and data_base64");const d=await S(async c=>await c.prepare("SELECT output_key FROM jobs WHERE object = ?").get(n));await(await ee()).put(`${d.output_key}/${String(t.seq).padStart(8,"0")}`,Buffer.from(t.data_base64,"base64"))}const a=i.activity;if(a!==void 0&&(!Number.isFinite(a.last_ms)||!Number.isFinite(a.sampled_ms)||!Array.isArray(a.files)))throw new r(400,"invalid_request","activity requires last_ms, sampled_ms and files");return await S(async d=>X(d,n,{...typeof i.pgid=="number"?{pgid:i.pgid}:{},...typeof i.pgid_identity=="string"?{pgidIdentity:i.pgid_identity}:{},...typeof i.exit_code=="number"?{exitCode:i.exit_code}:{},...i.vanished===!0?{vanished:!0}:{},...a===void 0?{}:{activity:{lastActivityMs:a.last_ms,sampledAtMs:a.sampled_ms,files:a.files}}})),{status:204}}w(se,"handleReport");async function ue(o){const{nodeId:e,jobId:n}=await y(o),i=await de(e,n),u=o.body,t=u?.deadline_at_ms,a=u?.keep===!0;if(u?.quiet_ok!==!0&&!a&&!Number.isFinite(t))throw new r(400,"invalid_request","patch requires quiet_ok, keep or deadline_at_ms");if(a&&t!==void 0)throw new r(400,"invalid_request","keep and deadline_at_ms are exclusive");return await S(async d=>{u?.quiet_ok===!0&&await Y(d,i),a?await E(d,i,null):Number.isFinite(t)&&await E(d,i,t)}),{status:204}}w(ue,"handlePatch");const Pe=[{method:"POST",pattern:"/v1/nodes/:id/jobs/:jobId/background",handler:ae},{method:"POST",pattern:"/v1/nodes/:id/jobs/:jobId/report",handler:se},{method:"PATCH",pattern:"/v1/nodes/:id/jobs/:jobId",handler:ue},{method:"POST",pattern:"/v1/nodes/:id/jobs/start",handler:ne},{method:"GET",pattern:"/v1/nodes/:id/jobs",handler:ie},{method:"DELETE",pattern:"/v1/nodes/:id/jobs/:jobId",handler:re}];export{Pe 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[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
+ var p=Object.defineProperty;var c=(o,t)=>p(o,"name",{value:t,configurable:!0});import{statSync as u}from"node:fs";import{isAbsolute as l}from"node:path";import{ApiError as d}from"../../../api/index.js";import{buildOperationalEnvBase as f}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{localEnvironmentSecrets as b}from"../../../core/secrets/environment-owner.js";import{usage as i}from"../../../core/errors.js";import{appOf as y}from"../router.js";const h=60,m=600,T=256*1024;function E(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"||!l(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 e=t.timeout_s??h;if(typeof e!="number"||!Number.isFinite(e)||e<=0||e>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:e,env:n,profile:t.profile}}c(E,"parseRequest");async function A(o){const t=E(o.body),e=y(o.principal)??"app:terminal";if(e!=="app:terminal"&&t.profile!==void 0)throw new d(403,"permission_error","app bash cannot select an owner profile");const n=e==="app:terminal"?t.profile??null:null,s=f({targetCwd:t.cwd,targetProfileId:n,skipSpawnAllow:e!=="app:terminal"}),a={...s,...await b(n,e),...t.env,...n===null?{}:{CRTR_PROFILE_ID:n},CRTR_ADMITTED_HOST_PATH:s.CRTR_ADMITTED_HOST_PATH},r=await(await w({app:e,...o.principal.class==="broker"?{nodeId:o.principal.node,isolated:(await _(o.principal.node))?.isolated===!0}:{},command:t.command,cwd:t.cwd,env:a,timeoutMs:t.timeout_s*1e3,headBytes:T})).completion;if(r.processError!==null)throw r.processError;return{status:200,body:{exit_code:r.timedOut?null:r.exitCode,signal:r.signal,stdout:r.stdout,stdout_truncated:r.stdoutTruncated,stderr:r.stderr,stderr_truncated:r.stderrTruncated,timed_out:r.timedOut,duration_ms:r.durationMs}}}c(A,"handleBash");const H=[{method:"POST",pattern:"/v1/bash",scope:"crtr:act",handler:A}];export{H as bashRoutes};
@@ -2,4 +2,7 @@ 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
4
  export declare function extensionNode(node: NonNullable<Awaited<ReturnType<typeof getNode>>>): Promise<BrokerExtensionNodeDTO>;
5
+ /** crtrd sets this once at boot from its role: only a process that runs the reconciler lanes starts run observers (an api
6
+ * process leaves them to `pollRunObservers` in the reconcile process). */
7
+ export declare function setRequestsStartRunObservers(enabled: boolean): void;
5
8
  export declare const brokerOperationRoutes: RouteTable;
@@ -1 +1 @@
1
- var O=Object.defineProperty;var r=(e,t)=>O(e,"name",{value:t,configurable:!0});import{canonicalSessionFile as R,findNodeBySessionFile as T,getNode as y,isWarmSpare 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 A}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 B}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 ie}from"../router.js";import{requireCurrentExecution as m}from"./broker-recovery.js";import{ensureRunObserver as oe}from"../../runs/observer.js";import{parseNodeTelemetryRecord as re,writeNodeTelemetryRecord as ae}from"./telemetry-record.js";import{mapAsync as N}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 se(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(se,"parseSessionBoundBody");function de(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(de,"parseSettleBody");function ce(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(ce,"parseParkCompleteBody");function ue(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=re(t);return{...n,expected_execution_id:t.expected_execution_id,updated_at:new Date(n.updated_at).toISOString()}}r(ue,"parseTelemetryBody");function le(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(le,"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 pe(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 N((await N(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 I(e),ancestors:n,children:a,fork_source:c===null?null:await k(c),subject:d,roadmap:await Y(e)}}r(pe,"extensionState");function F(e,t){return e?.kind===t.kind&&e?.mode===t.mode&&e?.lifecycle===t.lifecycle}r(F,"samePersona");function me(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(me,"parseGeneratedNameBody");function fe(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(fe,"parsePersonaAckBody");async function we(e){const t=e.params.id,n=se(e.body),o=n.sessionFile===null?null:R(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 T(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(we,"handleSessionBound");async function ye(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 A(e)?{action:"stay_dormant"}:{action:"shutdown"}:i.reason!=="awaiting"&&i.reason!=="scheduled"?{action:"stay_dormant"}:await _(e)!==null||H(e)||await A(e)?{action:"stay_dormant"}:(await h(e,"release"),{action:"shutdown"})}r(ye,"settleBroker");async function he(e){const t=e.params.id,n=de(e.body);await m(t,n.expected_execution_id);const o=await l(async()=>await ye(t,n));return o.action!=="reprompt"&&Z(t).catch(i=>B({level:"error",event:"api.broker_ops.companion_submit_failed",node_id:t,error:i})),{status:200,body:o}}r(he,"handleSettle");async function _e(e){const t=e.params.id,n=ce(e.body);return await m(t,n.expected_execution_id),{status:200,body:await l(async()=>{const i=ee(t);if(i===void 0)return{action:"stay_dormant"};const a=await f(t);return await ne(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}),B({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(_e,"handleParkComplete");async function ke(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:te(t)?"recorded":"none"}))}}r(ke,"handleParkActivity");async function be(e){const t=e.params.id,n=ue(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}),ae(t,n)}),{status:204}}r(be,"handleTelemetry");async function ge(e){const t=e.params.id,n=le(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(ge,"handleModelCommit");async function ve(e){const t=e.params.id,n=await f(t);return n.run_id&&await oe(t,n.run_id),{status:200,body:await pe(t)}}r(ve,"handleExtensionState");async function xe(e){const t=e.params.id,n=me(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(xe,"handleGeneratedName");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),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!F(a,n.to)||!F(d,n.from)?{applied:!1}:(await g(t,{persona_ack:n.to}),{applied:!0})})}}r(Se,"handlePersonaAck");const tt=ie([{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:we},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:he},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:_e},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:ke},{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{tt as brokerOperationRoutes,k as extensionNode};
1
+ var N=Object.defineProperty;var a=(t,e)=>N(t,"name",{value:e,configurable:!0});import{canonicalSessionFile as B,findNodeBySessionFile as I,getNode as h,isWarmSpare as C,recordRespawnAttempt as q,recordSettledTurn as M,setPresence as k,subscriptionsOf as $,updateNode as v,updateNodeTelemetry as j}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as D,recordExecutionIdle as L,recordExecutionPid as U}from"../../../core/canvas/executions.js";import{bindSession as W,readLiveSession as G,transferSession as H}from"../../../core/canvas/sessions.js";import{isSafeNodeId as V}from"../../../core/canvas/paths.js";import{appForNode as J}from"../../../core/canvas/node-agent-paths.js";import{isPidAlive as Y}from"../../../core/canvas/pid.js";import{editorLabel as x}from"../../../core/canvas/labels.js";import{assembleNodeSubject as z}from"../../../core/substrate/subject.js";import{openDb as K,withCanvasWrite as p}from"../../../core/canvas/db.js";import{runningJobs as Q}from"../../../core/graph/jobs.js";import{notFound as g,usage as u}from"../../../core/errors.js";import{hasUnseenWakeMail as S}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as X}from"../../../core/runtime/kickoff.js";import{readRoadmap as Z}from"../../../core/runtime/roadmap.js";import{forkSourceNode as ee}from"../../../core/runtime/nodes.js";import{transition as _}from"../../../core/runtime/lifecycle.js";import{confirmViewer as P,probeViewer as R,tearDownNode as O}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as te}from"../viewer-presence.js";import{evaluateStop as ne}from"../../../core/runtime/stop-guard.js";import{clearFault as w,recordFault as ie}from"../../../core/canvas/recovery.js";import{updateModelRecipe as oe}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as re}from"../../review/finish.js";import{emitEvent as F}from"../../../core/events/emit.js";import{consumePendingPark as ae,recordPendingParkActivity as se}from"../../park-pending.js";import{shouldParkAfterSummary as de}from"../../park-activity.js";import{ownerOnly as ce}from"../router.js";import{situationalContextEnvelope as ue}from"../../../core/runtime/situational-context.js";import{requireCurrentExecution as f}from"./broker-recovery.js";import{ensureRunObserver as le}from"../../runs/observer.js";import{parseNodeTelemetryRecord as pe,writeNodeTelemetryRecord as fe}from"./telemetry-record.js";import{mapAsync as E}from"../../../core/async-array.js";function l(t,e){if(typeof t!="object"||t===null||Array.isArray(t))throw u(`${e} requires a JSON body`);return t}a(l,"objectBody");function me(t){const e=l(t,"broker session-bound");if(typeof e.executionId!="string"||e.executionId==="")throw u("executionId must be a non-empty string");if(typeof e.piSessionId!="string"||e.piSessionId==="")throw u("piSessionId must be a non-empty string");if(e.sessionFile!==null&&typeof e.sessionFile!="string")throw u("sessionFile must be a string or null");if(!Number.isSafeInteger(e.pid)||e.pid<=0)throw u("pid must be a positive safe integer");if(e.reason!==null&&typeof e.reason!="string")throw u("reason must be a string or null");if(!Array.isArray(e.reviewBoundaryIds)||!e.reviewBoundaryIds.every(n=>typeof n=="string"))throw u("reviewBoundaryIds must be an array of strings");return e}a(me,"parseSessionBoundBody");function we(t){const e=l(t,"broker settle");if(typeof e.stopReason!="string")throw u("stopReason must be a string");for(const n of["pushedFinal"])if(typeof e[n]!="boolean")throw u(`${n} must be a boolean`);return e}a(we,"parseSettleBody");function ye(t){const e=l(t,"broker park-complete");if(e.outcome!=="completed"&&e.outcome!=="failed")throw u("outcome must be completed or failed");return e}a(ye,"parseParkCompleteBody");function he(t){const e=l(t,"broker telemetry");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw u("expected_execution_id must be a non-empty string");const n=pe(e);return{...n,expected_execution_id:e.expected_execution_id,updated_at:new Date(n.updated_at).toISOString()}}a(he,"parseTelemetryBody");function _e(t){const e=l(t,"broker model");if(typeof e.spec!="string"||e.spec.trim()==="")throw u("spec must be a non-empty string");const n=e.intent;if(n!==void 0){const i=n!==null&&typeof n=="object"?n:void 0;if(i===void 0||typeof i.family!="string"||i.family===""||!["ultra","strong","medium","light"].includes(i.strength))throw u("intent must be { family, strength } with strength ultra|strong|medium|light when present")}if(typeof e.userSelected!="boolean")throw u("userSelected must be a boolean");return e}a(_e,"parseModelCommitBody");async function m(t){const e=await h(t);if(e===null)throw g(`unknown node: ${t}`,{received:t});return e}a(m,"requireNode");async function b(t){return{node_id:t.node_id,grantee:await J(t.node_id),name:t.name,...t.description===void 0?{}:{description:t.description},...t.title===void 0?{}:{title:t.title},...t.icon===void 0?{}:{icon:t.icon},kind:t.kind,mode:t.mode,lifecycle:t.lifecycle,status:t.status,cwd:t.cwd,parent:t.parent??null,fork_from:t.fork_from??null,profile_id:t.profile_id??null,...t.managed_worktree===void 0?{}:{managed_worktree:t.managed_worktree===null?null:{state:t.managed_worktree.state,...t.managed_worktree.cleanup===void 0?{}:{cleanup:t.managed_worktree.cleanup},path:t.managed_worktree.path,branch:t.managed_worktree.branch,base_ref:t.managed_worktree.base_ref,base_sha:t.managed_worktree.base_sha}},...t.review_binding===void 0?{}:{review_binding:t.review_binding??null},intent:t.intent??null,...t.persona_ack===void 0?{}:{persona_ack:t.persona_ack},created:t.created}}a(b,"extensionNode");async function be(t){const e=await m(t),n=[],i=new Set([t]);let o=e.parent??null;for(;o!==null&&o!==""&&!i.has(o);){i.add(o);const s=await h(o);if(s===null)break;n.unshift(await b(s)),o=s.parent??null}const r=await E((await E(await $(t),async s=>await h(s.node_id))).filter(s=>s!==null&&s.kind!=="human").sort((s,y)=>s.status===y.status?0:s.status==="active"?-1:y.status==="active"?1:0),b),d=typeof e.fork_source_file=="string"?await ee(e.fork_source_file):null,c=await z(t);if(c===null)throw g(`unknown node: ${t}`,{received:t});return{node:await b(e),warm_spare:await C(t),situational_card:await ue(t),ancestors:n,children:r,fork_source:d===null?null:await b(d),subject:c,roadmap:await Z(t)}}a(be,"extensionState");function T(t,e){return t?.kind===e.kind&&t?.mode===e.mode&&t?.lifecycle===e.lifecycle}a(T,"samePersona");function ke(t){const e=l(t,"broker generated-name");if(e.kind!=="initial"&&e.kind!=="recap")throw u("kind must be initial or recap");if(typeof e.description!="string"||typeof e.title!="string"||typeof e.icon!="string")throw u("description, title, and icon must be strings");if(e.kind==="initial")return e;const n=e.expected;if(typeof n!="object"||n===null||Array.isArray(n)||["name","description","title","icon","kind"].some(i=>typeof n[i]!="string"))throw u("recap expected must contain name, description, title, icon, and kind strings");return e}a(ke,"parseGeneratedNameBody");function ve(t){const e=l(t,"broker persona-ack"),n=a(i=>{const o=e[i];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 u(`${i} must be a persona state`);return o},"parse");return{expected_execution_id:e.expected_execution_id,from:n("from"),to:n("to")}}a(ve,"parsePersonaAckBody");async function ge(t){const e=t.params.id,n=me(t.body),i=n.sessionFile===null?null:B(n.sessionFile);return{status:200,body:await p(async r=>{await r.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(e);const d=await m(e);if(await U(n.executionId,e,n.pid)==="shutdown")return{action:"shutdown"};const c=d.review_binding?.review_id;if(c!==void 0&&!n.reviewBoundaryIds.includes(c))return{action:"shutdown"};if(n.reason==="new"&&d.parent==null)return{action:"relaunch_root"};if(n.reason!=="new"&&d.fork_from!=null&&d.pi_session_id==null&&i===null)return{action:"shutdown"};const s=i===null?null:await I(i);if(s!==null&&s.node_id!==e){if(Y(s.pi_pid))return await ie(e,{link:"daemon\u2192node",op:"session-file-ownership",kind:"protocol",retry:{disposition:"fatal"},message:`refusing to bind ${i}: it is owned by live node ${s.node_id}`}),{action:"shutdown"};const y=await G(s.node_id);if(y===null||await H({fromNodeId:s.node_id,fromBindingId:y.bindingId,toNodeId:e,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:i})!=="transferred")return{action:"shutdown"}}else if(await W(e,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:i})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(await X(e),d.intent==="refresh"&&await _(e,"revive")),{action:"none"}})}}a(ge,"handleSessionBound");async function xe(t,e,n){const i=await h(t);if(i===null){if(e.pushedFinal)return{directive:{action:"shutdown"},closePane:!1};throw g(`unknown node: ${t}`,{received:t})}if(await M(t,new Date().toISOString()),(e.stopReason==="stop"||e.stopReason==="length")&&await q(t,{failures:0,notBefore:null}),e.stopReason==="quit"){let c=!1;return(i.status==="active"||i.status==="idle")&&i.intent===null&&(await _(t,"finish"),await w(t),await k(t,{pane:null,tmux_session:null,window:null}),c=!0),{directive:{action:"shutdown"},closePane:c}}if(e.stopReason!=="stop"&&e.stopReason!=="length")return await w(t,{link:"daemon\u2192node"}),{directive:i.intent==="refresh"?{action:"shutdown"}:{action:"stay_dormant"},closePane:!1};const o={pushedFinal:e.pushedFinal};if(o.pushedFinal||i.status==="done")return await w(t),await k(t,{pane:null,tmux_session:null,window:null}),{directive:{action:"shutdown"},closePane:!0};if(i.intent==="refresh")return await w(t),{directive:{action:"shutdown"},closePane:!1};const r=await ne(t,o);if(await w(t),r.action==="reprompt")return{directive:{action:"reprompt",prompt:r.message},closePane:!1};if(r.reason==="finished")return{directive:await S(t)?{action:"stay_dormant"}:{action:"shutdown"},closePane:!1};const d=n.live!==null||await te(t)||await S(t);return(await D(t))?.runner==="blaxel"?{directive:!d&&(await Q(await K(),t)).length===0?{action:"stay_resident"}:{action:"stay_dormant"},closePane:!1}:r.reason!=="awaiting"&&r.reason!=="scheduled"?{directive:{action:"stay_dormant"},closePane:!1}:d?{directive:{action:"stay_dormant"},closePane:!1}:(await _(t,"release"),{directive:{action:"shutdown"},closePane:!1})}a(xe,"settleBroker");async function Se(t){const e=t.params.id,n=l(t.body,"broker idle");return await f(e,n.expected_execution_id),await L(n.expected_execution_id),{status:204}}a(Se,"handleIdle");async function Pe(t){const e=t.params.id,n=we(t.body);await f(e,n.expected_execution_id);const i=await R(e),{directive:o,closePane:r}=await p(async()=>await xe(e,n,await P(i)));return r&&await O(e),o.action!=="reprompt"&&re(e).catch(d=>F({level:"error",event:"api.broker_ops.companion_submit_failed",node_id:e,error:d})),{status:200,body:o}}a(Pe,"handleSettle");async function Re(t){const e=t.params.id,n=ye(t.body);await f(e,n.expected_execution_id);const i=await R(e),o=await p(async()=>{const r=await ae(e);if(r===void 0)return{action:"stay_dormant"};const d=await m(e);return await de(e,d,r,await P(i))?(await w(e),await _(e,"park"),await k(e,{pane:null,tmux_session:null,window:null}),F({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...V(e)?{node_id:e}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}});return o.action==="shutdown"&&await O(e),{status:200,body:o}}a(Re,"handleParkComplete");async function Oe(t){const e=t.params.id;return await f(e,l(t.body,"broker park-activity").expected_execution_id),{status:200,body:await p(async()=>({activity:await se(e)?"recorded":"none"}))}}a(Oe,"handleParkActivity");async function Fe(t){const e=t.params.id,n=he(t.body);return await f(e,n.expected_execution_id),await p(async()=>{await j(e,{tokensIn:n.tokens_in,contextTokens:n.context_tokens,lastActivity:n.last_activity,updatedAt:n.updated_at}),fe(e,n)}),{status:204}}a(Fe,"handleTelemetry");async function Ee(t){const e=t.params.id,n=_e(t.body);return await f(e,n.expected_execution_id),{status:200,body:{modelOverride:(await p(async()=>await oe(await m(e),n.spec,n.intent,n.userSelected))).model_override}}}a(Ee,"handleModelCommit");let A=!0;function lt(t){A=t}a(lt,"setRequestsStartRunObservers");async function Te(t){const e=t.params.id,n=await m(e);return n.run_id&&A&&await le(e,n.run_id),{status:200,body:await be(e)}}a(Te,"handleExtensionState");async function Ae(t){const e=t.params.id,n=ke(t.body);return await f(e,n.expected_execution_id),{status:200,body:await p(async o=>{await o.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(e);const r=await m(e);if(n.kind==="initial"){if((r.description??"").trim()!=="")return{applied:!1};const s=await v(e,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:x(s),description:s.description??"",title:s.title??"",icon:s.icon??""}}const d=n.expected;if(r.name!==d.name||(r.description??"")!==d.description||(r.title??"")!==d.title||(r.icon??"")!==d.icon||r.kind!==d.kind)return{applied:!1};const c=await v(e,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:x(c),description:c.description??"",title:c.title??"",icon:c.icon??""}})}}a(Ae,"handleGeneratedName");async function Ne(t){const e=t.params.id,n=ve(t.body);return await f(e,n.expected_execution_id),{status:200,body:await p(async o=>{await o.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(e);const r=await m(e),d={kind:r.kind,mode:r.mode,lifecycle:r.lifecycle},c=r.persona_ack,s=c===void 0?d:{kind:c.kind??r.kind,mode:c.mode,lifecycle:c.lifecycle};return!T(d,n.to)||!T(s,n.from)?{applied:!1}:(await v(e,{persona_ack:n.to}),{applied:!0})})}}a(Ne,"handlePersonaAck");const pt=ce([{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:ge},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:Pe},{method:"POST",pattern:"/v1/nodes/:id/broker/idle",handler:Se},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:Re},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:Oe},{method:"POST",pattern:"/v1/nodes/:id/broker/telemetry",handler:Fe},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:Ee},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:Te},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:Ae},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:Ne}]);export{pt as brokerOperationRoutes,b as extensionNode,lt as setRequestsStartRunObservers};
@@ -1 +1 @@
1
- var k=Object.defineProperty;var o=(t,e)=>k(t,"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 R,invalidateEpisode as P,openTurn as h,parseProviderError as F,readEpisode as A,readFault as _,recordFault as v,recordPendingEpisode as N,recordTransportPoisonVerdict as j,recordTurnProgress as O,reopenEpisode as L,settleRejectedEpisode as D}from"../../../core/canvas/recovery.js";import{notFound as B,usage as n}from"../../../core/errors.js";import{hasPresentedViewer as $}from"../viewer-presence.js";import{ownerOnly as b}from"../router.js";const y=new Set(["pi\u2192provider","viewer\u2194broker","relay\u2194broker","viewer\u2194crtrd","daemon\u2192node","crtr\u2192pi"]),C=new Set(["rate-limit","overloaded","connection","auth","protocol","context-overflow","other","wedged","model-not-found"]),K=new Set(["auto","manual","fatal"]),U=new Set(["sdk","daemon","client"]);function d(t,e){if(typeof t!="object"||t===null||Array.isArray(t))throw n(`${e} requires a JSON object`);return t}o(d,"objectBody");async function a(t){if(await I(t)===null)throw B(`unknown node: ${t}`,{received:t})}o(a,"requireNode");async function u(t,e){if(typeof e!="string"||e==="")throw n("expected_execution_id must be a non-empty string");const r=await S(t);if(r===null||r.executionId!==e)throw new E(409,"stale_execution","broker execution is no longer current")}o(u,"requireCurrentExecution");function g(t){if(typeof t!="object"||t===null||Array.isArray(t))throw n("retry must be an object");const e=t;if(!K.has(e.disposition))throw n("retry.disposition must be auto, manual, or fatal");if(e.by!==void 0&&!U.has(e.by))throw n("retry.by must be sdk, daemon, or client");for(const r of["attempt","max"])if(e[r]!==void 0&&(!Number.isSafeInteger(e[r])||e[r]<0))throw n(`retry.${r} 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 c(t){const e=d(t,"fault input");if(!y.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(!C.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 r=e.provider_error===void 0?void 0:F(e.provider_error);if(e.provider_error!==void 0&&r===void 0)throw n("provider_error is invalid");return{...e,...r===void 0?{}:{provider_error:r},retry:g(e.retry)}}o(c,"parseFaultInput");function p(t){return{link:t.link,op:t.op,kind:t.kind,retry:t.retry,message:t.message,...t.operation_id===void 0?{}:{operation_id:t.operation_id},...t.since===void 0?{}:{since:t.since},...t.anchor_entry_id===void 0?{}:{anchorEntryId:t.anchor_entry_id},...t.provider_error===void 0?{}:{providerError:t.provider_error}}}o(p,"faultInput");function l(t){return{fault_id:t.faultId,link:t.link,op:t.op,kind:t.kind,retry:t.retry,message:t.message,since:t.since,operation_id:t.operation_id,...t.anchorEntryId===void 0?{}:{anchor_entry_id:t.anchorEntryId},...t.providerError===void 0?{}:{provider_error:t.providerError}}}o(l,"faultDto");async function x(t){const e=await _(t),r=await A(t);return{fault:e===null?null:l(e),episode:r===null?null:{state:r.state,session_id:r.sessionId,fault:l(r.fault)}}}o(x,"recoveryState");function V(t){const e=d(t,"broker turn"),r=e.event;if(r!=="started"&&r!=="progress"&&r!=="closed"&&r!=="interrupted"&&r!=="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(r==="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(r==="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(f=>typeof f=="string"&&f!==""))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(V,"parseTurn");async function Y(t){const e=t.params.id;await a(e);const r=V(t.body);await u(e,r.expected_execution_id);let i;switch(r.event){case"started":i=await h(r.expected_execution_id,{reason:"agent-start"});break;case"interrupted":i=await h(r.expected_execution_id,{reason:"prompt-unsettled"});break;case"progress":i=await O(r.expected_execution_id);break;case"closed":i=await R(r.expected_execution_id,{endReason:r.end_reason,viewerPresent:$(e)});break;case"exit-diagnostic":{const w=r.exit_diagnostic.transport_poison;i=await j(r.expected_execution_id,{consecutivePasses:w.consecutive_passes,routes:w.routes});break}}const s=(await _(e))?.link;return{status:200,body:{applied:i,fault_link:s==="daemon\u2192node"||s==="pi\u2192provider"?s:null}}}o(Y,"handleTurn");function G(t){const e=d(t,"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","settle-rejected"].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=c(e.input)),e.op==="settle-rejected"){if(typeof e.fault_id!="string"||e.fault_id==="")throw n("settle-rejected requires fault_id");if(typeof e.reopen!="boolean")throw n("settle-rejected requires reopen");e.input=c(e.input)}if(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(G,"parseProviderRetry");async function J(t){const e=t.params.id;await a(e);const r=G(t.body);await u(e,r.expected_execution_id);let i;switch(r.op){case"record-pending":i=await N(e,{sessionId:r.session_id,input:p(r.input)})!==null;break;case"admit":i=await T(e,{sessionId:r.session_id,faultId:r.fault_id,retry:r.retry});break;case"settle-rejected":i=await D(e,{sessionId:r.session_id,faultId:r.fault_id,fault:p(r.input),reopen:r.reopen});break;case"reopen":i=await L(e,{sessionId:r.session_id});break;case"invalidate":i=await P(e,{sessionId:r.session_id});break;case"clear":i=await q(e,{sessionId:r.session_id});break}return{status:200,body:{applied:i,episode:(await x(e)).episode}}}o(J,"handleProviderRetry");function W(t){const e=d(t,"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=c(e.input)),e.op==="clear"&&e.link!==void 0&&!y.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(W,"parseBrokerFault");async function z(t){const e=t.params.id;await a(e);const r=W(t.body);await u(e,r.expected_execution_id);const i=r.op==="record"?await v(e,p(r.input)):(await m(e,{...r.link===void 0?{}:{link:r.link},...r.preserve_episode===void 0?{}:{preserveEpisode:r.preserve_episode}}),await _(e));return{status:200,body:{fault:i===null?null:l(i)}}}o(z,"handleBrokerFault");async function H(t){const e=t.params.id;return await a(e),await u(e,t.query.get("expected_execution_id")),{status:200,body:await x(e)}}o(H,"handleRecovery");async function M(t){const e=t.params.id;await a(e);const r=await v(e,p(c(t.body)));return{status:200,body:{fault:r===null?null:l(r)}}}o(M,"handleNodeFaultRecord");async function Q(t){const e=t.params.id;await a(e);const r=t.query.get("link");if(r!==null&&!y.has(r))throw n("fault link is invalid");const i=t.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,{...r===null?{}:{link:r},...i===null?{}:{preserveEpisode:i==="true"}})}}}o(Q,"handleNodeFaultClear");const se=b([{method:"POST",pattern:"/v1/broker/:id/turn",handler:Y},{method:"POST",pattern:"/v1/broker/:id/provider-retry",handler:J},{method:"POST",pattern:"/v1/broker/:id/fault",handler:z},{method:"GET",pattern:"/v1/broker/:id/recovery",handler:H}]),de=b([{method:"POST",pattern:"/v1/nodes/:id/fault",handler:M},{method:"DELETE",pattern:"/v1/nodes/:id/fault",handler:Q}]);export{se as brokerRecoveryRoutes,de as nodeFaultRoutes,u as requireCurrentExecution};
1
+ var k=Object.defineProperty;var o=(t,e)=>k(t,"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 R,invalidateEpisode as P,openTurn as h,parseProviderError as F,readEpisode as A,readFault as _,recordFault as v,recordPendingEpisode as N,recordTransportPoisonVerdict as j,recordTurnProgress as O,reopenEpisode as L,settleRejectedEpisode as D}from"../../../core/canvas/recovery.js";import{notFound as B,usage as n}from"../../../core/errors.js";import{hasPresentedViewer as $}from"../viewer-presence.js";import{ownerOnly as b}from"../router.js";const y=new Set(["pi\u2192provider","viewer\u2194broker","relay\u2194broker","viewer\u2194crtrd","daemon\u2192node","crtr\u2192pi"]),C=new Set(["rate-limit","overloaded","connection","auth","protocol","context-overflow","other","wedged","model-not-found"]),K=new Set(["auto","manual","fatal"]),U=new Set(["sdk","daemon","client"]);function d(t,e){if(typeof t!="object"||t===null||Array.isArray(t))throw n(`${e} requires a JSON object`);return t}o(d,"objectBody");async function a(t){if(await I(t)===null)throw B(`unknown node: ${t}`,{received:t})}o(a,"requireNode");async function u(t,e){if(typeof e!="string"||e==="")throw n("expected_execution_id must be a non-empty string");const r=await S(t);if(r===null||r.executionId!==e)throw new E(409,"stale_execution","broker execution is no longer current")}o(u,"requireCurrentExecution");function g(t){if(typeof t!="object"||t===null||Array.isArray(t))throw n("retry must be an object");const e=t;if(!K.has(e.disposition))throw n("retry.disposition must be auto, manual, or fatal");if(e.by!==void 0&&!U.has(e.by))throw n("retry.by must be sdk, daemon, or client");for(const r of["attempt","max"])if(e[r]!==void 0&&(!Number.isSafeInteger(e[r])||e[r]<0))throw n(`retry.${r} 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 c(t){const e=d(t,"fault input");if(!y.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(!C.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 r=e.provider_error===void 0?void 0:F(e.provider_error);if(e.provider_error!==void 0&&r===void 0)throw n("provider_error is invalid");return{...e,...r===void 0?{}:{provider_error:r},retry:g(e.retry)}}o(c,"parseFaultInput");function p(t){return{link:t.link,op:t.op,kind:t.kind,retry:t.retry,message:t.message,...t.operation_id===void 0?{}:{operation_id:t.operation_id},...t.since===void 0?{}:{since:t.since},...t.anchor_entry_id===void 0?{}:{anchorEntryId:t.anchor_entry_id},...t.provider_error===void 0?{}:{providerError:t.provider_error}}}o(p,"faultInput");function l(t){return{fault_id:t.faultId,link:t.link,op:t.op,kind:t.kind,retry:t.retry,message:t.message,since:t.since,operation_id:t.operation_id,...t.anchorEntryId===void 0?{}:{anchor_entry_id:t.anchorEntryId},...t.providerError===void 0?{}:{provider_error:t.providerError}}}o(l,"faultDto");async function x(t){const e=await _(t),r=await A(t);return{fault:e===null?null:l(e),episode:r===null?null:{state:r.state,session_id:r.sessionId,fault:l(r.fault)}}}o(x,"recoveryState");function V(t){const e=d(t,"broker turn"),r=e.event;if(r!=="started"&&r!=="progress"&&r!=="closed"&&r!=="interrupted"&&r!=="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(r==="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(r==="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(f=>typeof f=="string"&&f!==""))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(V,"parseTurn");async function Y(t){const e=t.params.id;await a(e);const r=V(t.body);await u(e,r.expected_execution_id);let i;switch(r.event){case"started":i=await h(r.expected_execution_id,{reason:"agent-start"});break;case"interrupted":i=await h(r.expected_execution_id,{reason:"prompt-unsettled"});break;case"progress":i=await O(r.expected_execution_id);break;case"closed":i=await R(r.expected_execution_id,{endReason:r.end_reason,viewerPresent:await $(e)});break;case"exit-diagnostic":{const w=r.exit_diagnostic.transport_poison;i=await j(r.expected_execution_id,{consecutivePasses:w.consecutive_passes,routes:w.routes});break}}const s=(await _(e))?.link;return{status:200,body:{applied:i,fault_link:s==="daemon\u2192node"||s==="pi\u2192provider"?s:null}}}o(Y,"handleTurn");function G(t){const e=d(t,"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","settle-rejected"].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=c(e.input)),e.op==="settle-rejected"){if(typeof e.fault_id!="string"||e.fault_id==="")throw n("settle-rejected requires fault_id");if(typeof e.reopen!="boolean")throw n("settle-rejected requires reopen");e.input=c(e.input)}if(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(G,"parseProviderRetry");async function J(t){const e=t.params.id;await a(e);const r=G(t.body);await u(e,r.expected_execution_id);let i;switch(r.op){case"record-pending":i=await N(e,{sessionId:r.session_id,input:p(r.input)})!==null;break;case"admit":i=await T(e,{sessionId:r.session_id,faultId:r.fault_id,retry:r.retry});break;case"settle-rejected":i=await D(e,{sessionId:r.session_id,faultId:r.fault_id,fault:p(r.input),reopen:r.reopen});break;case"reopen":i=await L(e,{sessionId:r.session_id});break;case"invalidate":i=await P(e,{sessionId:r.session_id});break;case"clear":i=await q(e,{sessionId:r.session_id});break}return{status:200,body:{applied:i,episode:(await x(e)).episode}}}o(J,"handleProviderRetry");function W(t){const e=d(t,"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=c(e.input)),e.op==="clear"&&e.link!==void 0&&!y.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(W,"parseBrokerFault");async function z(t){const e=t.params.id;await a(e);const r=W(t.body);await u(e,r.expected_execution_id);const i=r.op==="record"?await v(e,p(r.input)):(await m(e,{...r.link===void 0?{}:{link:r.link},...r.preserve_episode===void 0?{}:{preserveEpisode:r.preserve_episode}}),await _(e));return{status:200,body:{fault:i===null?null:l(i)}}}o(z,"handleBrokerFault");async function H(t){const e=t.params.id;return await a(e),await u(e,t.query.get("expected_execution_id")),{status:200,body:await x(e)}}o(H,"handleRecovery");async function M(t){const e=t.params.id;await a(e);const r=await v(e,p(c(t.body)));return{status:200,body:{fault:r===null?null:l(r)}}}o(M,"handleNodeFaultRecord");async function Q(t){const e=t.params.id;await a(e);const r=t.query.get("link");if(r!==null&&!y.has(r))throw n("fault link is invalid");const i=t.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,{...r===null?{}:{link:r},...i===null?{}:{preserveEpisode:i==="true"}})}}}o(Q,"handleNodeFaultClear");const se=b([{method:"POST",pattern:"/v1/broker/:id/turn",handler:Y},{method:"POST",pattern:"/v1/broker/:id/provider-retry",handler:J},{method:"POST",pattern:"/v1/broker/:id/fault",handler:z},{method:"GET",pattern:"/v1/broker/:id/recovery",handler:H}]),de=b([{method:"POST",pattern:"/v1/nodes/:id/fault",handler:M},{method:"DELETE",pattern:"/v1/nodes/:id/fault",handler:Q}]);export{se as brokerRecoveryRoutes,de as nodeFaultRoutes,u as requireCurrentExecution};
@@ -10,9 +10,6 @@ export declare class BrokerSignalStreams {
10
10
  blockedMs: number;
11
11
  });
12
12
  open(nodeId: string, res: ServerResponse, hello: BrokerSignalLineDTO, req: RequestContext['req']): Promise<void>;
13
- /** Hint the node's broker to re-run its retry scheduling. False when no
14
- * broker stream is open (it resyncs on reconnect instead). */
15
- nudgeFaultRetry(nodeId: string): Promise<boolean>;
16
13
  close(): void;
17
14
  }
18
15
  export declare const brokerSignalStreams: BrokerSignalStreams;