@north-light/cli 0.3.561 → 0.3.563

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 (579) 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/build-root.d.ts +1 -0
  23. package/dist/build-root.js +1 -1
  24. package/dist/builtin-memory/crouter-sdk/release-notes.md +4 -0
  25. package/dist/cli.js +7 -7
  26. package/dist/clients/attach/chrome/bash-jobs.d.ts +11 -1
  27. package/dist/clients/attach/chrome/bash-jobs.js +1 -1
  28. package/dist/clients/attach/chrome/canvas-panels.d.ts +1 -1
  29. package/dist/clients/attach/chrome/roster.js +6 -4
  30. package/dist/clients/attach/overlays/auth.js +2 -2
  31. package/dist/clients/attach/render/chat-view.js +1 -1
  32. package/dist/clients/attach/viewer.js +550 -567
  33. package/dist/commands/canvas-config.js +2 -2
  34. package/dist/commands/canvas-use.js +1 -1
  35. package/dist/commands/human.js +2 -2
  36. package/dist/commands/node/bash.js +3 -3
  37. package/dist/commands/node/create.js +2 -2
  38. package/dist/commands/person-settings.d.ts +1 -0
  39. package/dist/commands/person-settings.js +1 -0
  40. package/dist/commands/pkg/market-manage.d.ts +2 -2
  41. package/dist/commands/pkg/market-manage.js +1 -1
  42. package/dist/commands/pkg/plugin-manage.js +13 -13
  43. package/dist/commands/pkg/shared.js +1 -1
  44. package/dist/commands/profile/default.js +1 -1
  45. package/dist/commands/push.js +2 -3
  46. package/dist/commands/sys/config.js +1 -1
  47. package/dist/commands/sys/connect.js +1 -1
  48. package/dist/commands/sys/context/sysprompt.js +2 -2
  49. package/dist/commands/sys/doctor.js +1 -1
  50. package/dist/commands/sys/join.js +1 -1
  51. package/dist/commands/sys/panels/broker-limits-panel.js +1 -1
  52. package/dist/commands/sys/panels/keybindings-panel.js +1 -1
  53. package/dist/commands/sys/panels/models-panel.d.ts +8 -2
  54. package/dist/commands/sys/panels/models-panel.js +1 -1
  55. package/dist/commands/sys/panels/prefs-panel.d.ts +1 -0
  56. package/dist/commands/sys/panels/prefs-panel.js +1 -1
  57. package/dist/commands/sys/panels/profiles-panel.js +1 -1
  58. package/dist/commands/sys/panels/provider-panel.d.ts +4 -0
  59. package/dist/commands/sys/panels/provider-panel.js +1 -1
  60. package/dist/commands/sys/provider-login.js +5 -5
  61. package/dist/commands/sys/setup-core.js +3 -3
  62. package/dist/commands/sys/setup-settings-runner.js +1 -1
  63. package/dist/commands/sys/spend.js +3 -3
  64. package/dist/commands/sys/update.js +1 -1
  65. package/dist/core/auth-file.d.ts +11 -19
  66. package/dist/core/auth-file.js +1 -2
  67. package/dist/core/auto-update.d.ts +1 -1
  68. package/dist/core/auto-update.js +4 -4
  69. package/dist/core/bash-jobs.d.ts +29 -71
  70. package/dist/core/bash-jobs.js +9 -10
  71. package/dist/core/blobs/directory.d.ts +3 -0
  72. package/dist/core/blobs/directory.js +1 -0
  73. package/dist/core/blobs/fault.d.ts +3 -0
  74. package/dist/core/blobs/fault.js +1 -0
  75. package/dist/core/blobs/index.d.ts +21 -0
  76. package/dist/core/blobs/index.js +1 -0
  77. package/dist/core/blobs/r2.d.ts +9 -0
  78. package/dist/core/blobs/r2.js +4 -0
  79. package/dist/core/bootstrap.d.ts +1 -1
  80. package/dist/core/bootstrap.js +2 -2
  81. package/dist/core/canvas/canvas.d.ts +9 -7
  82. package/dist/core/canvas/canvas.js +8 -8
  83. package/dist/core/canvas/crons.d.ts +3 -2
  84. package/dist/core/canvas/crons.js +3 -3
  85. package/dist/core/canvas/daemon-owner.d.ts +5 -0
  86. package/dist/core/canvas/daemon-owner.js +1 -1
  87. package/dist/core/canvas/db.d.ts +10 -9
  88. package/dist/core/canvas/db.js +4 -4
  89. package/dist/core/canvas/executions.d.ts +100 -4
  90. package/dist/core/canvas/executions.js +1 -1
  91. package/dist/core/canvas/export-sqlite.js +1 -1
  92. package/dist/core/canvas/focuses.d.ts +4 -0
  93. package/dist/core/canvas/focuses.js +1 -1
  94. package/dist/core/canvas/history.js +9 -9
  95. package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +2 -1
  96. package/dist/core/canvas/managed-worktree-sweep-candidates.js +3 -2
  97. package/dist/core/canvas/node-tokens.d.ts +1 -4
  98. package/dist/core/canvas/node-tokens.js +3 -3
  99. package/dist/core/canvas/paths.d.ts +0 -1
  100. package/dist/core/canvas/paths.js +1 -1
  101. package/dist/core/canvas/person-state.d.ts +26 -0
  102. package/dist/core/canvas/person-state.js +1 -0
  103. package/dist/core/canvas/person.d.ts +3 -10
  104. package/dist/core/canvas/person.js +7 -7
  105. package/dist/core/canvas/reconciler-leases.d.ts +12 -0
  106. package/dist/core/canvas/reconciler-leases.js +8 -0
  107. package/dist/core/canvas/recovery.d.ts +4 -0
  108. package/dist/core/canvas/recovery.js +1 -1
  109. package/dist/core/canvas/schema-pg/003-fleet-removals.sql +1 -1
  110. package/dist/core/canvas/schema-pg/005-fleet-blobs.sql +13 -0
  111. package/dist/core/canvas/schema-pg/006-job-rows.sql +20 -0
  112. package/dist/core/canvas/schema-pg/007-ledger-check.sql +117 -0
  113. package/dist/core/canvas/schema-version.d.ts +1 -1
  114. package/dist/core/canvas/schema-version.js +1 -1
  115. package/dist/core/canvas/sessions.d.ts +8 -11
  116. package/dist/core/canvas/sessions.js +1 -4
  117. package/dist/core/canvas/tree.d.ts +4 -2
  118. package/dist/core/canvas/tree.js +6 -6
  119. package/dist/core/canvas/types.d.ts +7 -0
  120. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  121. package/dist/core/command-plugins/bundle.d.ts +1 -1
  122. package/dist/core/command-plugins/bundle.js +1 -1
  123. package/dist/core/command-plugins/compose.d.ts +1 -1
  124. package/dist/core/command-plugins/discovery.d.ts +0 -1
  125. package/dist/core/command-plugins/discovery.js +1 -1
  126. package/dist/core/command-plugins/help-addenda.js +1 -1
  127. package/dist/core/command-plugins/presence.d.ts +2 -0
  128. package/dist/core/command-plugins/presence.js +1 -1
  129. package/dist/core/config.d.ts +16 -15
  130. package/dist/core/config.js +1 -1
  131. package/dist/core/conversation-store/client-worker.js +1 -1
  132. package/dist/core/conversation-store/client.js +2 -2
  133. package/dist/core/conversation-store/index.d.ts +9 -11
  134. package/dist/core/conversation-store/index.js +1 -1
  135. package/dist/core/conversation-store/patch.js +1 -1
  136. package/dist/core/conversation-store/row-store.d.ts +14 -0
  137. package/dist/core/conversation-store/row-store.js +13 -0
  138. package/dist/core/directory/join.d.ts +5 -3
  139. package/dist/core/directory/join.js +1 -1
  140. package/dist/core/env-name.d.ts +1 -0
  141. package/dist/core/env-name.js +1 -1
  142. package/dist/core/environment-recipe.d.ts +15 -0
  143. package/dist/core/environment-recipe.js +1 -0
  144. package/dist/core/environments.js +1 -1
  145. package/dist/core/events/emit.js +2 -2
  146. package/dist/core/events/run-event-chunks.d.ts +25 -0
  147. package/dist/core/events/run-event-chunks.js +5 -0
  148. package/dist/core/feed/messages.js +5 -5
  149. package/dist/core/grants/mirror.d.ts +15 -0
  150. package/dist/core/grants/mirror.js +15 -3
  151. package/dist/core/grants/on-sync.d.ts +9 -5
  152. package/dist/core/grants/on-sync.js +1 -1
  153. package/dist/core/grants/remove.d.ts +1 -6
  154. package/dist/core/grants/remove.js +1 -1
  155. package/dist/core/grants/sync.js +1 -1
  156. package/dist/core/grants/watch.d.ts +15 -9
  157. package/dist/core/grants/watch.js +1 -1
  158. package/dist/core/graph/custom.js +8 -8
  159. package/dist/core/graph/jobs.d.ts +83 -5
  160. package/dist/core/graph/jobs.js +11 -2
  161. package/dist/core/graph/kinds/job.js +2 -2
  162. package/dist/core/graph/names.js +7 -7
  163. package/dist/core/graph/objects.d.ts +5 -1
  164. package/dist/core/graph/objects.js +11 -11
  165. package/dist/core/graph/reader.d.ts +3 -0
  166. package/dist/core/graph/reader.js +3 -3
  167. package/dist/core/graph/repo-sync/identity.d.ts +3 -1
  168. package/dist/core/graph/repo-sync/identity.js +1 -1
  169. package/dist/core/graph/repo-sync/repos.d.ts +1 -1
  170. package/dist/core/graph/repo-sync/repos.js +2 -2
  171. package/dist/core/graph/repo-sync/sync.js +2 -2
  172. package/dist/core/installed-plugins.js +1 -1
  173. package/dist/core/keybindings/persistence.d.ts +1 -1
  174. package/dist/core/keybindings/persistence.js +1 -1
  175. package/dist/core/layout-migrate/loose-keys.d.ts +1 -1
  176. package/dist/core/layout-migrate/loose-keys.js +1 -1
  177. package/dist/core/ledger/account.d.ts +12 -0
  178. package/dist/core/ledger/account.js +2 -0
  179. package/dist/core/ledger/charges.d.ts +2 -2
  180. package/dist/core/ledger/charges.js +1 -1
  181. package/dist/core/ledger/check.d.ts +5 -1
  182. package/dist/core/ledger/check.js +1 -7
  183. package/dist/core/ledger/chunks.d.ts +8 -0
  184. package/dist/core/ledger/chunks.js +2 -0
  185. package/dist/core/ledger/index.d.ts +2 -1
  186. package/dist/core/ledger/index.js +1 -1
  187. package/dist/core/ledger/infra-allowance.d.ts +9 -0
  188. package/dist/core/ledger/infra-allowance.js +1 -0
  189. package/dist/core/ledger/limits.js +3 -3
  190. package/dist/core/ledger/payer.d.ts +1 -1
  191. package/dist/core/ledger/payer.js +1 -1
  192. package/dist/core/ledger/read.d.ts +14 -4
  193. package/dist/core/ledger/read.js +2 -3
  194. package/dist/core/ledger/totals.d.ts +5 -16
  195. package/dist/core/ledger/totals.js +4 -4
  196. package/dist/core/ledger/types.d.ts +12 -3
  197. package/dist/core/llm/run.js +2 -2
  198. package/dist/core/managed-providers.d.ts +72 -0
  199. package/dist/core/managed-providers.js +1 -0
  200. package/dist/core/model-auth/api-credential-store.d.ts +10 -0
  201. package/dist/core/model-auth/api-credential-store.js +1 -0
  202. package/dist/core/model-auth/daemon-login.d.ts +1 -1
  203. package/dist/core/model-auth/daemon-login.js +1 -1
  204. package/dist/core/model-auth/flows.d.ts +5 -4
  205. package/dist/core/model-auth/flows.js +1 -1
  206. package/dist/core/model-auth/handoff-jti.d.ts +3 -4
  207. package/dist/core/model-auth/handoff-jti.js +1 -1
  208. package/dist/core/model-auth/readiness.js +1 -1
  209. package/dist/core/model-config.d.ts +1 -1
  210. package/dist/core/model-config.js +1 -1
  211. package/dist/core/model-routes-pool.d.ts +14 -0
  212. package/dist/core/model-routes-pool.js +1 -0
  213. package/dist/core/model-routes.d.ts +11 -16
  214. package/dist/core/model-routes.js +1 -1
  215. package/dist/core/peer/ingest.d.ts +2 -0
  216. package/dist/core/peer/ingest.js +1 -1
  217. package/dist/core/peer/stubs.d.ts +8 -0
  218. package/dist/core/peer/stubs.js +1 -1
  219. package/dist/core/permissions/evaluator.d.ts +7 -2
  220. package/dist/core/permissions/evaluator.js +2 -2
  221. package/dist/core/plugin-env.js +1 -1
  222. package/dist/core/pool-credential-store.d.ts +2 -5
  223. package/dist/core/pool-credential-store.js +1 -1
  224. package/dist/core/profiles/app-env-store.d.ts +5 -5
  225. package/dist/core/profiles/app-env-store.js +1 -2
  226. package/dist/core/profiles/default-binding.d.ts +5 -5
  227. package/dist/core/profiles/default-binding.js +1 -1
  228. package/dist/core/profiles/env-store.d.ts +10 -21
  229. package/dist/core/profiles/env-store.js +1 -2
  230. package/dist/core/profiles/manifest.d.ts +14 -18
  231. package/dist/core/profiles/manifest.js +1 -1
  232. package/dist/core/profiles/relocate.js +1 -1
  233. package/dist/core/profiles/select.js +21 -21
  234. package/dist/core/provider-credential.d.ts +1 -1
  235. package/dist/core/provider-credential.js +1 -1
  236. package/dist/core/provider-management.d.ts +3 -4
  237. package/dist/core/provider-management.js +1 -1
  238. package/dist/core/providers/bundles.js +2 -2
  239. package/dist/core/providers/call.d.ts +3 -34
  240. package/dist/core/providers/description.d.ts +34 -0
  241. package/dist/core/providers/description.js +0 -0
  242. package/dist/core/providers/token-cache.d.ts +14 -14
  243. package/dist/core/providers/token-cache.js +1 -1
  244. package/dist/core/review/companion.js +1 -1
  245. package/dist/core/runs/activity.d.ts +1 -1
  246. package/dist/core/runs/activity.js +1 -1
  247. package/dist/core/runs/events.d.ts +7 -5
  248. package/dist/core/runs/events.js +2 -6
  249. package/dist/core/runs/operations.d.ts +1 -1
  250. package/dist/core/runs/operations.js +6 -6
  251. package/dist/core/runtime/bearings.js +1 -1
  252. package/dist/core/runtime/broker/attachments-fetch.d.ts +5 -0
  253. package/dist/core/runtime/broker/attachments-fetch.js +1 -0
  254. package/dist/core/runtime/broker/bash-job-launch.d.ts +4 -2
  255. package/dist/core/runtime/broker/bash-job-launch.js +1 -1
  256. package/dist/core/runtime/broker/boot-state.d.ts +9 -0
  257. package/dist/core/runtime/broker/boot-state.js +1 -0
  258. package/dist/core/runtime/broker/cli-relay.d.ts +2 -1
  259. package/dist/core/runtime/broker/cli-relay.js +1 -1
  260. package/dist/core/runtime/broker/client-registry.d.ts +3 -3
  261. package/dist/core/runtime/broker/daemon-ops.d.ts +10 -1
  262. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  263. package/dist/core/runtime/broker/fault-retry.d.ts +2 -0
  264. package/dist/core/runtime/broker/fault-retry.js +1 -1
  265. package/dist/core/runtime/broker/frame-engine-control.js +1 -1
  266. package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -0
  267. package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
  268. package/dist/core/runtime/broker/job-reporter.d.ts +18 -0
  269. package/dist/core/runtime/broker/job-reporter.js +2 -0
  270. package/dist/core/runtime/broker/model-adapter.d.ts +3 -0
  271. package/dist/core/runtime/broker/model-adapter.js +3 -2
  272. package/dist/core/runtime/broker/signal-stream.js +1 -1
  273. package/dist/core/runtime/broker/spilled-body.d.ts +5 -0
  274. package/dist/core/runtime/broker/spilled-body.js +1 -0
  275. package/dist/core/runtime/broker/summaries-post.d.ts +5 -0
  276. package/dist/core/runtime/broker/summaries-post.js +1 -0
  277. package/dist/core/runtime/broker/tool-groups.d.ts +3 -0
  278. package/dist/core/runtime/broker/tool-groups.js +1 -1
  279. package/dist/core/runtime/broker/turn-replies.d.ts +1 -0
  280. package/dist/core/runtime/broker/turn-replies.js +1 -1
  281. package/dist/core/runtime/broker-persona-guidance.js +2 -2
  282. package/dist/core/runtime/broker.js +1 -1
  283. package/dist/core/runtime/deliver-live.js +1 -1
  284. package/dist/core/runtime/first-boot-rows.d.ts +8 -0
  285. package/dist/core/runtime/first-boot-rows.js +2 -0
  286. package/dist/core/runtime/fleet.d.ts +13 -12
  287. package/dist/core/runtime/front-door-login.js +1 -1
  288. package/dist/core/runtime/front-door.js +6 -6
  289. package/dist/core/runtime/headless-pi.js +1 -1
  290. package/dist/core/runtime/host.d.ts +14 -3
  291. package/dist/core/runtime/host.js +3 -3
  292. package/dist/core/runtime/invocation.d.ts +6 -0
  293. package/dist/core/runtime/kickoff.d.ts +2 -14
  294. package/dist/core/runtime/kickoff.js +17 -19
  295. package/dist/core/runtime/launch-config-worker.js +1 -1
  296. package/dist/core/runtime/launch.js +2 -2
  297. package/dist/core/runtime/model-registry.js +1 -1
  298. package/dist/core/runtime/node-read.d.ts +4 -6
  299. package/dist/core/runtime/node-read.js +3 -3
  300. package/dist/core/runtime/nodes.js +1 -1
  301. package/dist/core/runtime/outcome-document.d.ts +0 -1
  302. package/dist/core/runtime/outcome-document.js +1 -1
  303. package/dist/core/runtime/output-result.d.ts +15 -0
  304. package/dist/core/runtime/output-result.js +5 -0
  305. package/dist/core/runtime/placement.d.ts +17 -1
  306. package/dist/core/runtime/placement.js +1 -1
  307. package/dist/core/runtime/provider-credential-gate.d.ts +6 -2
  308. package/dist/core/runtime/provider-credential-gate.js +2 -2
  309. package/dist/core/runtime/recovery-hold.d.ts +21 -2
  310. package/dist/core/runtime/recovery-hold.js +2 -1
  311. package/dist/core/runtime/recycle.js +1 -1
  312. package/dist/core/runtime/reset.js +1 -1
  313. package/dist/core/runtime/revive.d.ts +2 -2
  314. package/dist/core/runtime/revive.js +2 -2
  315. package/dist/core/runtime/runner/blaxel/client.d.ts +81 -0
  316. package/dist/core/runtime/runner/blaxel/client.js +1 -0
  317. package/dist/core/runtime/runner/blaxel/image-build.d.ts +74 -0
  318. package/dist/core/runtime/runner/blaxel/image-build.js +5 -0
  319. package/dist/core/runtime/runner/blaxel/runner.d.ts +41 -0
  320. package/dist/core/runtime/runner/blaxel/runner.js +3 -0
  321. package/dist/core/runtime/runner/index.d.ts +8 -0
  322. package/dist/core/runtime/runner/index.js +1 -0
  323. package/dist/core/runtime/runner/process.d.ts +11 -0
  324. package/dist/core/runtime/runner/process.js +1 -0
  325. package/dist/core/runtime/runner/types.d.ts +95 -0
  326. package/dist/core/runtime/runner/types.js +0 -0
  327. package/dist/core/runtime/situational-context.d.ts +3 -6
  328. package/dist/core/runtime/situational-context.js +2 -2
  329. package/dist/core/runtime/situational-live.js +1 -1
  330. package/dist/core/runtime/spawn-env-rows.d.ts +5 -0
  331. package/dist/core/runtime/spawn-env-rows.js +1 -0
  332. package/dist/core/runtime/spawn-env.d.ts +4 -18
  333. package/dist/core/runtime/spawn-env.js +1 -1
  334. package/dist/core/runtime/spawn.js +2 -2
  335. package/dist/core/runtime/stop-guard.d.ts +1 -1
  336. package/dist/core/runtime/stop-guard.js +2 -8
  337. package/dist/core/runtime/structured-output.d.ts +0 -67
  338. package/dist/core/runtime/structured-output.js +3 -8
  339. package/dist/core/runtime/tmux-driver.d.ts +8 -0
  340. package/dist/core/runtime/tmux-driver.js +6 -6
  341. package/dist/core/runtime/view-socket.d.ts +20 -0
  342. package/dist/core/runtime/view-socket.js +3 -1
  343. package/dist/core/runtime/warm-pool.d.ts +13 -1
  344. package/dist/core/runtime/warm-pool.js +1 -1
  345. package/dist/core/scoped-state/legacy-profiles.d.ts +11 -0
  346. package/dist/core/scoped-state/legacy-profiles.js +1 -0
  347. package/dist/core/scoped-state/materialized-plugins.d.ts +18 -0
  348. package/dist/core/scoped-state/materialized-plugins.js +1 -0
  349. package/dist/core/scoped-state/migrate.d.ts +8 -1
  350. package/dist/core/scoped-state/migrate.js +3 -3
  351. package/dist/core/scoped-state/person-rows.d.ts +10 -0
  352. package/dist/core/scoped-state/person-rows.js +6 -0
  353. package/dist/core/scoped-state/person-store.d.ts +72 -0
  354. package/dist/core/scoped-state/person-store.js +1 -0
  355. package/dist/core/secrets/blaxel-launch.d.ts +24 -0
  356. package/dist/core/secrets/blaxel-launch.js +4 -0
  357. package/dist/core/secrets/blaxel-register.d.ts +2 -0
  358. package/dist/core/secrets/blaxel-register.js +1 -0
  359. package/dist/core/secrets/env-rows.d.ts +17 -0
  360. package/dist/core/secrets/env-rows.js +4 -0
  361. package/dist/core/secrets/environment-owner.d.ts +8 -0
  362. package/dist/core/secrets/environment-owner.js +1 -0
  363. package/dist/core/secrets/environment-secrets.d.ts +14 -0
  364. package/dist/core/secrets/environment-secrets.js +1 -0
  365. package/dist/core/secrets/index.d.ts +2 -0
  366. package/dist/core/secrets/index.js +1 -0
  367. package/dist/core/secrets/key.d.ts +3 -0
  368. package/dist/core/secrets/key.js +2 -0
  369. package/dist/core/secrets/seal.d.ts +18 -0
  370. package/dist/core/secrets/seal.js +1 -0
  371. package/dist/core/spaces/mounts.d.ts +1 -1
  372. package/dist/core/spaces/mounts.js +1 -1
  373. package/dist/core/spaces/process.d.ts +1 -1
  374. package/dist/core/spaces/stop.d.ts +7 -5
  375. package/dist/core/spaces/stop.js +2 -2
  376. package/dist/core/spaces/users.d.ts +2 -1
  377. package/dist/core/spaces/users.js +1 -1
  378. package/dist/core/storage/attachments.d.ts +11 -8
  379. package/dist/core/storage/attachments.js +1 -1
  380. package/dist/core/storage/tables.d.ts +4 -0
  381. package/dist/core/storage/tables.js +3 -3
  382. package/dist/core/subscription-state.d.ts +34 -72
  383. package/dist/core/subscription-state.js +1 -4
  384. package/dist/core/substrate/delivery/plan.js +1 -1
  385. package/dist/core/user-settings.js +1 -1
  386. package/dist/daemon/api/app-listener.js +10 -10
  387. package/dist/daemon/api/auth/person-bearer.d.ts +14 -0
  388. package/dist/daemon/api/auth/person-bearer.js +1 -0
  389. package/dist/daemon/api/bridge.js +4 -4
  390. package/dist/daemon/api/document-listener.js +3 -3
  391. package/dist/daemon/api/environment-of.d.ts +18 -0
  392. package/dist/daemon/api/environment-of.js +5 -0
  393. package/dist/daemon/api/handlers/analytics.js +1 -1
  394. package/dist/daemon/api/handlers/app-profiles.d.ts +2 -2
  395. package/dist/daemon/api/handlers/app-profiles.js +1 -1
  396. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  397. package/dist/daemon/api/handlers/bash.js +1 -1
  398. package/dist/daemon/api/handlers/broker-ops.d.ts +3 -0
  399. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  400. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  401. package/dist/daemon/api/handlers/broker-signals.d.ts +0 -3
  402. package/dist/daemon/api/handlers/broker-signals.js +2 -2
  403. package/dist/daemon/api/handlers/canvas.js +4 -4
  404. package/dist/daemon/api/handlers/charges.d.ts +1 -1
  405. package/dist/daemon/api/handlers/charges.js +1 -1
  406. package/dist/daemon/api/handlers/conversations.d.ts +2 -0
  407. package/dist/daemon/api/handlers/conversations.js +3 -0
  408. package/dist/daemon/api/handlers/crons.js +1 -1
  409. package/dist/daemon/api/handlers/daemon.js +1 -1
  410. package/dist/daemon/api/handlers/delivery.d.ts +1 -1
  411. package/dist/daemon/api/handlers/delivery.js +1 -1
  412. package/dist/daemon/api/handlers/docs.js +1 -1
  413. package/dist/daemon/api/handlers/exec.js +1 -1
  414. package/dist/daemon/api/handlers/execution-start.d.ts +2 -0
  415. package/dist/daemon/api/handlers/execution-start.js +2 -0
  416. package/dist/daemon/api/handlers/files.js +1 -1
  417. package/dist/daemon/api/handlers/git-credential.d.ts +11 -0
  418. package/dist/daemon/api/handlers/git-credential.js +1 -0
  419. package/dist/daemon/api/handlers/hook-exec.d.ts +1 -1
  420. package/dist/daemon/api/handlers/hook-exec.js +1 -1
  421. package/dist/daemon/api/handlers/human-requests.js +1 -1
  422. package/dist/daemon/api/handlers/inbox.js +1 -1
  423. package/dist/daemon/api/handlers/messages.js +1 -1
  424. package/dist/daemon/api/handlers/model-config.js +1 -1
  425. package/dist/daemon/api/handlers/modelauth.d.ts +1 -1
  426. package/dist/daemon/api/handlers/modelauth.js +1 -1
  427. package/dist/daemon/api/handlers/node-events.d.ts +6 -0
  428. package/dist/daemon/api/handlers/node-events.js +3 -3
  429. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  430. package/dist/daemon/api/handlers/node-records.js +3 -2
  431. package/dist/daemon/api/handlers/nodes.js +1 -1
  432. package/dist/daemon/api/handlers/objects.js +3 -3
  433. package/dist/daemon/api/handlers/profiles.js +1 -1
  434. package/dist/daemon/api/handlers/providers.js +1 -1
  435. package/dist/daemon/api/handlers/reports.js +9 -13
  436. package/dist/daemon/api/handlers/reviews.js +1 -1
  437. package/dist/daemon/api/handlers/runs.js +1 -1
  438. package/dist/daemon/api/handlers/settings.d.ts +2 -0
  439. package/dist/daemon/api/handlers/settings.js +1 -0
  440. package/dist/daemon/api/handlers/structured-requests.js +1 -1
  441. package/dist/daemon/api/handlers/vendor-status.d.ts +1 -1
  442. package/dist/daemon/api/handlers/vendor-status.js +1 -1
  443. package/dist/daemon/api/handlers/worktree.js +1 -1
  444. package/dist/daemon/api/map.d.ts +2 -2
  445. package/dist/daemon/api/map.js +2 -2
  446. package/dist/daemon/api/operations.js +1 -1
  447. package/dist/daemon/api/reader.d.ts +8 -1
  448. package/dist/daemon/api/reader.js +1 -1
  449. package/dist/daemon/api/router.d.ts +4 -2
  450. package/dist/daemon/api/router.js +1 -1
  451. package/dist/daemon/api/server.d.ts +15 -3
  452. package/dist/daemon/api/server.js +1 -1
  453. package/dist/daemon/api/vendor-signin.d.ts +2 -1
  454. package/dist/daemon/api/vendor-signin.js +19 -19
  455. package/dist/daemon/api/viewer-presence.d.ts +20 -6
  456. package/dist/daemon/api/viewer-presence.js +2 -1
  457. package/dist/daemon/boot-settings.d.ts +3 -0
  458. package/dist/daemon/boot-settings.js +1 -0
  459. package/dist/daemon/broker-signals/bus.d.ts +48 -11
  460. package/dist/daemon/broker-signals/bus.js +1 -1
  461. package/dist/daemon/cron/armed-context.js +1 -1
  462. package/dist/daemon/cron/lease-recovery.js +1 -1
  463. package/dist/daemon/cron/live-runs.d.ts +6 -0
  464. package/dist/daemon/cron/live-runs.js +1 -1
  465. package/dist/daemon/cron/run-socket.js +1 -1
  466. package/dist/daemon/cron-run.js +2 -2
  467. package/dist/daemon/crtrd-cli.js +1 -1
  468. package/dist/daemon/crtrd.d.ts +10 -0
  469. package/dist/daemon/crtrd.js +18 -17
  470. package/dist/daemon/delivery/run-delivery.d.ts +1 -1
  471. package/dist/daemon/delivery/run-delivery.js +1 -1
  472. package/dist/daemon/due-sources.d.ts +1 -1
  473. package/dist/daemon/due-sources.js +1 -1
  474. package/dist/daemon/due.js +7 -6
  475. package/dist/daemon/fleet.d.ts +6 -6
  476. package/dist/daemon/fleet.js +9 -9
  477. package/dist/daemon/park-activity.d.ts +2 -1
  478. package/dist/daemon/park-activity.js +1 -1
  479. package/dist/daemon/park-pending.d.ts +20 -13
  480. package/dist/daemon/park-pending.js +3 -1
  481. package/dist/daemon/profile-delete.js +1 -1
  482. package/dist/daemon/reconcilers/bash-deadline.d.ts +15 -10
  483. package/dist/daemon/reconcilers/bash-deadline.js +1 -3
  484. package/dist/daemon/reconcilers/broker-supervision.d.ts +13 -3
  485. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  486. package/dist/daemon/reconcilers/cron-lane.d.ts +0 -1
  487. package/dist/daemon/reconcilers/cron-lane.js +1 -1
  488. package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +2 -9
  489. package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
  490. package/dist/daemon/reconcilers/grant-effects.d.ts +8 -0
  491. package/dist/daemon/reconcilers/grant-effects.js +1 -0
  492. package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +1 -3
  493. package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
  494. package/dist/daemon/reconcilers/ledger-r2.d.ts +27 -0
  495. package/dist/daemon/reconcilers/ledger-r2.js +7 -0
  496. package/dist/daemon/reconcilers/ledger-sandbox.d.ts +55 -0
  497. package/dist/daemon/reconcilers/ledger-sandbox.js +9 -0
  498. package/dist/daemon/reconcilers/ledger-storage.d.ts +22 -0
  499. package/dist/daemon/reconcilers/ledger-storage.js +5 -0
  500. package/dist/daemon/reconcilers/live-obligation.d.ts +3 -2
  501. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  502. package/dist/daemon/reconcilers/managed-worktree-sweep.d.ts +0 -5
  503. package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
  504. package/dist/daemon/reconcilers/node-deadline.d.ts +2 -1
  505. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  506. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +1 -2
  507. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  508. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +31 -0
  509. package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -0
  510. package/dist/daemon/reconcilers/node-lifecycle/requested-stops.d.ts +5 -0
  511. package/dist/daemon/reconcilers/node-lifecycle/requested-stops.js +2 -0
  512. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  513. package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
  514. package/dist/daemon/reconcilers/recipe-image.d.ts +49 -0
  515. package/dist/daemon/reconcilers/recipe-image.js +7 -0
  516. package/dist/daemon/reconcilers/row-claim.d.ts +19 -0
  517. package/dist/daemon/reconcilers/row-claim.js +2 -0
  518. package/dist/daemon/reconcilers/storage-due-work.d.ts +18 -3
  519. package/dist/daemon/reconcilers/storage-due-work.js +2 -1
  520. package/dist/daemon/reconcilers/storage-maintenance.d.ts +5 -13
  521. package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
  522. package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
  523. package/dist/daemon/reconcilers/throttled-lane.d.ts +11 -0
  524. package/dist/daemon/reconcilers/throttled-lane.js +1 -0
  525. package/dist/daemon/review/finish.js +1 -1
  526. package/dist/daemon/run-notices.d.ts +3 -0
  527. package/dist/daemon/run-notices.js +1 -1
  528. package/dist/daemon/runs/append-section.d.ts +4 -1
  529. package/dist/daemon/runs/append-section.js +2 -2
  530. package/dist/daemon/runs/observer.d.ts +3 -2
  531. package/dist/daemon/runs/observer.js +3 -2
  532. package/dist/daemon/runs/view-transport.d.ts +19 -0
  533. package/dist/daemon/runs/view-transport.js +1 -0
  534. package/dist/daemon/structured-requests/boot.d.ts +2 -1
  535. package/dist/daemon/structured-requests/boot.js +1 -1
  536. package/dist/daemon/structured-requests/effects.d.ts +4 -3
  537. package/dist/daemon/structured-requests/effects.js +1 -1
  538. package/dist/daemon/structured-requests/notifier.d.ts +2 -0
  539. package/dist/daemon/structured-requests/notifier.js +1 -1
  540. package/dist/daemon/structured-requests/sidecar.d.ts +4 -3
  541. package/dist/daemon/structured-requests/sidecar.js +1 -1
  542. package/dist/launcher/validate.js +1 -1
  543. package/dist/migrations/004-canvas-documents/index.js +2 -2
  544. package/dist/pi-extensions/broker-local.d.ts +3 -3
  545. package/dist/pi-extensions/broker-local.js +1 -2
  546. package/dist/pi-extensions/canvas-bash-valve.js +6 -6
  547. package/dist/pi-extensions/canvas-context-intro.js +2 -2
  548. package/dist/pi-extensions/canvas-elapsed.js +2 -2
  549. package/dist/pi-extensions/canvas-goal-capture.js +1 -1
  550. package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
  551. package/dist/pi-extensions/canvas-review-boundary.d.ts +11 -1
  552. package/dist/pi-extensions/canvas-review-boundary.js +3 -3
  553. package/dist/pi-extensions/canvas-stophook.js +1 -1
  554. package/dist/pi-extensions/canvas-structured-output.d.ts +5 -3
  555. package/dist/pi-extensions/canvas-structured-output.js +6 -11
  556. package/dist/pi-extensions/canvas-tool-guide.d.ts +9 -2
  557. package/dist/pi-extensions/canvas-tool-guide.js +6 -6
  558. package/dist/shared/inbox-entry-body.js +7 -7
  559. package/dist/types.d.ts +12 -0
  560. package/docs/sdk/release-notes.md +4 -0
  561. package/package.json +7 -4
  562. package/packages/crouter-identity/package.json +1 -1
  563. package/runtime.lock.json +13 -13
  564. package/scripts/git-credential-crtr +33 -0
  565. package/scripts/sandbox-bootstrap.sh +54 -0
  566. package/scripts/sandbox-start.mjs +320 -0
  567. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +0 -78
  568. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +0 -1179
  569. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +0 -1406
  570. package/dist/core/conversation-store/file-store.d.ts +0 -37
  571. package/dist/core/conversation-store/file-store.js +0 -9
  572. package/dist/core/conversation-store/listener.d.ts +0 -4
  573. package/dist/core/conversation-store/listener.js +0 -8
  574. package/dist/core/scoped-state/profiles.d.ts +0 -27
  575. package/dist/core/scoped-state/profiles.js +0 -1
  576. package/dist/core/scoped-state/providers.d.ts +0 -24
  577. package/dist/core/scoped-state/providers.js +0 -1
  578. package/dist/core/scoped-state/settings.d.ts +0 -28
  579. package/dist/core/scoped-state/settings.js +0 -1
@@ -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;
@@ -1,2 +1,2 @@
1
- var D=Object.defineProperty;var r=(c,e)=>D(c,"name",{value:e,configurable:!0});import{ApiError as M}from"../../../api/errors.js";import{getNode as y}from"../../../core/canvas/canvas.js";import{brokerSignalBus as E}from"../../broker-signals/bus.js";import{boundDaemonControl as T}from"../../control.js";import{requireCurrentExecution as v}from"./broker-recovery.js";import{extensionNode as _}from"./broker-ops.js";const R=15e3,C=3e4;class N{static{r(this,"BrokerSignalStreams")}timing;streams=new Map;constructor(e={pingMs:R,blockedMs:C}){this.timing=e}async open(e,t,u,d){this.streams.get(e)?.close();let n=!1,i=!1,h=!1,w=!1,g=!1,s,m,b;const a=r((o=!1)=>{n||(n=!0,m!==void 0&&clearInterval(m),s!==void 0&&clearTimeout(s),t.off("drain",k),t.off("close",l),t.off("error",l),d.off("aborted",l),b?.(),this.streams.get(e)===S&&this.streams.delete(e),o?t.destroy():t.writableEnded||t.end())},"close"),f=r(o=>{n||i||t.write(`${JSON.stringify(o)}
2
- `)||(i=!0,s=setTimeout(()=>a(!0),this.timing.blockedMs),s.unref())},"send"),p=r(async()=>{if(!(n||i)&&(h&&(h=!1,f({type:"mail",channel:"wake",at:Date.now()})),g&&!i&&(g=!1,f({type:"fault-retry",at:Date.now()})),w&&!i)){w=!1;const o=await y(e);o!==null&&f({type:"node",node:await _(o),at:Date.now()})}},"flush"),k=r(()=>{i=!1,s!==void 0&&clearTimeout(s),s=void 0,p().catch(()=>a())},"drain"),l=r(()=>a(),"onClosed"),S={close:a,nudgeFaultRetry:r(async()=>{if(!n){g=!0;try{await p()}catch{a()}}},"nudgeFaultRetry")};this.streams.set(e,S),t.on("drain",k),t.once("close",l),t.once("error",l),b=await E.subscribe((o,x)=>{o!==e||n||(x==="mail"?h=!0:w=!0,p().catch(()=>a()))}),m=setInterval(()=>{if(!(i||n))try{f({type:"ping",at:Date.now()})}catch{a()}},this.timing.pingMs),m.unref(),d.once("aborted",l);try{f(u),await p()}catch{a()}}async nudgeFaultRetry(e){const t=this.streams.get(e);return t===void 0?!1:(await t.nudgeFaultRetry(),!0)}close(){for(const e of[...this.streams.values()])e.close()}}const B=new N;async function F(c){const e=c.params.id??"",t=await y(e);if(t===null)throw new M(404,"node_not_found",`no node ${e}`);const u=c.query.get("execution_id");await v(e,u);const{req:d,res:n}=c;n.writeHead(200,{"content-type":"application/x-ndjson; charset=utf-8","cache-control":"no-cache",connection:"keep-alive"});try{await B.open(e,n,{type:"hello",epoch:T()?.epoch??"",execution_id:u,node:await _(await y(e)??t),at:Date.now()},d)}catch{n.writableEnded||n.end()}return{status:200}}r(F,"handleSignals");const J=[{method:"GET",pattern:"/v1/nodes/:id/broker/signals",handler:F}];export{N as BrokerSignalStreams,J as brokerSignalRoutes,B as brokerSignalStreams};
1
+ var D=Object.defineProperty;var r=(l,e)=>D(l,"name",{value:e,configurable:!0});import{ApiError as M}from"../../../api/errors.js";import{getNode as y}from"../../../core/canvas/canvas.js";import{brokerSignalBus as E}from"../../broker-signals/bus.js";import{boundDaemonControl as T}from"../../control.js";import{requireCurrentExecution as v}from"./broker-recovery.js";import{extensionNode as x}from"./broker-ops.js";const C=15e3,N=3e4;class B{static{r(this,"BrokerSignalStreams")}timing;streams=new Map;constructor(e={pingMs:C,blockedMs:N}){this.timing=e}async open(e,t,u,d){this.streams.get(e)?.close();let n=!1,a=!1,p=!1,h=!1,w=!1,i,m,b;const s=r((o=!1)=>{n||(n=!0,m!==void 0&&clearInterval(m),i!==void 0&&clearTimeout(i),t.off("drain",k),t.off("close",c),t.off("error",c),d.off("aborted",c),b?.(),this.streams.get(e)===S&&this.streams.delete(e),o?t.destroy():t.writableEnded||t.end())},"close"),f=r(o=>{n||a||t.write(`${JSON.stringify(o)}
2
+ `)||(a=!0,i=setTimeout(()=>s(!0),this.timing.blockedMs),i.unref())},"send"),g=r(async()=>{if(!(n||a)&&(p&&(p=!1,f({type:"mail",channel:"wake",at:Date.now()})),w&&!a&&(w=!1,f({type:"fault-retry",at:Date.now()})),h&&!a)){h=!1;const o=await y(e);o!==null&&f({type:"node",node:await x(o),at:Date.now()})}},"flush"),k=r(()=>{a=!1,i!==void 0&&clearTimeout(i),i=void 0,g().catch(()=>s())},"drain"),c=r(()=>s(),"onClosed"),S={close:s};this.streams.set(e,S),t.on("drain",k),t.once("close",c),t.once("error",c),b=await E.subscribe((o,_)=>{o!==e||n||(_==="mail"?p=!0:_==="fault_retry"?w=!0:h=!0,g().catch(()=>s()))},{kinds:["mail","node","fault_retry"]}),m=setInterval(()=>{if(!(a||n))try{f({type:"ping",at:Date.now()})}catch{s()}},this.timing.pingMs),m.unref(),d.once("aborted",c);try{f(u),await g()}catch{s()}}close(){for(const e of[...this.streams.values()])e.close()}}const q=new B;async function G(l){const e=l.params.id??"",t=await y(e);if(t===null)throw new M(404,"node_not_found",`no node ${e}`);const u=l.query.get("execution_id");await v(e,u);const{req:d,res:n}=l;n.writeHead(200,{"content-type":"application/x-ndjson; charset=utf-8","cache-control":"no-cache",connection:"keep-alive"});try{await q.open(e,n,{type:"hello",epoch:T()?.epoch??"",execution_id:u,node:await x(await y(e)??t),at:Date.now()},d)}catch{n.writableEnded||n.end()}return{status:200}}r(G,"handleSignals");const K=[{method:"GET",pattern:"/v1/nodes/:id/broker/signals",handler:G}];export{B as BrokerSignalStreams,K as brokerSignalRoutes,q as brokerSignalStreams};
@@ -1,6 +1,6 @@
1
- var Q=Object.defineProperty;var c=(n,e)=>Q(n,"name",{value:e,configurable:!0});import{gzipSync as Y}from"node:zlib";import{browseNodes as B,graphNodes as V,pruneNodes as X,pruneToLimit as Z,rosterEdges as N,rosterNodes as ee}from"../../../core/canvas/canvas.js";import{liveObjectWaitsNamed as te,readControllerWait as ne}from"../../../core/canvas/waits.js";import{activeBackgroundBashJobs as se}from"../../../core/bash-jobs.js";import{contextDir as oe}from"../../../core/canvas/node-agent-paths.js";import{nowIso as I}from"../../../core/fs-utils.js";import{isPidPresent as re}from"../../../core/canvas/pid.js";import{dashboardRowsAllFromSource as ie,enrichRowsFromSource as ae}from"../../../core/canvas/render-source.js";import{localCanvasSource as P}from"../../../core/canvas/source.js";import{ticketCountsForNodes as F,ticketsAcrossCanvas as de}from"../../../core/canvas/attention.js";import{buildCorpus as le,groupCorpus as ce,resolveRef as ue}from"../../../core/canvas/history.js";import{listFocuses as G,reapEmptyNodes as fe}from"../../../core/runtime/placement.js";import{boundFleet as me}from"../../../core/runtime/fleet.js";import{retentionHold as pe}from"../../reconcilers/live-obligation.js";import{notFound as _e,usage as _}from"../../../core/errors.js";import{openDb as ye}from"../../../core/canvas/db.js";import{view as he}from"../../../core/canvas/tree.js";import{isLiveStatus as be}from"../../../core/canvas/node-order.js";import{readNodeRecap as ge}from"../../../core/canvas/node-recap.js";import{readGoal as ve}from"../../../core/runtime/kickoff.js";import{faultSummary as we}from"../../../core/canvas/status-glyph.js";import{listPendingAsks as ke}from"../../../core/human/requests.js";import{toGraphNodeDTO as Se}from"../map.js";import{actsAsPerson as Ne,readableNodeIds as D}from"../router.js";import{ApiError as T}from"../../../api/errors.js";import{mapAsync as q}from"../../../core/async-array.js";async function w(n){return await D(n.principal)}c(w,"visibleNodes");async function Ce(n){const e=await w(n);return{status:200,body:{items:(await de()).filter(t=>e===null||e.has(t.node_id)).map(t=>({node_id:t.node_id,name:t.name,cwd:t.cwd,count:t.count,subjects:t.subjects}))}}}c(Ce,"handleAttention");async function Re(n){const e=n.body;if(e===null||typeof e!="object"||!Array.isArray(e.node_ids))throw _("attention count request requires node_ids: string[]");const o=e.node_ids;if(!o.every(l=>typeof l=="string"))throw _("attention count request node_ids must contain only strings");const t=await w(n);return{status:200,body:{counts:await F(o.filter(l=>t===null||t.has(l)))}}}c(Re,"handleAttentionCounts");function x(n){return Buffer.from(String(n),"utf8").toString("base64")}c(x,"encodeCursor");function H(n){const e=Number(Buffer.from(n,"base64").toString("utf8"));if(!Number.isInteger(e)||e<0)throw _(`invalid cursor: ${n}`);return e}c(H,"decodeCursor");function je(n,e,o){const a=n.loadBody().split(`
2
- `);if(e.length>0){const i=a.findIndex(m=>{const f=m.toLowerCase();return e.some(y=>f.includes(y))});if(i!==-1)return a.slice(i,i+o).map(m=>m.trim()).filter(m=>m!=="").join(" \u23CE ")}const l=a.map(i=>i.trim()).filter(i=>i!=="").slice(0,o).join(" \u23CE ");return l!==""?l:n.title}c(je,"snippet");function Ie(n,e,o){const t=[...n];return e==="relevance"&&o!==void 0?t.sort((a,l)=>(o.get(l.ref)??0)-(o.get(a.ref)??0)||l.tsMs-a.tsMs||a.ref.localeCompare(l.ref)):e==="oldest"?t.sort((a,l)=>a.tsMs-l.tsMs||a.ref.localeCompare(l.ref)):t.sort((a,l)=>l.tsMs-a.tsMs||a.ref.localeCompare(l.ref)),t}c(Ie,"sortArtifacts");function Me(n){if(n==null)return{};if(typeof n!="object")throw _("history search body must be a JSON object");return n}c(Me,"parseSearchBody");function Le(n){if(n===null||typeof n!="object")throw _("history grep body must be a JSON object");const e=n;if(typeof e.pattern!="string"||e.pattern==="")throw _("history grep body requires a non-empty pattern");return e}c(Le,"parseGrepBody");async function $(n,e){const o={cwd:n.cwd,allCwds:n.all_cwds===!0,under:n.under,nodes:n.nodes},t={types:n.types,kinds:n.kinds,statuses:n.statuses,sinceMs:n.since_ms,untilMs:n.until_ms,origins:n.origins,roles:n.roles,from:n.from},a=await w(e);return(await le(o,t)).filter(l=>a===null||a.has(l.nodeId))}c($,"buildCorpusFromQuery");function Oe(n){if(n==null)return{};if(typeof n!="object")throw _("history stats body must be a JSON object");return n}c(Oe,"parseStatsBody");const z=["origin","node","kind","day","type","role"];async function Ee(n){const e=Oe(n.body),o=e.group_by??"type";if(!z.includes(o))throw _(`--group-by must be one of: ${z.join(", ")}; received: ${String(e.group_by)}`);const t=await $(e,n),a=ce(t,o);return{status:200,body:{group_by:o,groups:a,total:a.reduce((i,m)=>i+m.count,0),scanned:t.length}}}c(Ee,"handleHistoryStats");async function Te(n){const e=Le(n.body),o=Math.min(100,Math.max(1,e.limit??20)),t=await $(e,n),a=e.cursor!==void 0?H(e.cursor):0;let l;try{l=new RegExp(e.pattern,"i")}catch{throw _(`invalid regex pattern: ${e.pattern}`)}const i=[];for(const r of t)r.loadBody().split(`
3
- `).forEach((u,g)=>{l.test(u)&&i.push({ref:r.ref,node:`${r.nodeName} (${r.nodeId})`,ts:r.ts,line:g+1,text:u.trim()})});i.sort((r,s)=>r.ref.localeCompare(s.ref)||r.line-s.line);const m=i.slice(a,a+o),f=a+o<i.length?x(a+o):null;return{status:200,body:{hits:m,next_cursor:f,total:i.length}}}c(Te,"handleHistoryGrep");async function $e(n){const e=Me(n.body),o=(e.query??"").trim(),t=e.weigh_body===!0,a=e.full===!0,l=Math.max(1,e.snippet_lines??1),i=Math.min(100,Math.max(1,e.limit??20)),m=e.per_node===!0;if(m&&(e.nodes===void 0||e.nodes.length===0))throw new T(400,"invalid_request","`per_node` requires a non-empty `nodes` list",{param:"nodes"});const f=await $(e,n),y=e.cursor!==void 0?H(e.cursor):0,r=o.toLowerCase().split(/\s+/).filter(d=>d.length>0);let s=f,u;const g=e.sort??(r.length>0?"relevance":"recency");if(r.length>0&&g==="relevance"){u=new Map;const d=[];for(const p of f){const E=p.title.toLowerCase(),W=p.nodeName.toLowerCase(),U=p.nodeDesc.toLowerCase(),A=t?p.loadBody().toLowerCase():null;let S=0;for(const j of r)E.includes(j)&&(S+=10),W.includes(j)&&(S+=5),U.includes(j)&&(S+=3),A!==null&&A.includes(j)&&(S+=1);S>0&&(u.set(p.ref,S),d.push(p))}s=d}else r.length>0&&(s=f.filter(d=>{const p=`${d.title}
1
+ var Y=Object.defineProperty;var c=(n,e)=>Y(n,"name",{value:e,configurable:!0});import{gzipSync as V}from"node:zlib";import{browseNodes as B,graphNodes as X,pruneNodes as Z,pruneToLimit as ee,rosterEdges as N,rosterNodes as te}from"../../../core/canvas/canvas.js";import{liveObjectWaitsNamed as ne,readControllerWait as se}from"../../../core/canvas/waits.js";import{runningJobs as oe}from"../../../core/graph/jobs.js";import{nowIso as I}from"../../../core/fs-utils.js";import{isPidPresent as re}from"../../../core/canvas/pid.js";import{dashboardRowsAllFromSource as ie,enrichRowsFromSource as ae}from"../../../core/canvas/render-source.js";import{localCanvasSource as P}from"../../../core/canvas/source.js";import{ticketCountsForNodes as F,ticketsAcrossCanvas as de}from"../../../core/canvas/attention.js";import{buildCorpus as le,groupCorpus as ce,resolveRef as ue}from"../../../core/canvas/history.js";import{listFocuses as G,reapEmptyNodes as fe}from"../../../core/runtime/placement.js";import{boundFleet as me}from"../../../core/runtime/fleet.js";import{retentionHold as pe}from"../../reconcilers/live-obligation.js";import{notFound as _e,usage as _}from"../../../core/errors.js";import{openDb as q}from"../../../core/canvas/db.js";import{view as ye}from"../../../core/canvas/tree.js";import{isLiveStatus as he}from"../../../core/canvas/node-order.js";import{readNodeRecap as be}from"../../../core/canvas/node-recap.js";import{readGoal as ge}from"../../../core/runtime/kickoff.js";import{faultSummary as ve}from"../../../core/canvas/status-glyph.js";import{listPendingAsks as we}from"../../../core/human/requests.js";import{toGraphNodeDTO as ke}from"../map.js";import{actsAsPerson as Se,readableNodeIds as D}from"../router.js";import{ApiError as T}from"../../../api/errors.js";import{mapAsync as x}from"../../../core/async-array.js";async function w(n){return await D(n.principal)}c(w,"visibleNodes");async function Ne(n){const e=await w(n);return{status:200,body:{items:(await de()).filter(t=>e===null||e.has(t.node_id)).map(t=>({node_id:t.node_id,name:t.name,cwd:t.cwd,count:t.count,subjects:t.subjects}))}}}c(Ne,"handleAttention");async function Ce(n){const e=n.body;if(e===null||typeof e!="object"||!Array.isArray(e.node_ids))throw _("attention count request requires node_ids: string[]");const o=e.node_ids;if(!o.every(l=>typeof l=="string"))throw _("attention count request node_ids must contain only strings");const t=await w(n);return{status:200,body:{counts:await F(o.filter(l=>t===null||t.has(l)))}}}c(Ce,"handleAttentionCounts");function H(n){return Buffer.from(String(n),"utf8").toString("base64")}c(H,"encodeCursor");function z(n){const e=Number(Buffer.from(n,"base64").toString("utf8"));if(!Number.isInteger(e)||e<0)throw _(`invalid cursor: ${n}`);return e}c(z,"decodeCursor");function Re(n,e,o){const a=n.loadBody().split(`
2
+ `);if(e.length>0){const i=a.findIndex(m=>{const f=m.toLowerCase();return e.some(y=>f.includes(y))});if(i!==-1)return a.slice(i,i+o).map(m=>m.trim()).filter(m=>m!=="").join(" \u23CE ")}const l=a.map(i=>i.trim()).filter(i=>i!=="").slice(0,o).join(" \u23CE ");return l!==""?l:n.title}c(Re,"snippet");function je(n,e,o){const t=[...n];return e==="relevance"&&o!==void 0?t.sort((a,l)=>(o.get(l.ref)??0)-(o.get(a.ref)??0)||l.tsMs-a.tsMs||a.ref.localeCompare(l.ref)):e==="oldest"?t.sort((a,l)=>a.tsMs-l.tsMs||a.ref.localeCompare(l.ref)):t.sort((a,l)=>l.tsMs-a.tsMs||a.ref.localeCompare(l.ref)),t}c(je,"sortArtifacts");function Ie(n){if(n==null)return{};if(typeof n!="object")throw _("history search body must be a JSON object");return n}c(Ie,"parseSearchBody");function Me(n){if(n===null||typeof n!="object")throw _("history grep body must be a JSON object");const e=n;if(typeof e.pattern!="string"||e.pattern==="")throw _("history grep body requires a non-empty pattern");return e}c(Me,"parseGrepBody");async function $(n,e){const o={cwd:n.cwd,allCwds:n.all_cwds===!0,under:n.under,nodes:n.nodes},t={types:n.types,kinds:n.kinds,statuses:n.statuses,sinceMs:n.since_ms,untilMs:n.until_ms,origins:n.origins,roles:n.roles,from:n.from},a=await w(e);return(await le(o,t)).filter(l=>a===null||a.has(l.nodeId))}c($,"buildCorpusFromQuery");function Le(n){if(n==null)return{};if(typeof n!="object")throw _("history stats body must be a JSON object");return n}c(Le,"parseStatsBody");const J=["origin","node","kind","day","type","role"];async function Oe(n){const e=Le(n.body),o=e.group_by??"type";if(!J.includes(o))throw _(`--group-by must be one of: ${J.join(", ")}; received: ${String(e.group_by)}`);const t=await $(e,n),a=ce(t,o);return{status:200,body:{group_by:o,groups:a,total:a.reduce((i,m)=>i+m.count,0),scanned:t.length}}}c(Oe,"handleHistoryStats");async function Ee(n){const e=Me(n.body),o=Math.min(100,Math.max(1,e.limit??20)),t=await $(e,n),a=e.cursor!==void 0?z(e.cursor):0;let l;try{l=new RegExp(e.pattern,"i")}catch{throw _(`invalid regex pattern: ${e.pattern}`)}const i=[];for(const r of t)r.loadBody().split(`
3
+ `).forEach((u,g)=>{l.test(u)&&i.push({ref:r.ref,node:`${r.nodeName} (${r.nodeId})`,ts:r.ts,line:g+1,text:u.trim()})});i.sort((r,s)=>r.ref.localeCompare(s.ref)||r.line-s.line);const m=i.slice(a,a+o),f=a+o<i.length?H(a+o):null;return{status:200,body:{hits:m,next_cursor:f,total:i.length}}}c(Ee,"handleHistoryGrep");async function Te(n){const e=Ie(n.body),o=(e.query??"").trim(),t=e.weigh_body===!0,a=e.full===!0,l=Math.max(1,e.snippet_lines??1),i=Math.min(100,Math.max(1,e.limit??20)),m=e.per_node===!0;if(m&&(e.nodes===void 0||e.nodes.length===0))throw new T(400,"invalid_request","`per_node` requires a non-empty `nodes` list",{param:"nodes"});const f=await $(e,n),y=e.cursor!==void 0?z(e.cursor):0,r=o.toLowerCase().split(/\s+/).filter(d=>d.length>0);let s=f,u;const g=e.sort??(r.length>0?"relevance":"recency");if(r.length>0&&g==="relevance"){u=new Map;const d=[];for(const p of f){const E=p.title.toLowerCase(),U=p.nodeName.toLowerCase(),Q=p.nodeDesc.toLowerCase(),A=t?p.loadBody().toLowerCase():null;let S=0;for(const j of r)E.includes(j)&&(S+=10),U.includes(j)&&(S+=5),Q.includes(j)&&(S+=3),A!==null&&A.includes(j)&&(S+=1);S>0&&(u.set(p.ref,S),d.push(p))}s=d}else r.length>0&&(s=f.filter(d=>{const p=`${d.title}
4
4
  ${d.nodeName}
5
5
  ${d.nodeDesc}${t?`
6
- `+d.loadBody():""}`.toLowerCase();return r.some(E=>p.includes(E))}));let b=Ie(s,g,u);if(m){const d=new Set;b=b.filter(p=>!d.has(p.nodeId)&&d.add(p.nodeId))}const v=m?b:b.slice(y,y+i),h=!m&&y+i<b.length?x(y+i):null;return{status:200,body:{hits:v.map(d=>{const p={ref:d.ref,node:`${d.nodeName} (${d.nodeId})`,kind:d.nodeKind,source:d.source,ts:d.ts,...m?{node_id:d.nodeId}:{}};return g==="relevance"&&u!==void 0&&(p.score=u.get(d.ref)??0),a?p.body=d.loadBody():p.snippet=je(d,r,l),p}),next_cursor:h,total:b.length}}}c($e,"handleHistorySearch");async function Ae(n){const e=(n.query.get("ref")??"").trim();if(!e.includes(":"))throw _(`ref must be <node-id>:inbox/<n>, <node-id>:session, or <node-id>:session/<n>; received: ${e}`,{received:e,next:"Get a valid ref from `crtr canvas history search`. Reports and documents are `crtr canvas read <name>`."});const o=await ue(e);if(o===null)throw _e(`no inbox entry or message for ref: ${e}`,{ref:e,next:"Re-run `crtr canvas history search` for a current ref. Reports and documents are `crtr canvas read <name>`."});if((await w(n))?.has(o.nodeId)===!1)throw new T(404,"not_found","artifact not found");const t=o.source,l=n.query.get("format")==="raw"&&o.raw!==null?o.raw:o.body;return{status:200,body:{ref:e,node:`${o.nodeName} (${o.nodeId})`,source:t,ts:o.ts,content:l}}}c(Ae,"handleHistoryRead");function Be(n){for(const[t]of n.query)if(t!=="live")throw _(`unknown snapshot query parameter: ${t}`);const e=n.query.getAll("live");if(e.length>1)throw _("live must appear at most once");const o=e[0];if(o===void 0||o==="false"||o==="0")return!1;if(o==="true"||o==="1")return!0;throw _("live must be true or false")}c(Be,"snapshotLiveOnly");async function Pe(n){const e=new Set((await G()).map(r=>r.node_id)),o=await w(n),t=(await ie(P,e,Be(n))).filter(r=>o===null||o.has(r.node_id)),a=await F(t.map(r=>r.node_id));await ae(P,t,a);const l=await q(t,async r=>{const s=r.srcRow,u=s?.host_kind??"tmux";return{node_id:r.node_id,name:r.name,title:r.handle??r.name,description:r.description??null,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle??s?.lifecycle,status:r.status,cwd:r.cwd,profile_id:r.profile_id??null,parent:s?.parent??null,created:r.created,host_kind:u,enterable:u==="broker",attention_count:r.asks,...s?.cycles!=null?{cycles:s.cycles}:{},...r.mtimeMs!==void 0?{last_activity:new Date(r.mtimeMs).toISOString()}:{},ctx_tokens:r.ctx_tokens,streaming:r.streaming??!1,jobs_active:s!==void 0&&re(s.pi_pid)?se(await oe(r.node_id)).length:0,waiting_for:(await ne(r.node_id))?.controllerId??null,hanging:r.hanging??null,viewed:r.viewed??!1,final_report:s?.final_report??null,finalized_at:s?.finalized_at??null}}),i=new Map;for(const r of await N()){const s=i.get(r.from_id);s===void 0?i.set(r.from_id,[r.to_id]):s.push(r.to_id)}const m=new Set(t.map(r=>r.node_id)),f=Object.fromEntries(t.map(r=>[r.node_id,(i.get(r.node_id)??[]).filter(s=>m.has(s))]));return{status:200,body:{generated_at:I(),nodes:l,subscriptions:f}}}c(Pe,"handleSnapshot");async function J(){const n=(await ee()).map(t=>{const a=t.host_kind??"tmux";return{node_id:t.node_id,name:t.name,kind:t.kind,mode:t.mode,lifecycle:t.lifecycle,status:t.status,cwd:t.cwd,host_kind:a,enterable:a==="broker",parent:t.parent,created:t.created,description:t.description}}),e=(await N()).map(t=>({from_id:t.from_id,to_id:t.to_id,active:t.active,created:t.created})),o=(await te()).map(t=>({node_id:t.nodeId,object_id:t.objectId,object_type:t.objectType,object_name:t.objectName,created:new Date(t.createdAt).toISOString()}));return{generated_at:I(),nodes:n,edges:e,object_waits:o}}c(J,"buildRoster");let C=null,M=null;function Fe(){return C===null?(C=Promise.resolve().then(async()=>await J()).finally(()=>{C=null}),C):(M===null&&(M=C.then(async()=>await J()).finally(()=>{M=null})),M)}c(Fe,"rosterCoalesced");async function Ge(n){const e=await Fe(),o=await w(n);return o===null?{status:200,body:e}:{status:200,body:{...e,nodes:e.nodes.filter(t=>o.has(t.node_id)),edges:e.edges.filter(t=>o.has(t.from_id)&&o.has(t.to_id)),object_waits:(e.object_waits??[]).filter(t=>o.has(t.node_id))}}}c(Ge,"handleRoster");function K(n){if(n.name!==""&&n.name!==n.kind)return n.name;const e=(n.description??"").trim();return e!==""?e:n.name}c(K,"liveRootName");const De=1440*6e4;async function qe(){const n=await B(),e=new Map(n.map(s=>[s.node_id,s])),o=new Map((await(await ye()).prepare("SELECT node_id, reply_at, read_at, intent FROM nodes WHERE parent IS NULL").all()).map(s=>[s.node_id,s])),t=await ke(),a=new Map;for(const s of t)a.set(s.requester_node_id,(a.get(s.requester_node_id)??0)+1);const l=new Date(Date.now()-De).toISOString(),i=c(s=>{const u=o.get(s.node_id);return u?.reply_at!=null&&(u.read_at==null||u.reply_at>u.read_at)||(a.get(s.node_id)??0)>0?!0:s.status!=="done"||u?.intent!=="parked"?!1:[s.created,s.telemetry_updated_at,u.reply_at].reduce((v,h)=>h!=null&&h>v?h:v,"")>=l},"keepFinished"),m=n.filter(s=>s.parent===null&&s.kind!=="human"&&(be(s.status)||i(s))),f=new Map;for(const s of await N())f.set(s.from_id,[...f.get(s.from_id)??[],s.to_id]);const y=c(s=>{const u=e.get(s)?.fault;return u&&u.link!=="broker\u2194crtrd"?we(u):null},"faultOf"),r=await q(m,async s=>{const u=[s.node_id,...await he(s.node_id)].filter(d=>e.get(d)?.kind!=="human"&&e.has(d)),g=new Set(u),b=t.filter(d=>g.has(d.requester_node_id)),v=o.get(s.node_id),h=v?.reply_at??null,O=v?.read_at??null;let k=s.created;for(const d of u){const p=e.get(d).telemetry_updated_at;p!=null&&p>k&&(k=p)}return h!==null&&h>k&&(k=h),{node_id:s.node_id,name:K(s),cwd:s.cwd,profile_id:s.profile_id,status:s.status,state_line:(()=>{const d=ge(s.node_id)?.state.trim();return d||null})(),goal:(await ve(s.node_id))?.trim()||null,asks:b.length,first_ask_ticket_id:b[0]?.inbox_ticket_id??null,fault:u.map(y).find(d=>d!==null)??null,running_count:u.filter(d=>e.get(d).streaming===!0).length,unread:h!==null&&(O===null||h>O),last_activity:k,children:(f.get(s.node_id)??[]).filter(d=>e.has(d)&&e.get(d).kind!=="human").map(d=>{const p=e.get(d);return{node_id:d,name:K(p),status:p.status,streaming:p.streaming===!0,asks:a.get(d)??0,fault:y(d)}})}});return{generated_at:I(),rows:r}}c(qe,"buildLiveRoots");let R=null,L=null;function xe(){const n=c(()=>Promise.resolve().then(qe),"run");return R===null?(R=n().finally(()=>{R=null}),R):(L===null&&(L=R.then(n).finally(()=>{L=null})),L)}c(xe,"liveRootsCoalesced");async function He(n){if(!Ne(n.principal))throw new T(403,"permission_error","only the person reads the dashboard");const e=await xe(),o=n.query.get("profile");return{status:200,body:o===null?e:{...e,rows:e.rows.filter(t=>t.profile_id===o)}}}c(He,"handleLiveRoots");async function ze(n){const e=await D(n.principal),o=(await B()).filter(i=>e===null||e.has(i.node_id)).map(i=>({node_id:i.node_id,name:i.name,description:i.description,kind:i.kind,mode:i.mode,lifecycle:i.lifecycle,status:i.status,cwd:i.cwd,profile_id:i.profile_id,grantee:i.grantee??"app:terminal",parent:i.parent,created:i.created,frozen_at:i.frozen_at??null,terminal_reason:i.terminal_reason??null,final_report:i.final_report??null,telemetry_tokens_in:i.telemetry_tokens_in??null,telemetry_updated_at:i.telemetry_updated_at??null,fault:i.fault&&i.fault.link!=="broker\u2194crtrd"?{...i.fault,link:i.fault.link}:null,streaming:i.streaming??!1})),t=new Set(o.map(i=>i.node_id)),a=(await N()).filter(i=>t.has(i.from_id)&&t.has(i.to_id));return{status:200,rawBody:Y(JSON.stringify({nodes:o,edges:a}),{level:1}),headers:{"content-type":"application/gzip"}}}c(ze,"handleBrowse");async function Je(n){const e=await w(n);return{status:200,body:{generated_at:I(),nodes:(await V()).filter(t=>e===null||e.has(t.node_id)).map(Se),edges:(await N()).filter(t=>e===null||e.has(t.from_id)&&e.has(t.to_id)).map(t=>({from_id:t.from_id,to_id:t.to_id,active:t.active,created:t.created})),focused_node_ids:(await G()).map(t=>t.node_id).filter(t=>e===null||e.has(t))}}}c(Je,"handleGraph");function Ke(n){if(n==null)return{};if(typeof n!="object")throw _("prune body must be a JSON object");const e=n,o=c(r=>{const s=e[r];if(s!==void 0){if(typeof s!="number"||!Number.isFinite(s))throw _(`${r} must be a number`);return s}},"num"),t=c(r=>{const s=e[r];if(s!==void 0){if(typeof s!="boolean")throw _(`${r} must be a boolean`);return s}},"bool"),a={},l=o("limit");l!==void 0&&(a.limit=l);const i=o("ttl_days");i!==void 0&&(a.ttl_days=i);const m=t("include_stale");m!==void 0&&(a.include_stale=m);const f=t("empty");f!==void 0&&(a.empty=f);const y=t("dry_run");return y!==void 0&&(a.dry_run=y),a}c(Ke,"parsePruneBody");async function We(n){const e=Ke(n.body),o=e.ttl_days??14,t=e.dry_run??!1,a=await pe(me());let l;return e.limit!==void 0?l=(await Z({maxNodes:e.limit,held:a,dryRun:t})).pruned.map(f=>({node_id:f.node_id,status:f.status,created:f.created})):e.empty===!0?l=(await fe({dryRun:t})).map(f=>({node_id:f,status:"empty",created:""})):l=(await X({ttlDays:o,held:a,dryRun:t,includeStale:e.include_stale??!1})).pruned.map(f=>({node_id:f.node_id,status:f.status,created:f.created})),{status:200,body:{pruned:l,dry_run:t,ttl_days:o}}}c(We,"handlePrune");const wt=[{method:"GET",pattern:"/v1/canvas/attention",handler:Ce},{method:"POST",pattern:"/v1/canvas/attention/counts",handler:Re},{method:"POST",pattern:"/v1/canvas/history/search",handler:$e},{method:"POST",pattern:"/v1/canvas/history/grep",handler:Te},{method:"GET",pattern:"/v1/canvas/history/read",handler:Ae},{method:"POST",pattern:"/v1/canvas/history/stats",handler:Ee},{method:"GET",pattern:"/v1/canvas/snapshot",handler:Pe},{method:"GET",pattern:"/v1/canvas/roster",handler:Ge},{method:"GET",pattern:"/v1/canvas/live-roots",handler:He},{method:"GET",pattern:"/v1/canvas/browse",handler:ze},{method:"GET",pattern:"/v1/canvas/graph",handler:Je},{method:"POST",pattern:"/v1/canvas/prune",ownerOnly:!0,handler:We}];export{wt as canvasRoutes,ze as handleBrowse};
6
+ `+d.loadBody():""}`.toLowerCase();return r.some(E=>p.includes(E))}));let b=je(s,g,u);if(m){const d=new Set;b=b.filter(p=>!d.has(p.nodeId)&&d.add(p.nodeId))}const v=m?b:b.slice(y,y+i),h=!m&&y+i<b.length?H(y+i):null;return{status:200,body:{hits:v.map(d=>{const p={ref:d.ref,node:`${d.nodeName} (${d.nodeId})`,kind:d.nodeKind,source:d.source,ts:d.ts,...m?{node_id:d.nodeId}:{}};return g==="relevance"&&u!==void 0&&(p.score=u.get(d.ref)??0),a?p.body=d.loadBody():p.snippet=Re(d,r,l),p}),next_cursor:h,total:b.length}}}c(Te,"handleHistorySearch");async function $e(n){const e=(n.query.get("ref")??"").trim();if(!e.includes(":"))throw _(`ref must be <node-id>:inbox/<n>, <node-id>:session, or <node-id>:session/<n>; received: ${e}`,{received:e,next:"Get a valid ref from `crtr canvas history search`. Reports and documents are `crtr canvas read <name>`."});const o=await ue(e);if(o===null)throw _e(`no inbox entry or message for ref: ${e}`,{ref:e,next:"Re-run `crtr canvas history search` for a current ref. Reports and documents are `crtr canvas read <name>`."});if((await w(n))?.has(o.nodeId)===!1)throw new T(404,"not_found","artifact not found");const t=o.source,l=n.query.get("format")==="raw"&&o.raw!==null?o.raw:o.body;return{status:200,body:{ref:e,node:`${o.nodeName} (${o.nodeId})`,source:t,ts:o.ts,content:l}}}c($e,"handleHistoryRead");function Ae(n){for(const[t]of n.query)if(t!=="live")throw _(`unknown snapshot query parameter: ${t}`);const e=n.query.getAll("live");if(e.length>1)throw _("live must appear at most once");const o=e[0];if(o===void 0||o==="false"||o==="0")return!1;if(o==="true"||o==="1")return!0;throw _("live must be true or false")}c(Ae,"snapshotLiveOnly");async function Be(n){const e=new Set((await G()).map(r=>r.node_id)),o=await w(n),t=(await ie(P,e,Ae(n))).filter(r=>o===null||o.has(r.node_id)),a=await F(t.map(r=>r.node_id));await ae(P,t,a);const l=await x(t,async r=>{const s=r.srcRow,u=s?.host_kind??"tmux";return{node_id:r.node_id,name:r.name,title:r.handle??r.name,description:r.description??null,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle??s?.lifecycle,status:r.status,cwd:r.cwd,profile_id:r.profile_id??null,parent:s?.parent??null,created:r.created,host_kind:u,enterable:u==="broker",attention_count:r.asks,...s?.cycles!=null?{cycles:s.cycles}:{},...r.mtimeMs!==void 0?{last_activity:new Date(r.mtimeMs).toISOString()}:{},ctx_tokens:r.ctx_tokens,streaming:r.streaming??!1,jobs_active:s!==void 0&&re(s.pi_pid)?(await oe(await q(),r.node_id)).length:0,waiting_for:(await se(r.node_id))?.controllerId??null,hanging:r.hanging??null,viewed:r.viewed??!1,final_report:s?.final_report??null,finalized_at:s?.finalized_at??null}}),i=new Map;for(const r of await N(o)){const s=i.get(r.from_id);s===void 0?i.set(r.from_id,[r.to_id]):s.push(r.to_id)}const m=new Set(t.map(r=>r.node_id)),f=Object.fromEntries(t.map(r=>[r.node_id,(i.get(r.node_id)??[]).filter(s=>m.has(s))]));return{status:200,body:{generated_at:I(),nodes:l,subscriptions:f}}}c(Be,"handleSnapshot");async function K(){const n=(await te()).map(t=>{const a=t.host_kind??"tmux";return{node_id:t.node_id,name:t.name,kind:t.kind,mode:t.mode,lifecycle:t.lifecycle,status:t.status,cwd:t.cwd,host_kind:a,enterable:a==="broker",parent:t.parent,created:t.created,description:t.description}}),e=(await N()).map(t=>({from_id:t.from_id,to_id:t.to_id,active:t.active,created:t.created})),o=(await ne()).map(t=>({node_id:t.nodeId,object_id:t.objectId,object_type:t.objectType,object_name:t.objectName,created:new Date(t.createdAt).toISOString()}));return{generated_at:I(),nodes:n,edges:e,object_waits:o}}c(K,"buildRoster");let C=null,M=null;function Pe(){return C===null?(C=Promise.resolve().then(async()=>await K()).finally(()=>{C=null}),C):(M===null&&(M=C.then(async()=>await K()).finally(()=>{M=null})),M)}c(Pe,"rosterCoalesced");async function Fe(n){const e=await Pe(),o=await w(n);return o===null?{status:200,body:e}:{status:200,body:{...e,nodes:e.nodes.filter(t=>o.has(t.node_id)),edges:e.edges.filter(t=>o.has(t.from_id)&&o.has(t.to_id)),object_waits:(e.object_waits??[]).filter(t=>o.has(t.node_id))}}}c(Fe,"handleRoster");function W(n){if(n.name!==""&&n.name!==n.kind)return n.name;const e=(n.description??"").trim();return e!==""?e:n.name}c(W,"liveRootName");const Ge=1440*6e4;async function qe(){const n=await B(),e=new Map(n.map(s=>[s.node_id,s])),o=new Map((await(await q()).prepare("SELECT node_id, reply_at, read_at, intent FROM nodes WHERE parent IS NULL").all()).map(s=>[s.node_id,s])),t=await we(),a=new Map;for(const s of t)a.set(s.requester_node_id,(a.get(s.requester_node_id)??0)+1);const l=new Date(Date.now()-Ge).toISOString(),i=c(s=>{const u=o.get(s.node_id);return u?.reply_at!=null&&(u.read_at==null||u.reply_at>u.read_at)||(a.get(s.node_id)??0)>0?!0:s.status!=="done"||u?.intent!=="parked"?!1:[s.created,s.telemetry_updated_at,u.reply_at].reduce((v,h)=>h!=null&&h>v?h:v,"")>=l},"keepFinished"),m=n.filter(s=>s.parent===null&&s.kind!=="human"&&(he(s.status)||i(s))),f=new Map;for(const s of await N())f.set(s.from_id,[...f.get(s.from_id)??[],s.to_id]);const y=c(s=>{const u=e.get(s)?.fault;return u&&u.link!=="broker\u2194crtrd"?ve(u):null},"faultOf"),r=await x(m,async s=>{const u=[s.node_id,...await ye(s.node_id)].filter(d=>e.get(d)?.kind!=="human"&&e.has(d)),g=new Set(u),b=t.filter(d=>g.has(d.requester_node_id)),v=o.get(s.node_id),h=v?.reply_at??null,O=v?.read_at??null;let k=s.created;for(const d of u){const p=e.get(d).telemetry_updated_at;p!=null&&p>k&&(k=p)}return h!==null&&h>k&&(k=h),{node_id:s.node_id,name:W(s),cwd:s.cwd,profile_id:s.profile_id,status:s.status,state_line:(()=>{const d=be(s.node_id)?.state.trim();return d||null})(),goal:(await ge(s.node_id))?.trim()||null,asks:b.length,first_ask_ticket_id:b[0]?.inbox_ticket_id??null,fault:u.map(y).find(d=>d!==null)??null,running_count:u.filter(d=>e.get(d).streaming===!0).length,unread:h!==null&&(O===null||h>O),last_activity:k,children:(f.get(s.node_id)??[]).filter(d=>e.has(d)&&e.get(d).kind!=="human").map(d=>{const p=e.get(d);return{node_id:d,name:W(p),status:p.status,streaming:p.streaming===!0,asks:a.get(d)??0,fault:y(d)}})}});return{generated_at:I(),rows:r}}c(qe,"buildLiveRoots");let R=null,L=null;function De(){const n=c(()=>Promise.resolve().then(qe),"run");return R===null?(R=n().finally(()=>{R=null}),R):(L===null&&(L=R.then(n).finally(()=>{L=null})),L)}c(De,"liveRootsCoalesced");async function xe(n){if(!Se(n.principal))throw new T(403,"permission_error","only the person reads the dashboard");const e=await De(),o=n.query.get("profile");return{status:200,body:o===null?e:{...e,rows:e.rows.filter(t=>t.profile_id===o)}}}c(xe,"handleLiveRoots");async function He(n){const e=await D(n.principal),o=(await B()).filter(i=>e===null||e.has(i.node_id)).map(i=>({node_id:i.node_id,name:i.name,description:i.description,kind:i.kind,mode:i.mode,lifecycle:i.lifecycle,status:i.status,cwd:i.cwd,profile_id:i.profile_id,grantee:i.grantee??"app:terminal",parent:i.parent,created:i.created,frozen_at:i.frozen_at??null,terminal_reason:i.terminal_reason??null,final_report:i.final_report??null,telemetry_tokens_in:i.telemetry_tokens_in??null,telemetry_updated_at:i.telemetry_updated_at??null,fault:i.fault&&i.fault.link!=="broker\u2194crtrd"?{...i.fault,link:i.fault.link}:null,streaming:i.streaming??!1})),t=new Set(o.map(i=>i.node_id)),a=(await N(e)).filter(i=>t.has(i.from_id)&&t.has(i.to_id));return{status:200,rawBody:V(JSON.stringify({nodes:o,edges:a}),{level:1}),headers:{"content-type":"application/gzip"}}}c(He,"handleBrowse");async function ze(n){const e=await w(n);return{status:200,body:{generated_at:I(),nodes:(await X()).filter(t=>e===null||e.has(t.node_id)).map(ke),edges:(await N(e)).filter(t=>e===null||e.has(t.from_id)&&e.has(t.to_id)).map(t=>({from_id:t.from_id,to_id:t.to_id,active:t.active,created:t.created})),focused_node_ids:(await G()).map(t=>t.node_id).filter(t=>e===null||e.has(t))}}}c(ze,"handleGraph");function Je(n){if(n==null)return{};if(typeof n!="object")throw _("prune body must be a JSON object");const e=n,o=c(r=>{const s=e[r];if(s!==void 0){if(typeof s!="number"||!Number.isFinite(s))throw _(`${r} must be a number`);return s}},"num"),t=c(r=>{const s=e[r];if(s!==void 0){if(typeof s!="boolean")throw _(`${r} must be a boolean`);return s}},"bool"),a={},l=o("limit");l!==void 0&&(a.limit=l);const i=o("ttl_days");i!==void 0&&(a.ttl_days=i);const m=t("include_stale");m!==void 0&&(a.include_stale=m);const f=t("empty");f!==void 0&&(a.empty=f);const y=t("dry_run");return y!==void 0&&(a.dry_run=y),a}c(Je,"parsePruneBody");async function Ke(n){const e=Je(n.body),o=e.ttl_days??14,t=e.dry_run??!1,a=await pe(me());let l;return e.limit!==void 0?l=(await ee({maxNodes:e.limit,held:a,dryRun:t})).pruned.map(f=>({node_id:f.node_id,status:f.status,created:f.created})):e.empty===!0?l=(await fe({dryRun:t})).map(f=>({node_id:f,status:"empty",created:""})):l=(await Z({ttlDays:o,held:a,dryRun:t,includeStale:e.include_stale??!1})).pruned.map(f=>({node_id:f.node_id,status:f.status,created:f.created})),{status:200,body:{pruned:l,dry_run:t,ttl_days:o}}}c(Ke,"handlePrune");const gt=[{method:"GET",pattern:"/v1/canvas/attention",handler:Ne},{method:"POST",pattern:"/v1/canvas/attention/counts",handler:Ce},{method:"POST",pattern:"/v1/canvas/history/search",handler:Te},{method:"POST",pattern:"/v1/canvas/history/grep",handler:Ee},{method:"GET",pattern:"/v1/canvas/history/read",handler:$e},{method:"POST",pattern:"/v1/canvas/history/stats",handler:Oe},{method:"GET",pattern:"/v1/canvas/snapshot",handler:Be},{method:"GET",pattern:"/v1/canvas/roster",handler:Fe},{method:"GET",pattern:"/v1/canvas/live-roots",handler:xe},{method:"GET",pattern:"/v1/canvas/browse",handler:He},{method:"GET",pattern:"/v1/canvas/graph",handler:ze},{method:"POST",pattern:"/v1/canvas/prune",ownerOnly:!0,handler:Ke}];export{gt as canvasRoutes,He as handleBrowse};
@@ -1,3 +1,3 @@
1
- import { type RouteTable } from '../router.js';
1
+ import type { RouteTable } from '../router.js';
2
2
  export declare const chargeRoutes: RouteTable;
3
3
  export declare const spendLimitRoutes: RouteTable;
@@ -1 +1 @@
1
- var b=Object.defineProperty;var o=(n,e)=>b(n,"name",{value:e,configurable:!0});import{ApiError as l}from"../../../api/errors.js";import{personIdAsync as w}from"../../../core/canvas/person.js";import{assertReference as v,deleteLimit as _,listCharges as q,listLimits as y,monthTotals as R,parseUsageMonth as E,upsertLimit as L}from"../../../core/ledger/index.js";import{ownerOnly as T}from"../router.js";import{integer as $}from"./runs.js";import{invalidRequest as N,objectBody as O}from"./validate.js";function k(n){const{principal:e}=n;if(e.class==="app"||e.class==="broker")return e.app;if(e.class!=="person")throw new l(403,"owner_only","charges are read by the person, a node or an app")}o(k,"granteeOf");async function F(n){const e=k(n),r=n.query.get("under"),t=n.query.get("after"),s=n.query.get("month"),i=r===null||s!==null?E(s):void 0,{charges:d,next:p}=await q({...i===void 0?{}:{month:i},...e===void 0?{}:{grantee:e},...r===null?{}:{under:v(r)},...t===null?{}:{after:t},limit:$(n.query.get("limit"),"limit",1,1e4,1e3)}),a=e===void 0&&r===null?await R(i):void 0;return{...i===void 0?{}:{month:i},charges:d,next:p,...a===void 0?{}:{totals:a}}}o(F,"listRoute");const h=["bill","subscription","key","endpoint","take","legacy"],f="person:";function g(n){const e=n.params.id??"";if(!e.startsWith(f)||e.length===f.length||e.length>128)throw new l(400,"invalid_request",`a person limit id starts with \`${f}\`; received ${e}`,{violations:[{field:"id",problem:`must start with ${f}`,received:e}]});return e}o(g,"idOf");function c(n,e,r){const t=n[e];if(t==null)return t;if(typeof t!="string"||t===""){r.push({field:e,problem:"must be a non-empty string or null",received:t});return}return t}o(c,"nullableString");async function G(n){const e=g(n),r=[],t=O(n.body,["payer","usd_per_month","funding","grantee","provider","sub"],r),s=t.payer;(typeof s!="string"||!/^(user|app):.+/.test(s))&&r.push({field:"payer",problem:"must be user:<id> or app:<id>",...s===void 0?{}:{received:s}});const i=t.usd_per_month;(typeof i!="number"||!Number.isFinite(i)||i<0)&&r.push({field:"usd_per_month",problem:"must be a number of at least 0",...i===void 0?{}:{received:i}});const d=c(t,"funding",r);typeof d=="string"&&!h.includes(d)&&r.push({field:"funding",problem:`must be one of ${h.join(", ")}`,received:d});const p=c(t,"grantee",r),a=c(t,"provider",r),m=c(t,"sub",r);r.length>0&&N("spend limit request",r);const u=t;if(u.payer.startsWith("user:")&&u.payer!==await w())throw new l(403,"owner_only","a person sets limits only on their own payer or on an app",{payer:u.payer});return await L({id:e,payer:u.payer,usd_per_month:u.usd_per_month,source:"person",...d===void 0?{}:{funding:d},...p===void 0?{}:{grantee:p},...a===void 0?{}:{provider:a},...m===void 0?{}:{sub:m}})}o(G,"setRoute");async function I(n){const e=g(n);if((await y({source:"person"})).find(t=>t.id===e)===void 0||!await _(e))throw new l(404,"not_found",`no person limit ${e}`);return{id:e,removed:!0}}o(I,"removeRoute");const B=[{method:"GET",pattern:"/v1/charges",handler:o(async n=>({status:200,body:await F(n)}),"handler")}],C=T([{method:"GET",pattern:"/v1/spend-limits",handler:o(async()=>({status:200,body:{limits:await y()}}),"handler")},{method:"PUT",pattern:"/v1/spend-limits/:id",handler:o(async n=>({status:200,body:await G(n)}),"handler")},{method:"DELETE",pattern:"/v1/spend-limits/:id",handler:o(async n=>({status:200,body:await I(n)}),"handler")}]);export{B as chargeRoutes,C as spendLimitRoutes};
1
+ var _=Object.defineProperty;var s=(n,e)=>_(n,"name",{value:e,configurable:!0});import{ApiError as p}from"../../../api/errors.js";import{personIdAsync as $}from"../../../core/canvas/person.js";import{assertReference as q,deleteLimit as R,listCharges as E,listLimits as w,monthTotals as L,parseUsageMonth as O,upsertLimit as T}from"../../../core/ledger/index.js";import{payersOf as b}from"../../../core/ledger/read.js";import{integer as N}from"./runs.js";import{invalidRequest as W,objectBody as k}from"./validate.js";function F(n){const{principal:e}=n;if(e.class==="app"||e.class==="broker")return{app:e.app};if(e.class==="person")return e.sub===void 0?void 0:{person:e.sub};throw new p(403,"owner_only","charges are read by the person, a node or an app")}s(F,"readerOf");async function G(n){const e=F(n),r=n.query.get("under"),t=n.query.get("after"),o=n.query.get("month"),i=r===null||o!==null?O(o):void 0,{charges:a,next:d}=await E({...i===void 0?{}:{month:i},...e===void 0?{}:{reader:e},...r===null?{}:{under:q(r)},...t===null?{}:{after:t},limit:N(n.query.get("limit"),"limit",1,1e4,1e3)}),f=r!==null||e!==void 0&&!("person"in e)?void 0:await L(i,e===void 0?void 0:e.person);return{...i===void 0?{}:{month:i},charges:a,next:d,...f===void 0?{}:{totals:f}}}s(G,"listRoute");const g=["bill","subscription","key","endpoint","take","legacy"],l="person:";function m(n){const{principal:e}=n;if(e.class!=="person")throw new p(403,"owner_only","spend limits are set by a person");return e.sub===void 0?void 0:e.sub.startsWith("user:")?e.sub:`user:${e.sub}`}s(m,"limitOwner");function v(n,e){const r=n.params.id??"";if(!r.startsWith(l)||r.length===l.length||r.length>128)throw new p(400,"invalid_request",`a person limit id starts with \`${l}\`; received ${r}`,{violations:[{field:"id",problem:`must start with ${l}`,received:r}]});if(e===void 0)return r;const t=r.slice(l.length);if(t.includes("/"))throw new p(400,"invalid_request","a person limit name has no `/`",{violations:[{field:"id",problem:"must not contain /",received:r}]});return`${l}${e.slice(5)}/${t}`}s(v,"idOf");function c(n,e,r){const t=n[e];if(t==null)return t;if(typeof t!="string"||t===""){r.push({field:e,problem:"must be a non-empty string or null",received:t});return}return t}s(c,"nullableString");async function I(n){const e=m(n),r=v(n,e),t=[],o=k(n.body,["payer","usd_per_month","funding","grantee","provider","sub"],t),i=o.payer;(typeof i!="string"||!/^(user|app):.+/.test(i))&&t.push({field:"payer",problem:"must be user:<id> or app:<id>",...i===void 0?{}:{received:i}});const a=o.usd_per_month;(typeof a!="number"||!Number.isFinite(a)||a<0)&&t.push({field:"usd_per_month",problem:"must be a number of at least 0",...a===void 0?{}:{received:a}});const d=c(o,"funding",t);typeof d=="string"&&!g.includes(d)&&t.push({field:"funding",problem:`must be one of ${g.join(", ")}`,received:d});const f=c(o,"grantee",t),y=c(o,"provider",t),h=c(o,"sub",t);t.length>0&&W("spend limit request",t);const u=o;if(e===void 0){if(u.payer.startsWith("user:")&&u.payer!==await $())throw new p(403,"owner_only","a person sets limits only on their own payer or on an app",{payer:u.payer})}else if(!(await b(e)).includes(u.payer))throw new p(403,"owner_only","a person sets limits only on their own payer or on an app they hold",{payer:u.payer});return await T({id:r,payer:u.payer,usd_per_month:u.usd_per_month,source:"person",...d===void 0?{}:{funding:d},...f===void 0?{}:{grantee:f},...y===void 0?{}:{provider:y},...h===void 0?{}:{sub:h}})}s(I,"setRoute");async function P(n){const e=m(n),r=await w();if(e===void 0)return{limits:r};const t=new Set(await b(e)),o=`${l}${e.slice(5)}/`;return{limits:r.filter(i=>i.id.startsWith(o)||i.payer!==null&&t.has(i.payer)||i.account===e)}}s(P,"listLimitsRoute");async function S(n){const e=v(n,m(n));if((await w({source:"person"})).find(t=>t.id===e)===void 0||!await R(e))throw new p(404,"not_found",`no person limit ${e}`);return{id:e,removed:!0}}s(S,"removeRoute");const X=[{method:"GET",pattern:"/v1/charges",handler:s(async n=>({status:200,body:await G(n)}),"handler")}],z=[{method:"GET",pattern:"/v1/spend-limits",handler:s(async n=>({status:200,body:await P(n)}),"handler")},{method:"PUT",pattern:"/v1/spend-limits/:id",handler:s(async n=>({status:200,body:await I(n)}),"handler")},{method:"DELETE",pattern:"/v1/spend-limits/:id",handler:s(async n=>({status:200,body:await S(n)}),"handler")}];export{X as chargeRoutes,z as spendLimitRoutes};
@@ -0,0 +1,2 @@
1
+ import type { RouteTable } from '../router.js';
2
+ export declare const conversationRoutes: RouteTable;
@@ -0,0 +1,3 @@
1
+ var _=Object.defineProperty;var r=(e,a)=>_(e,"name",{value:a,configurable:!0});import{conversationStore as b}from"../../../core/conversation-store/index.js";import{createRowStore as T}from"../../../core/conversation-store/row-store.js";import{conversationOwner as N}from"../../../core/canvas/sessions.js";import{mayOnNode as v}from"../router.js";import{ApiError as l}from"../../../api/errors.js";const m=128*1024*1024,s=r(()=>b(),"store"),o=r(e=>e.body,"input");function d(){throw new l(404,"not_found","conversation not found")}r(d,"notFound");async function p(e,a,n=!1){const t=await N(a);if(!t)return d();if(e.principal.class==="broker"){if(t!==e.principal.node)return d()}else if(n||e.principal.class!=="person"||!await v(e.principal,"read",t))return d();return t}r(p,"authorize");const O=r(async(e,a)=>{await p(e,a);const n=e.query.get("head"),t=e.query.get("tail");if(n!==null||t!==null){if(n===null||t===null||!/^\d+$/.test(n)||!/^\d+$/.test(t)||Number(n)>m||Number(t)>m)throw new l(400,"invalid_request","head and tail must be byte counts");const i=await s().read(a,{head:Number(n),tail:Number(t)});return e.res.writeHead(200,{"content-type":"application/x-ndjson","x-conversation-path":i.path,...i.tail?{"x-conversation-tail":String(i.entries.length+1)}:{}}),e.res.end([i.header,...i.entries,...i.tail??[]].map(f=>JSON.stringify(f)+`
2
+ `).join("")),{status:200}}const c=await s().readLines?.(a);if(!c)throw new Error("conversation store does not support streaming reads");e.res.writeHead(200,{"content-type":"application/x-ndjson","x-conversation-path":c.path});let u="";const w=r(()=>{const i=u;return u="",new Promise((f,y)=>e.res.write(i,h=>h?y(h):f()))},"flush");for await(const i of c.lines)u+=i+`
3
+ `,u.length>=256*1024&&await w();return u&&await w(),e.res.end(),{status:200}},"readResult"),k=[{method:"POST",pattern:"/v1/conversations",maxBodyBytes:m,handler:r(async e=>e.principal.class!=="broker"||o(e).node_id!==e.principal.node?d():{status:201,body:{conversation_id:await s().create(e.principal.node,o(e).header,o(e).entries)}},"handler")},{method:"GET",pattern:"/v1/conversations",handler:r(async e=>{if(e.principal.class==="broker"){const n=e.query.get("node_id");return n&&n!==e.principal.node?d():{status:200,body:{conversations:await s().list(e.principal.node)}}}if(e.principal.class!=="person")return d();const a=e.query.get("node_id");if(!a)throw new l(400,"invalid_request","node_id is required");return await v(e.principal,"read",a)?{status:200,body:{conversations:await s().list(a)}}:d()},"handler")},{method:"POST",pattern:"/v1/conversations/:id/entries",maxBodyBytes:m,handler:r(async e=>{await p(e,e.params.id,!0);const a=process.env.CRTR_FAULT_CONVERSATION??"";if(a.startsWith("append_refuse:")){const n=Number(a.slice(14));throw process.env.CRTR_FAULT_CONVERSATION=n>1?`append_refuse:${n-1}`:"",new l(503,"unavailable","conversation append refused (fault)")}return await s().append(e.params.id,o(e).entries),a==="append_drop_after_store"?(e.res.destroy(),{status:204}):{status:204}},"handler")},{method:"POST",pattern:"/v1/conversations/:id/commit",handler:r(async e=>{if(await p(e,e.params.id,!0),process.env.CRTR_FAULT_CONVERSATION==="commit_put_fail")throw new l(503,"unavailable","conversation commit refused (fault)");return{status:200,body:{seq:await T().commit(e.params.id)}}},"handler")},{method:"GET",pattern:"/v1/conversations/:id",handler:r(async e=>await O(e,e.params.id),"handler")},{method:"GET",pattern:"/v1/conversations/:id/header",handler:r(async e=>(await p(e,e.params.id),{status:200,body:await s().header(e.params.id)}),"handler")},{method:"PUT",pattern:"/v1/conversations/:id",maxBodyBytes:m,handler:r(async e=>(await p(e,e.params.id,!0),await s().replace(e.params.id,o(e).header,o(e).entries),{status:204}),"handler")},{method:"POST",pattern:"/v1/conversations/:id/fork",handler:r(async e=>{const a=await p(e,e.params.id,!0);return o(e).node_id!==a?d():{status:201,body:{conversation_id:await s().fork(e.params.id,a,o(e).leaf_id,o(e).cwd)}}},"handler")},{method:"DELETE",pattern:"/v1/conversations/:id",handler:r(async e=>(await p(e,e.params.id,!0),await s().delete(e.params.id),{status:204}),"handler")}];export{k as conversationRoutes};