@north-light/crouter 0.3.349 → 0.3.350

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 (629) hide show
  1. package/bin/crtr-launcher +4 -0
  2. package/bin/runtime-generation-manifest.mjs +12 -2
  3. package/dist/api/client.d.ts +50 -7
  4. package/dist/api/client.js +2 -2
  5. package/dist/api/dto/analytics.d.ts +184 -0
  6. package/dist/api/dto/analytics.js +0 -0
  7. package/dist/api/dto/broker-ops.d.ts +43 -1
  8. package/dist/api/dto/config.d.ts +11 -0
  9. package/dist/api/dto/grants.d.ts +14 -0
  10. package/dist/api/dto/grants.js +0 -0
  11. package/dist/api/dto/human-requests.d.ts +14 -0
  12. package/dist/api/dto/memory.d.ts +6 -0
  13. package/dist/api/dto/modelauth.d.ts +35 -0
  14. package/dist/api/dto/node-records.d.ts +35 -0
  15. package/dist/api/dto/node-records.js +0 -0
  16. package/dist/api/dto/nodes.d.ts +5 -0
  17. package/dist/api/dto/profiles.d.ts +38 -3
  18. package/dist/api/dto/worktree.d.ts +11 -0
  19. package/dist/api/errors.d.ts +23 -1
  20. package/dist/api/errors.js +1 -1
  21. package/dist/api/index.d.ts +2 -0
  22. package/dist/api/index.js +1 -1
  23. package/dist/api/node-transport.js +1 -1
  24. package/dist/api/routes.d.ts +22 -0
  25. package/dist/api/routes.js +1 -1
  26. package/dist/build-root.d.ts +6 -1
  27. package/dist/build-root.js +1 -1
  28. package/dist/builtin-memory/crouter-sdk/client.md +34 -0
  29. package/dist/builtin-memory/crouter-sdk/errors.md +2 -0
  30. package/dist/builtin-memory/crouter-sdk/memory.md +2 -2
  31. package/dist/builtin-memory/crouter-sdk/streaming.md +21 -0
  32. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/claude-plugin-commands.ts +8 -4
  33. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +39 -118
  34. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.d.ts +6 -1
  35. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.js +41 -27
  36. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/provider-rotation.ts +52 -29
  37. package/dist/cli.js +9 -8
  38. package/dist/clients/attach/chrome/inbox-strip.js +1 -1
  39. package/dist/clients/attach/chrome/roster.js +1 -1
  40. package/dist/clients/attach/config.js +1 -1
  41. package/dist/clients/attach/overlays/auth.js +2 -2
  42. package/dist/clients/attach/overlays/graph.js +1 -1
  43. package/dist/clients/attach/render/tool-calls.js +3 -3
  44. package/dist/clients/attach/session/connection.js +1 -1
  45. package/dist/clients/attach/session/profile-files.js +1 -1
  46. package/dist/clients/attach/viewer.js +1569 -816
  47. package/dist/commands/api-client.js +3 -3
  48. package/dist/commands/broker-permissions.d.ts +2 -0
  49. package/dist/commands/broker-permissions.js +1 -0
  50. package/dist/commands/canvas-analytics/chart.d.ts +52 -0
  51. package/dist/commands/canvas-analytics/chart.js +1 -0
  52. package/dist/commands/canvas-analytics/drilldown.d.ts +34 -0
  53. package/dist/commands/canvas-analytics/drilldown.js +1 -0
  54. package/dist/commands/canvas-analytics/format.d.ts +29 -0
  55. package/dist/commands/canvas-analytics/format.js +1 -0
  56. package/dist/commands/canvas-analytics/graph-detail.d.ts +2 -0
  57. package/dist/commands/canvas-analytics/graph-detail.js +2 -0
  58. package/dist/commands/canvas-analytics/graphs.d.ts +9 -0
  59. package/dist/commands/canvas-analytics/graphs.js +1 -0
  60. package/dist/commands/canvas-analytics/memory.d.ts +2 -0
  61. package/dist/commands/canvas-analytics/memory.js +1 -0
  62. package/dist/commands/canvas-analytics/overview.d.ts +2 -0
  63. package/dist/commands/canvas-analytics/overview.js +1 -0
  64. package/dist/commands/canvas-analytics/shell.d.ts +60 -0
  65. package/dist/commands/canvas-analytics/shell.js +2 -0
  66. package/dist/commands/canvas-analytics/time.d.ts +2 -0
  67. package/dist/commands/canvas-analytics/time.js +1 -0
  68. package/dist/commands/canvas-analytics/usage.d.ts +2 -0
  69. package/dist/commands/canvas-analytics/usage.js +1 -0
  70. package/dist/commands/canvas-analytics/view.d.ts +85 -0
  71. package/dist/commands/canvas-analytics/view.js +1 -0
  72. package/dist/commands/canvas-analytics.d.ts +2 -0
  73. package/dist/commands/canvas-analytics.js +1 -0
  74. package/dist/commands/canvas-prune.js +1 -1
  75. package/dist/commands/canvas.js +1 -1
  76. package/dist/commands/cron.js +5 -5
  77. package/dist/commands/human/components.d.ts +2 -0
  78. package/dist/commands/human/components.js +2 -2
  79. package/dist/commands/human/prompts.js +1 -1
  80. package/dist/commands/human/queue.js +1 -1
  81. package/dist/commands/memory/client.d.ts +11 -0
  82. package/dist/commands/memory/client.js +1 -0
  83. package/dist/commands/memory/delete.js +1 -1
  84. package/dist/commands/memory/edit.js +3 -3
  85. package/dist/commands/memory/find.js +1 -1
  86. package/dist/commands/memory/history.js +4 -4
  87. package/dist/commands/memory/lint.js +1 -1
  88. package/dist/commands/memory/list.d.ts +0 -2
  89. package/dist/commands/memory/list.js +1 -1
  90. package/dist/commands/memory/move.js +1 -1
  91. package/dist/commands/memory/origin.js +1 -1
  92. package/dist/commands/memory/read.d.ts +0 -5
  93. package/dist/commands/memory/read.js +3 -3
  94. package/dist/commands/memory/shared.d.ts +0 -178
  95. package/dist/commands/memory/shared.js +1 -12
  96. package/dist/commands/memory/write.js +5 -5
  97. package/dist/commands/node/bash.js +5 -5
  98. package/dist/commands/node/create.d.ts +0 -17
  99. package/dist/commands/node/create.js +2 -3
  100. package/dist/commands/node/inspect.js +6 -6
  101. package/dist/commands/node/lifecycle.js +2 -2
  102. package/dist/commands/node-context.js +2 -2
  103. package/dist/commands/node-inspect-artifacts.js +6 -6
  104. package/dist/commands/pkg/browse/catalog.js +1 -1
  105. package/dist/commands/pkg/browse/model.d.ts +1 -1
  106. package/dist/commands/pkg/market-manage.js +1 -1
  107. package/dist/commands/pkg/plugin-manage.js +10 -10
  108. package/dist/commands/profile/daemon-profiles.d.ts +13 -0
  109. package/dist/commands/profile/daemon-profiles.js +4 -0
  110. package/dist/commands/profile/delete.js +1 -1
  111. package/dist/commands/profile/env.d.ts +6 -0
  112. package/dist/commands/profile/env.js +2 -2
  113. package/dist/commands/profile/kind.js +1 -2
  114. package/dist/commands/profile/list.js +1 -1
  115. package/dist/commands/profile/meta.js +1 -1
  116. package/dist/commands/profile/new.js +1 -1
  117. package/dist/commands/profile/pause.js +1 -1
  118. package/dist/commands/profile/project.js +1 -1
  119. package/dist/commands/profile/rename.js +1 -1
  120. package/dist/commands/profile/show.js +1 -1
  121. package/dist/commands/profile.js +1 -1
  122. package/dist/commands/push.js +3 -3
  123. package/dist/commands/surface-inspect.js +1 -1
  124. package/dist/commands/sys/branch.js +1 -1
  125. package/dist/commands/sys/config.js +1 -1
  126. package/dist/commands/sys/connect.js +3 -3
  127. package/dist/commands/sys/context/admin/actions.js +1 -1
  128. package/dist/commands/sys/context/admin/model.d.ts +1 -0
  129. package/dist/commands/sys/context/admin/model.js +1 -1
  130. package/dist/commands/sys/context/admin.js +1 -1
  131. package/dist/commands/sys/context/expose.js +2 -1
  132. package/dist/commands/sys/context/prompt-review.js +2 -2
  133. package/dist/commands/sys/context/resolve.js +7 -7
  134. package/dist/commands/sys/context/sysprompt.js +1 -1
  135. package/dist/commands/sys/join.d.ts +1 -0
  136. package/dist/commands/sys/join.js +1 -0
  137. package/dist/commands/sys/migrate.js +1 -1
  138. package/dist/commands/sys/panels/models-panel.js +1 -1
  139. package/dist/commands/sys/panels/profiles-panel.d.ts +0 -1
  140. package/dist/commands/sys/panels/profiles-panel.js +1 -1
  141. package/dist/commands/sys/provider-login.js +6 -6
  142. package/dist/commands/sys/setup-core.d.ts +1 -1
  143. package/dist/commands/sys/setup-core.js +6 -6
  144. package/dist/commands/sys/setup-settings-runner.js +1 -1
  145. package/dist/commands/sys/setup.js +1 -1
  146. package/dist/commands/sys/spaces.d.ts +1 -0
  147. package/dist/commands/sys/spaces.js +2 -0
  148. package/dist/commands/sys/sync-deps.js +2 -2
  149. package/dist/commands/sys/sync-project-guidance.js +4 -4
  150. package/dist/commands/sys/sync-skills.js +2 -2
  151. package/dist/commands/sys/worktrees.d.ts +1 -0
  152. package/dist/commands/sys/worktrees.js +1 -1
  153. package/dist/commands/sys.js +1 -1
  154. package/dist/core/auth-file.js +2 -2
  155. package/dist/core/bash-job-supervisor.d.ts +6 -0
  156. package/dist/core/bash-job-supervisor.js +4 -0
  157. package/dist/core/bash-jobs.d.ts +13 -6
  158. package/dist/core/bash-jobs.js +8 -7
  159. package/dist/core/broker-client/transport-relay.d.ts +6 -3
  160. package/dist/core/broker-client/transport-relay.js +1 -1
  161. package/dist/core/broker-client/transport-socket.d.ts +6 -1
  162. package/dist/core/broker-client/transport-socket.js +1 -1
  163. package/dist/core/canvas/canvas.d.ts +39 -18
  164. package/dist/core/canvas/canvas.js +21 -20
  165. package/dist/core/canvas/context-strip.d.ts +20 -0
  166. package/dist/core/canvas/context-strip.js +5 -0
  167. package/dist/core/canvas/crons.d.ts +12 -20
  168. package/dist/core/canvas/crons.js +15 -13
  169. package/dist/core/canvas/db.js +2 -2
  170. package/dist/core/canvas/deliveries.d.ts +4 -1
  171. package/dist/core/canvas/deliveries.js +1 -1
  172. package/dist/core/canvas/executions.js +1 -1
  173. package/dist/core/canvas/history.d.ts +2 -1
  174. package/dist/core/canvas/history.js +17 -18
  175. package/dist/core/canvas/memory-reads.d.ts +19 -0
  176. package/dist/core/canvas/memory-reads.js +1 -0
  177. package/dist/core/canvas/migrations.d.ts +0 -4
  178. package/dist/core/canvas/migrations.js +99 -32
  179. package/dist/core/canvas/nav-render.js +1 -1
  180. package/dist/core/canvas/node-agent-paths.d.ts +8 -0
  181. package/dist/core/canvas/node-agent-paths.js +1 -0
  182. package/dist/core/canvas/node-recap.d.ts +2 -2
  183. package/dist/core/canvas/node-recap.js +2 -2
  184. package/dist/core/canvas/node-tokens.d.ts +24 -0
  185. package/dist/core/canvas/node-tokens.js +5 -0
  186. package/dist/core/canvas/paths.d.ts +16 -19
  187. package/dist/core/canvas/paths.js +1 -1
  188. package/dist/core/canvas/render-source.d.ts +2 -2
  189. package/dist/core/canvas/render-source.js +6 -9
  190. package/dist/core/canvas/sessions.d.ts +18 -0
  191. package/dist/core/canvas/sessions.js +4 -1
  192. package/dist/core/canvas/types.d.ts +22 -6
  193. package/dist/core/command-hooks/compose.js +1 -1
  194. package/dist/core/command-hooks/discovery.d.ts +15 -1
  195. package/dist/core/command-hooks/discovery.js +1 -1
  196. package/dist/core/command-hooks/help.d.ts +2 -2
  197. package/dist/core/command-hooks/lifecycle-create.d.ts +1 -1
  198. package/dist/core/command-hooks/lifecycle-create.js +1 -1
  199. package/dist/core/command-hooks/transport/exec-invoke.d.ts +2 -0
  200. package/dist/core/command-hooks/transport/exec-invoke.js +1 -1
  201. package/dist/core/command-hooks/transport/exec-lifecycle.d.ts +1 -0
  202. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  203. package/dist/core/command-hooks/transport/plan.d.ts +3 -0
  204. package/dist/core/command-hooks/transport/plan.js +1 -0
  205. package/dist/core/command-plugins/discovery.js +1 -1
  206. package/dist/core/command.d.ts +6 -2
  207. package/dist/core/command.js +6 -6
  208. package/dist/core/config.d.ts +8 -5
  209. package/dist/core/config.js +1 -1
  210. package/dist/core/conversation-store/client-worker.d.ts +1 -0
  211. package/dist/core/conversation-store/client-worker.js +1 -0
  212. package/dist/core/conversation-store/client.d.ts +2 -0
  213. package/dist/core/conversation-store/client.js +2 -0
  214. package/dist/core/conversation-store/file-store.d.ts +37 -0
  215. package/dist/core/conversation-store/file-store.js +9 -0
  216. package/dist/core/conversation-store/index.d.ts +50 -0
  217. package/dist/core/conversation-store/index.js +1 -0
  218. package/dist/core/conversation-store/listener.d.ts +4 -0
  219. package/dist/core/conversation-store/listener.js +3 -0
  220. package/dist/core/conversation-store/patch.d.ts +1 -0
  221. package/dist/core/conversation-store/patch.js +1 -0
  222. package/dist/core/directory/join.d.ts +27 -0
  223. package/dist/core/directory/join.js +1 -0
  224. package/dist/core/disk-usage.d.ts +4 -0
  225. package/dist/core/disk-usage.js +1 -0
  226. package/dist/core/events/emit.d.ts +2 -0
  227. package/dist/core/events/emit.js +3 -1
  228. package/dist/core/feed/feed.js +4 -4
  229. package/dist/core/feed/messages.d.ts +3 -0
  230. package/dist/core/feed/messages.js +6 -6
  231. package/dist/core/fs-utils.d.ts +2 -0
  232. package/dist/core/fs-utils.js +3 -3
  233. package/dist/core/grants/local.d.ts +4 -0
  234. package/dist/core/grants/local.js +1 -0
  235. package/dist/core/grants/mirror.d.ts +44 -0
  236. package/dist/core/grants/mirror.js +4 -0
  237. package/dist/core/grants/on-sync.d.ts +22 -0
  238. package/dist/core/grants/on-sync.js +1 -0
  239. package/dist/core/grants/remove.d.ts +7 -0
  240. package/dist/core/grants/remove.js +1 -0
  241. package/dist/core/grants/sandboxes.d.ts +7 -0
  242. package/dist/core/grants/sandboxes.js +1 -0
  243. package/dist/core/grants/sync.d.ts +12 -0
  244. package/dist/core/grants/sync.js +1 -0
  245. package/dist/core/help/memory-extensions.d.ts +3 -0
  246. package/dist/core/help/memory-extensions.js +2 -0
  247. package/dist/core/help.d.ts +14 -0
  248. package/dist/core/help.js +7 -7
  249. package/dist/core/host-exports/builtins.js +3 -3
  250. package/dist/core/host-exports/export.js +3 -3
  251. package/dist/core/human/action-binding.d.ts +2 -0
  252. package/dist/core/human/action-binding.js +1 -1
  253. package/dist/core/human/feedback-companion.d.ts +0 -1
  254. package/dist/core/human/feedback-companion.js +1 -1
  255. package/dist/core/human/page-schema.d.ts +1 -1
  256. package/dist/core/inspector/core.d.ts +2 -0
  257. package/dist/core/inspector/core.js +1 -1
  258. package/dist/core/inspector/tui.js +2 -2
  259. package/dist/core/installed-plugins.js +1 -1
  260. package/dist/core/io.js +6 -6
  261. package/dist/core/keybindings/catalog.d.ts +1 -1
  262. package/dist/core/keybindings/catalog.js +1 -1
  263. package/dist/core/layout-migrate/index.d.ts +15 -0
  264. package/dist/core/layout-migrate/index.js +4 -0
  265. package/dist/core/layout-migrate/paths.d.ts +26 -0
  266. package/dist/core/layout-migrate/paths.js +1 -0
  267. package/dist/core/layout-migrate/stored-paths.d.ts +2 -0
  268. package/dist/core/layout-migrate/stored-paths.js +11 -0
  269. package/dist/core/layout-migrate/stores.d.ts +17 -0
  270. package/dist/core/layout-migrate/stores.js +4 -0
  271. package/dist/core/layout.d.ts +26 -0
  272. package/dist/core/layout.js +2 -0
  273. package/dist/core/llm/run.d.ts +60 -0
  274. package/dist/core/llm/run.js +4 -0
  275. package/dist/core/memory/cli-selector.d.ts +13 -0
  276. package/dist/core/memory/cli-selector.js +1 -0
  277. package/dist/core/memory/history.d.ts +5 -4
  278. package/dist/core/memory/history.js +6 -6
  279. package/dist/core/memory/inline-ref-inventory.d.ts +2 -1
  280. package/dist/core/memory/inline-ref-inventory.js +1 -1
  281. package/dist/core/memory/lint.js +2 -2
  282. package/dist/core/memory/mutation-domain.d.ts +2 -2
  283. package/dist/core/memory/mutation-domain.js +8 -7
  284. package/dist/core/memory/mutations.js +1 -1
  285. package/dist/core/memory/service.d.ts +5 -0
  286. package/dist/core/memory/service.js +2 -2
  287. package/dist/core/memory-resolver.d.ts +11 -7
  288. package/dist/core/memory-resolver.js +2 -2
  289. package/dist/core/model-auth/daemon-login.d.ts +13 -0
  290. package/dist/core/model-auth/daemon-login.js +1 -0
  291. package/dist/core/model-auth/flows.d.ts +45 -0
  292. package/dist/core/model-auth/flows.js +1 -0
  293. package/dist/core/model-auth/handoff-jti.d.ts +4 -0
  294. package/dist/core/model-auth/handoff-jti.js +1 -0
  295. package/dist/core/model-routes.js +1 -1
  296. package/dist/core/nested-stores.d.ts +2 -1
  297. package/dist/core/nested-stores.js +1 -2
  298. package/dist/core/preview-registry.js +2 -2
  299. package/dist/core/profiles/env-store.js +2 -2
  300. package/dist/core/profiles/manifest.d.ts +16 -5
  301. package/dist/core/profiles/manifest.js +1 -1
  302. package/dist/core/provider-management.js +1 -1
  303. package/dist/core/review/birth.js +1 -1
  304. package/dist/core/review/companion.d.ts +0 -2
  305. package/dist/core/review/companion.js +1 -1
  306. package/dist/core/review/fork.js +2 -2
  307. package/dist/core/review/realize.js +1 -1
  308. package/dist/core/review/stage.d.ts +1 -1
  309. package/dist/core/review/stage.js +1 -1
  310. package/dist/core/review/types.d.ts +1 -1
  311. package/dist/core/runs/events.d.ts +34 -0
  312. package/dist/core/runs/events.js +1 -0
  313. package/dist/core/runs/operations.d.ts +43 -0
  314. package/dist/core/runs/operations.js +12 -0
  315. package/dist/core/runtime/bearings-render.d.ts +2 -2
  316. package/dist/core/runtime/bearings-render.js +11 -11
  317. package/dist/core/runtime/bearings.js +2 -2
  318. package/dist/core/runtime/broker/cli-relay.d.ts +5 -0
  319. package/dist/core/runtime/broker/cli-relay.js +1 -0
  320. package/dist/core/runtime/broker/client-registry.d.ts +0 -5
  321. package/dist/core/runtime/broker/client-registry.js +1 -1
  322. package/dist/core/runtime/broker/daemon-ops.d.ts +28 -1
  323. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  324. package/dist/core/runtime/broker/engine-drive.d.ts +0 -2
  325. package/dist/core/runtime/broker/engine-drive.js +1 -1
  326. package/dist/core/runtime/broker/fault-retry.d.ts +9 -0
  327. package/dist/core/runtime/broker/fault-retry.js +1 -1
  328. package/dist/core/runtime/broker/frame-dispatch.d.ts +5 -9
  329. package/dist/core/runtime/broker/frame-dispatch.js +1 -1
  330. package/dist/core/runtime/broker/frame-engine-control.d.ts +3 -2
  331. package/dist/core/runtime/broker/frame-engine-control.js +1 -1
  332. package/dist/core/runtime/broker/frame-memory-refs.d.ts +4 -3
  333. package/dist/core/runtime/broker/frame-memory-refs.js +1 -1
  334. package/dist/core/runtime/broker/frame-read.js +1 -1
  335. package/dist/core/runtime/broker/frame-session.js +1 -1
  336. package/dist/core/runtime/broker/held-deferred-inbox.d.ts +3 -1
  337. package/dist/core/runtime/broker/held-deferred-inbox.js +1 -1
  338. package/dist/core/runtime/broker/inbox.d.ts +1 -2
  339. package/dist/core/runtime/broker/inbox.js +7 -10
  340. package/dist/core/runtime/broker/model-adapter.d.ts +9 -0
  341. package/dist/core/runtime/broker/model-adapter.js +2 -0
  342. package/dist/core/runtime/broker/node-token.d.ts +3 -0
  343. package/dist/core/runtime/broker/node-token.js +1 -0
  344. package/dist/core/runtime/broker/read-ops.js +1 -1
  345. package/dist/core/runtime/broker/rebind.d.ts +2 -0
  346. package/dist/core/runtime/broker/rebind.js +1 -1
  347. package/dist/core/runtime/broker/tool-groups.js +1 -1
  348. package/dist/core/runtime/broker/turn-ignition.d.ts +3 -3
  349. package/dist/core/runtime/broker/turn-ignition.js +1 -1
  350. package/dist/core/runtime/broker-cli.js +3 -3
  351. package/dist/core/runtime/broker-extension-render.d.ts +2 -5
  352. package/dist/core/runtime/broker-extension-render.js +4 -4
  353. package/dist/core/runtime/broker-persona-guidance.js +3 -3
  354. package/dist/core/runtime/broker-protocol.d.ts +7 -8
  355. package/dist/core/runtime/broker.js +1 -1
  356. package/dist/core/runtime/canvas-extensions.d.ts +1 -0
  357. package/dist/core/runtime/canvas-extensions.js +1 -1
  358. package/dist/core/runtime/close.d.ts +9 -0
  359. package/dist/core/runtime/close.js +1 -1
  360. package/dist/core/runtime/deliver-live.js +1 -1
  361. package/dist/core/runtime/fleet.d.ts +1 -1
  362. package/dist/core/runtime/front-door-login.js +1 -1
  363. package/dist/core/runtime/front-door.js +2 -2
  364. package/dist/core/runtime/headless-pi.d.ts +1 -1
  365. package/dist/core/runtime/headless-pi.js +1 -1
  366. package/dist/core/runtime/host.d.ts +1 -1
  367. package/dist/core/runtime/host.js +3 -1
  368. package/dist/core/runtime/invocation.d.ts +3 -0
  369. package/dist/core/runtime/kickoff.d.ts +1 -0
  370. package/dist/core/runtime/kickoff.js +16 -16
  371. package/dist/core/runtime/launch-target.d.ts +1 -1
  372. package/dist/core/runtime/launch-target.js +1 -1
  373. package/dist/core/runtime/launch.d.ts +10 -35
  374. package/dist/core/runtime/launch.js +1 -1
  375. package/dist/core/runtime/lifecycle.js +2 -2
  376. package/dist/core/runtime/memory.d.ts +1 -1
  377. package/dist/core/runtime/memory.js +1 -1
  378. package/dist/core/runtime/model-registry.js +1 -1
  379. package/dist/core/runtime/model-swap.d.ts +17 -19
  380. package/dist/core/runtime/model-swap.js +1 -1
  381. package/dist/core/runtime/node-read.js +3 -2
  382. package/dist/core/runtime/nodes.d.ts +7 -0
  383. package/dist/core/runtime/nodes.js +1 -1
  384. package/dist/core/runtime/outcome-document.js +1 -1
  385. package/dist/core/runtime/package-health.js +2 -2
  386. package/dist/core/runtime/persona.js +2 -2
  387. package/dist/core/runtime/pi-vendored.js +1 -1
  388. package/dist/core/runtime/placement-tmux.d.ts +1 -1
  389. package/dist/core/runtime/placement-tmux.js +1 -1
  390. package/dist/core/runtime/placement.js +1 -1
  391. package/dist/core/runtime/promote.js +1 -1
  392. package/dist/core/runtime/provider-credential-gate.js +2 -2
  393. package/dist/core/runtime/recovery-hold.d.ts +2 -0
  394. package/dist/core/runtime/recovery-hold.js +1 -0
  395. package/dist/core/runtime/recycle.js +1 -1
  396. package/dist/core/runtime/reopen.js +1 -1
  397. package/dist/core/runtime/reset.js +1 -1
  398. package/dist/core/runtime/revive.d.ts +1 -1
  399. package/dist/core/runtime/revive.js +2 -3
  400. package/dist/core/runtime/roadmap.js +4 -4
  401. package/dist/core/runtime/run-command.d.ts +6 -0
  402. package/dist/core/runtime/run-command.js +1 -1
  403. package/dist/core/runtime/session-branch.d.ts +2 -8
  404. package/dist/core/runtime/session-branch.js +1 -1
  405. package/dist/core/runtime/session-list-cache.d.ts +6 -22
  406. package/dist/core/runtime/session-list-cache.js +1 -1
  407. package/dist/core/runtime/situational-context.js +2 -2
  408. package/dist/core/runtime/spawn-env.d.ts +6 -6
  409. package/dist/core/runtime/spawn-env.js +1 -1
  410. package/dist/core/runtime/spawn.d.ts +5 -0
  411. package/dist/core/runtime/spawn.js +2 -2
  412. package/dist/core/runtime/stop-guard.js +2 -2
  413. package/dist/core/runtime/stop-signals.d.ts +2 -2
  414. package/dist/core/runtime/stop-signals.js +1 -1
  415. package/dist/core/runtime/structured-output.d.ts +10 -4
  416. package/dist/core/runtime/structured-output.js +4 -4
  417. package/dist/core/runtime/tmux-bindings.js +3 -3
  418. package/dist/core/runtime/tmux-driver.d.ts +4 -0
  419. package/dist/core/runtime/tmux-driver.js +7 -7
  420. package/dist/core/runtime/view-socket.d.ts +9 -2
  421. package/dist/core/runtime/view-socket.js +1 -1
  422. package/dist/core/runtime/warm-pool.js +1 -1
  423. package/dist/core/scope.d.ts +3 -2
  424. package/dist/core/scope.js +1 -1
  425. package/dist/core/scoped-state/db.js +1 -1
  426. package/dist/core/scoped-state/migrate.js +3 -3
  427. package/dist/core/scoped-state/profiles.d.ts +2 -1
  428. package/dist/core/scoped-state/profiles.js +1 -1
  429. package/dist/core/scoped-state/schema.d.ts +2 -1
  430. package/dist/core/scoped-state/schema.js +4 -4
  431. package/dist/core/scopes.d.ts +2 -2
  432. package/dist/core/scopes.js +1 -1
  433. package/dist/core/secrets.d.ts +1 -0
  434. package/dist/core/secrets.js +2 -2
  435. package/dist/core/spaces/mounts.d.ts +32 -0
  436. package/dist/core/spaces/mounts.js +1 -0
  437. package/dist/core/spaces/open-beneath.d.ts +71 -0
  438. package/dist/core/spaces/open-beneath.js +1 -0
  439. package/dist/core/spaces/permissions.d.ts +46 -0
  440. package/dist/core/spaces/permissions.js +1 -0
  441. package/dist/core/spaces/process.d.ts +27 -0
  442. package/dist/core/spaces/process.js +1 -0
  443. package/dist/core/spaces/space.d.ts +8 -0
  444. package/dist/core/spaces/space.js +2 -0
  445. package/dist/core/spaces/stop.d.ts +8 -0
  446. package/dist/core/spaces/stop.js +2 -0
  447. package/dist/core/spaces/users.d.ts +19 -0
  448. package/dist/core/spaces/users.js +1 -0
  449. package/dist/core/subscription-state.d.ts +2 -0
  450. package/dist/core/subscription-state.js +3 -3
  451. package/dist/core/substrate/frontmatter-validation.js +1 -1
  452. package/dist/core/substrate/injected-store.d.ts +28 -3
  453. package/dist/core/substrate/injected-store.js +2 -1
  454. package/dist/core/substrate/listings.js +1 -1
  455. package/dist/core/substrate/memory-events.d.ts +6 -0
  456. package/dist/core/substrate/memory-events.js +1 -0
  457. package/dist/core/substrate/on-read-node.js +1 -1
  458. package/dist/core/substrate/on-read.d.ts +6 -6
  459. package/dist/core/substrate/on-read.js +5 -5
  460. package/dist/core/substrate/plan.js +1 -1
  461. package/dist/core/substrate/render-node.js +1 -1
  462. package/dist/core/substrate/render.d.ts +4 -3
  463. package/dist/core/substrate/render.js +38 -38
  464. package/dist/core/substrate/schema.d.ts +6 -0
  465. package/dist/core/substrate/schema.js +1 -1
  466. package/dist/core/tui/panel.js +1 -1
  467. package/dist/core/user-settings.d.ts +12 -0
  468. package/dist/core/user-settings.js +1 -1
  469. package/dist/core/worktree-mutation-async.js +5 -5
  470. package/dist/core/worktree-quarantine.js +1 -1
  471. package/dist/core/worktree-remove.d.ts +15 -0
  472. package/dist/core/worktree-remove.js +1 -0
  473. package/dist/core/worktree-sweep.js +6 -6
  474. package/dist/daemon/analytics/compute.d.ts +37 -0
  475. package/dist/daemon/analytics/compute.js +1 -0
  476. package/dist/daemon/analytics/scan-worker.d.ts +1 -0
  477. package/dist/daemon/analytics/scan-worker.js +2 -0
  478. package/dist/daemon/analytics/scan.d.ts +37 -0
  479. package/dist/daemon/analytics/scan.js +1 -0
  480. package/dist/daemon/api/app-listener.d.ts +11 -0
  481. package/dist/daemon/api/app-listener.js +21 -0
  482. package/dist/daemon/api/bridge.js +5 -5
  483. package/dist/daemon/api/handlers/analytics.d.ts +2 -0
  484. package/dist/daemon/api/handlers/analytics.js +1 -0
  485. package/dist/daemon/api/handlers/attach.js +1 -1
  486. package/dist/daemon/api/handlers/bash-jobs.js +2 -2
  487. package/dist/daemon/api/handlers/bash.js +1 -1
  488. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  489. package/dist/daemon/api/handlers/canvas.d.ts +1 -1
  490. package/dist/daemon/api/handlers/canvas.js +6 -6
  491. package/dist/daemon/api/handlers/crons.js +1 -1
  492. package/dist/daemon/api/handlers/files.d.ts +1 -1
  493. package/dist/daemon/api/handlers/files.js +1 -1
  494. package/dist/daemon/api/handlers/health.js +2 -2
  495. package/dist/daemon/api/handlers/hook-exec.d.ts +2 -0
  496. package/dist/daemon/api/handlers/hook-exec.js +1 -0
  497. package/dist/daemon/api/handlers/human-requests.js +1 -1
  498. package/dist/daemon/api/handlers/inbox.js +1 -1
  499. package/dist/daemon/api/handlers/llm.d.ts +2 -0
  500. package/dist/daemon/api/handlers/llm.js +3 -0
  501. package/dist/daemon/api/handlers/memory-reads.d.ts +4 -0
  502. package/dist/daemon/api/handlers/memory-reads.js +1 -0
  503. package/dist/daemon/api/handlers/memory.js +5 -1
  504. package/dist/daemon/api/handlers/messages.js +2 -2
  505. package/dist/daemon/api/handlers/modelauth.js +1 -1
  506. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  507. package/dist/daemon/api/handlers/node-records.d.ts +2 -0
  508. package/dist/daemon/api/handlers/node-records.js +3 -0
  509. package/dist/daemon/api/handlers/nodes.d.ts +1 -1
  510. package/dist/daemon/api/handlers/nodes.js +1 -1
  511. package/dist/daemon/api/handlers/profiles.d.ts +4 -1
  512. package/dist/daemon/api/handlers/profiles.js +1 -1
  513. package/dist/daemon/api/handlers/reports.js +5 -3
  514. package/dist/daemon/api/handlers/reviews.d.ts +1 -1
  515. package/dist/daemon/api/handlers/reviews.js +1 -1
  516. package/dist/daemon/api/handlers/run-routes.d.ts +2 -0
  517. package/dist/daemon/api/handlers/run-routes.js +1 -0
  518. package/dist/daemon/api/handlers/runs.d.ts +9 -0
  519. package/dist/daemon/api/handlers/runs.js +1 -0
  520. package/dist/daemon/api/handlers/subscriptions.js +1 -1
  521. package/dist/daemon/api/handlers/worktree.js +1 -1
  522. package/dist/daemon/api/map.d.ts +10 -4
  523. package/dist/daemon/api/map.js +2 -2
  524. package/dist/daemon/api/operations.d.ts +18 -0
  525. package/dist/daemon/api/operations.js +1 -0
  526. package/dist/daemon/api/principal.d.ts +42 -0
  527. package/dist/daemon/api/principal.js +1 -0
  528. package/dist/daemon/api/router.d.ts +27 -3
  529. package/dist/daemon/api/router.js +1 -1
  530. package/dist/daemon/api/server.d.ts +4 -0
  531. package/dist/daemon/api/server.js +1 -1
  532. package/dist/daemon/api/vendor-signin.d.ts +7 -0
  533. package/dist/daemon/api/vendor-signin.js +77 -0
  534. package/dist/daemon/api/viewer-presence.d.ts +3 -0
  535. package/dist/daemon/api/viewer-presence.js +1 -0
  536. package/dist/daemon/cron/armed-context.d.ts +4 -0
  537. package/dist/daemon/cron/armed-context.js +1 -1
  538. package/dist/daemon/cron/escalation.js +3 -3
  539. package/dist/daemon/cron/lease-recovery.js +1 -1
  540. package/dist/daemon/cron/sinks.js +2 -2
  541. package/dist/daemon/cron-run.d.ts +5 -5
  542. package/dist/daemon/cron-run.js +1 -1
  543. package/dist/daemon/crtrd.js +8 -7
  544. package/dist/daemon/delivery/run-delivery.d.ts +4 -0
  545. package/dist/daemon/delivery/run-delivery.js +1 -1
  546. package/dist/daemon/fleet.d.ts +1 -1
  547. package/dist/daemon/fleet.js +6 -6
  548. package/dist/daemon/human/finish.js +7 -7
  549. package/dist/daemon/joined-owner.d.ts +5 -0
  550. package/dist/daemon/joined-owner.js +1 -0
  551. package/dist/daemon/manage.js +2 -2
  552. package/dist/daemon/messaging/node-message.js +1 -1
  553. package/dist/daemon/park-activity.js +1 -1
  554. package/dist/daemon/reconcilers/bash-deadline.js +1 -1
  555. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  556. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  557. package/dist/daemon/reconcilers/delivery-lane.js +1 -1
  558. package/dist/daemon/reconcilers/live-obligation.d.ts +7 -0
  559. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  560. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  561. package/dist/daemon/reconcilers/storage-maintenance.d.ts +20 -1
  562. package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
  563. package/dist/daemon/runs/append-section.d.ts +6 -0
  564. package/dist/daemon/runs/append-section.js +2 -0
  565. package/dist/daemon/runs/observer.d.ts +5 -0
  566. package/dist/daemon/runs/observer.js +4 -0
  567. package/dist/launcher/bwrap.d.ts +4 -0
  568. package/dist/launcher/bwrap.js +2 -0
  569. package/dist/launcher/client.d.ts +2 -0
  570. package/dist/launcher/client.js +3 -0
  571. package/dist/launcher/main.d.ts +1 -0
  572. package/dist/launcher/main.js +3 -0
  573. package/dist/launcher/netrule.d.ts +1 -0
  574. package/dist/launcher/netrule.js +1 -0
  575. package/dist/launcher/seccomp.d.ts +1 -0
  576. package/dist/launcher/seccomp.js +1 -0
  577. package/dist/launcher/spec.d.ts +88 -0
  578. package/dist/launcher/spec.js +1 -0
  579. package/dist/launcher/users.d.ts +18 -0
  580. package/dist/launcher/users.js +7 -0
  581. package/dist/launcher/validate.d.ts +22 -0
  582. package/dist/launcher/validate.js +1 -0
  583. package/dist/migrations/corpus.js +3 -3
  584. package/dist/migrations/runner.js +1 -1
  585. package/dist/native/linux/addon.node +0 -0
  586. package/dist/native/linux.d.ts +29 -0
  587. package/dist/native/linux.js +1 -0
  588. package/dist/pi-extensions/broker-local.js +2 -2
  589. package/dist/pi-extensions/canvas-bash-valve.d.ts +1 -3
  590. package/dist/pi-extensions/canvas-bash-valve.js +4 -7
  591. package/dist/pi-extensions/canvas-context-intro.d.ts +1 -2
  592. package/dist/pi-extensions/canvas-context-intro.js +2 -2
  593. package/dist/pi-extensions/canvas-doc-substrate.js +6 -6
  594. package/dist/pi-extensions/canvas-inbox-watcher.d.ts +2 -1
  595. package/dist/pi-extensions/canvas-inbox-watcher.js +2 -1
  596. package/dist/pi-extensions/canvas-passive-context.d.ts +1 -1
  597. package/dist/pi-extensions/canvas-passive-context.js +11 -11
  598. package/dist/pi-extensions/canvas-recap.js +6 -6
  599. package/dist/pi-extensions/canvas-stophook.js +1 -1
  600. package/dist/pi-extensions/canvas-structured-output.js +4 -4
  601. package/dist/pi-extensions/canvas-tool-guide.js +1 -1
  602. package/dist/pi-extensions/system-prompt-entry.d.ts +15 -0
  603. package/dist/pi-extensions/system-prompt-entry.js +1 -0
  604. package/dist/shared/env.d.ts +5 -1
  605. package/dist/shared/env.js +1 -1
  606. package/dist/shared/strip-cd-prefix.d.ts +1 -0
  607. package/dist/shared/strip-cd-prefix.js +1 -0
  608. package/dist/types.d.ts +31 -15
  609. package/docs/cli/memory-and-preferences.md +3 -1
  610. package/docs/sdk/client.md +34 -0
  611. package/docs/sdk/errors.md +2 -0
  612. package/docs/sdk/memory.md +2 -2
  613. package/docs/sdk/streaming.md +21 -0
  614. package/package.json +18 -4
  615. package/packages/crouter-identity/dist/index.d.ts +54 -0
  616. package/packages/crouter-identity/dist/index.js +166 -0
  617. package/packages/crouter-identity/package.json +33 -0
  618. package/runtime.lock.json +34 -8
  619. package/scripts/build-native-linux.mjs +16 -0
  620. package/scripts/install-runtime.mjs +9 -7
  621. package/scripts/lib/isolation-env.mjs +42 -0
  622. package/scripts/runtime-smoke.mjs +49 -0
  623. package/src/native/linux/addon.c +249 -0
  624. package/dist/core/profiles/state-block.d.ts +0 -4
  625. package/dist/core/profiles/state-block.js +0 -3
  626. package/dist/core/runtime/broker/auth-reload.d.ts +0 -41
  627. package/dist/core/runtime/broker/auth-reload.js +0 -1
  628. package/dist/core/substrate/cli-context-delivery.d.ts +0 -22
  629. package/dist/core/substrate/cli-context-delivery.js +0 -1
@@ -1 +1 @@
1
- var F=Object.defineProperty;var r=(t,e)=>F(t,"name",{value:e,configurable:!0});import{canonicalSessionFile as A,findNodeBySessionFile as P,getNode as k,isWarmSpare as T,listNodeIdentities as I,recordSettledTurn as R,setPresence as w,subscriptionsOf as $,updateNode as g,updateNodeTelemetry as q}from"../../../core/canvas/canvas.js";import{recordExecutionPid as C}from"../../../core/canvas/executions.js";import{bindSession as j,readLiveSession as E,transferSession as M}from"../../../core/canvas/sessions.js";import{isSafeNodeId as D}from"../../../core/canvas/paths.js";import{isPidAlive as L}from"../../../core/canvas/pid.js";import{editorLabel as N}from"../../../core/canvas/labels.js";import{assembleNodeSubject as G}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 O}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as J}from"../../../core/runtime/kickoff.js";import{transition as h}from"../../../core/runtime/lifecycle.js";import{focusOf as b,tearDownNode as x}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as W}from"../../../core/runtime/broker/client-registry.js";import{evaluateStop as U}from"../../../core/runtime/stop-guard.js";import{clearFault as f,recordFault as V}from"../../../core/canvas/recovery.js";import{updateModelRecipe as Y}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as z}from"../../review/finish.js";import{emitEvent as H}from"../../../core/events/emit.js";import{consumePendingPark as K,recordPendingParkActivity as Q}from"../../park-pending.js";import{shouldParkAfterSummary as X}from"../../park-activity.js";import{ownerOnly as Z}from"../router.js";import{requireCurrentExecution as m}from"./broker-recovery.js";function p(t,e){if(typeof t!="object"||t===null||Array.isArray(t))throw s(`${e} requires a JSON body`);return t}r(p,"objectBody");function ee(t){const e=p(t,"broker session-bound");if(typeof e.executionId!="string"||e.executionId==="")throw s("executionId must be a non-empty string");if(typeof e.piSessionId!="string"||e.piSessionId==="")throw s("piSessionId must be a non-empty string");if(e.sessionFile!==null&&typeof e.sessionFile!="string")throw s("sessionFile must be a string or null");if(!Number.isSafeInteger(e.pid)||e.pid<=0)throw s("pid must be a positive safe integer");if(e.reason!==null&&typeof e.reason!="string")throw s("reason must be a string or null");if(!Array.isArray(e.reviewBoundaryIds)||!e.reviewBoundaryIds.every(n=>typeof n=="string"))throw s("reviewBoundaryIds must be an array of strings");return e}r(ee,"parseSessionBoundBody");function te(t){const e=p(t,"broker settle");if(typeof e.stopReason!="string")throw s("stopReason must be a string");for(const n of["backgroundJobsRunning","pushedFinal"])if(typeof e[n]!="boolean")throw s(`${n} must be a boolean`);return e}r(te,"parseSettleBody");function ne(t){const e=p(t,"broker park-complete");if(e.outcome!=="completed"&&e.outcome!=="failed")throw s("outcome must be completed or failed");return e}r(ne,"parseParkCompleteBody");function ie(t){const e=p(t,"broker telemetry");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw s("expected_execution_id must be a non-empty string");if(typeof e.tokens_in!="number"||!Number.isFinite(e.tokens_in)||e.tokens_in<0)throw s("tokens_in must be a non-negative finite number");if(e.context_tokens!==null&&(typeof e.context_tokens!="number"||!Number.isFinite(e.context_tokens)||e.context_tokens<0))throw s("context_tokens must be a non-negative finite number or null");if(e.last_activity!==null&&typeof e.last_activity!="string")throw s("last_activity must be a string or null");if(typeof e.updated_at!="string"||Number.isNaN(Date.parse(e.updated_at)))throw s("updated_at must be an ISO timestamp");return{...e,updated_at:new Date(e.updated_at).toISOString()}}r(ie,"parseTelemetryBody");function oe(t){const e=p(t,"broker model");if(typeof e.spec!="string"||e.spec.trim()==="")throw s("spec must be a non-empty string");if(e.pinnedOverride!==void 0&&typeof e.pinnedOverride!="boolean")throw s("pinnedOverride must be a boolean when present");if(typeof e.userSelected!="boolean")throw s("userSelected must be a boolean");return e}r(oe,"parseModelCommitBody");function _(t){const e=k(t);if(e===null)throw v(`unknown node: ${t}`,{received:t});return e}r(_,"requireNode");function y(t){return{node_id: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}}r(y,"extensionNode");function re(t){const e=_(t),n=[],o=new Set([t]);let i=e.parent??null;for(;i!==null&&i!==""&&!o.has(i);){o.add(i);const c=k(i);if(c===null)break;n.unshift(y(c)),i=c.parent??null}const a=$(t).map(c=>k(c.node_id)).filter(c=>c!==null&&c.kind!=="human").sort((c,S)=>c.status===S.status?0:c.status==="active"?-1:S.status==="active"?1:0).map(y),u=typeof e.fork_source_file=="string"?P(e.fork_source_file):null,d=G(t);if(d===null)throw v(`unknown node: ${t}`,{received:t});return{node:y(e),warm_spare:T(t),ancestors:n,children:a,fork_source:u===null?null:y(u),subject:d,report_nodes:I()}}r(re,"extensionState");function B(t,e){return t?.kind===e.kind&&t?.mode===e.mode&&t?.lifecycle===e.lifecycle}r(B,"samePersona");function se(t){const e=p(t,"broker generated-name");if(e.kind!=="initial"&&e.kind!=="recap")throw s("kind must be initial or recap");if(typeof e.description!="string"||typeof e.title!="string"||typeof e.icon!="string")throw s("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(o=>typeof n[o]!="string"))throw s("recap expected must contain name, description, title, icon, and kind strings");return e}r(se,"parseGeneratedNameBody");function ae(t){const e=p(t,"broker persona-ack"),n=r(o=>{const i=e[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:e.expected_execution_id,from:n("from"),to:n("to")}}r(ae,"parsePersonaAckBody");function de(t){const e=t.params.id,n=ee(t.body),o=n.sessionFile===null?null:A(n.sessionFile);return{status:200,body:l(()=>{const a=_(e);if(C(n.executionId,e,n.pid)==="shutdown")return{action:"shutdown"};const u=a.review_binding?.review_id;if(u!==void 0&&!n.reviewBoundaryIds.includes(u))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:P(o);if(d!==null&&d.node_id!==e){if(L(d.pi_pid))return V(e,{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 c=E(d.node_id);if(c===null||M({fromNodeId:d.node_id,fromBindingId:c.bindingId,toNodeId:e,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:o})!=="transferred")return{action:"shutdown"}}else if(j(e,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:o})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(J(e),a.intent==="refresh"&&h(e,"revive")),{action:"none"}})}}r(de,"handleSessionBound");function ue(t,e){const n=k(t);if(n===null){if(e.pushedFinal)return{action:"shutdown"};throw v(`unknown node: ${t}`,{received:t})}if(R(t,new Date().toISOString()),e.stopReason==="quit")return(n.status==="active"||n.status==="idle")&&n.intent===null&&(h(t,"finish"),f(t),b(t)!==null&&x(t),w(t,{pane:null,tmux_session:null,window:null})),{action:"shutdown"};if(e.stopReason!=="stop"&&e.stopReason!=="length")return f(t,{link:"daemon\u2192node"}),n.intent==="refresh"?{action:"shutdown"}:{action:"stay_dormant"};const o={pushedFinal:e.pushedFinal};if(o.pushedFinal||n.status==="done")return f(t),b(t)!==null&&x(t),w(t,{pane:null,tmux_session:null,window:null}),{action:"shutdown"};if(n.intent==="refresh")return f(t),{action:"shutdown"};const i=U(t,o,e.backgroundJobsRunning);return f(t),i.action==="reprompt"?{action:"reprompt",prompt:i.message}:i.reason==="finished"?O(t)?{action:"stay_dormant"}:{action:"shutdown"}:i.reason!=="awaiting"&&i.reason!=="scheduled"?{action:"stay_dormant"}:b(t)!==null||W(t)||O(t)?{action:"stay_dormant"}:(h(t,"release"),{action:"shutdown"})}r(ue,"settleBroker");function ce(t){const e=t.params.id,n=te(t.body);m(e,n.expected_execution_id);const o=l(()=>ue(e,n));return o.action!=="reprompt"&&z(e),{status:200,body:o}}r(ce,"handleSettle");function le(t){const e=t.params.id,n=ne(t.body);return m(e,n.expected_execution_id),{status:200,body:l(()=>{const i=K(e);if(i===void 0)return{action:"stay_dormant"};const a=_(e);return X(e,a,i)?(f(e),h(e,"park"),b(e)!==null&&x(e),w(e,{pane:null,tmux_session:null,window:null}),H({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...D(e)?{node_id:e}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}})}}r(le,"handleParkComplete");function pe(t){const e=t.params.id;return m(e,p(t.body,"broker park-activity").expected_execution_id),{status:200,body:l(()=>({activity:Q(e)?"recorded":"none"}))}}r(pe,"handleParkActivity");function me(t){const e=t.params.id,n=ie(t.body);return m(e,n.expected_execution_id),l(()=>{q(e,{tokensIn:n.tokens_in,contextTokens:n.context_tokens,lastActivity:n.last_activity,updatedAt:n.updated_at})}),{status:204}}r(me,"handleTelemetry");function fe(t){const e=t.params.id,n=oe(t.body);return m(e,n.expected_execution_id),{status:200,body:{modelOverride:l(()=>Y(_(e),n.spec,n.pinnedOverride,n.userSelected)).model_override}}}r(fe,"handleModelCommit");function _e(t){return{status:200,body:re(t.params.id)}}r(_e,"handleExtensionState");function ke(t){const e=t.params.id,n=se(t.body);return m(e,n.expected_execution_id),{status:200,body:l(()=>{const i=_(e);if(n.kind==="initial"){if((i.description??"").trim()!=="")return{applied:!1};const d=g(e,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:N(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 u=g(e,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:N(u),description:u.description??"",title:u.title??"",icon:u.icon??""}})}}r(ke,"handleGeneratedName");function he(t){const e=t.params.id,n=ae(t.body);return m(e,n.expected_execution_id),{status:200,body:l(()=>{const i=_(e),a={kind:i.kind,mode:i.mode,lifecycle:i.lifecycle},u=i.persona_ack,d=u===void 0?a:{kind:u.kind??i.kind,mode:u.mode,lifecycle:u.lifecycle};return!B(a,n.to)||!B(d,n.from)?{applied:!1}:(g(e,{persona_ack:n.to}),{applied:!0})})}}r(he,"handlePersonaAck");const Ge=Z([{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:de},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:ce},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:le},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:pe},{method:"POST",pattern:"/v1/nodes/:id/broker/telemetry",handler:me},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:fe},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:_e},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:ke},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:he}]);export{Ge as brokerOperationRoutes};
1
+ var q=Object.defineProperty;var s=(t,e)=>q(t,"name",{value:e,configurable:!0});import{canonicalSessionFile as D,findNodeBySessionFile as L,getNode as y,isWarmSpare as W,listNodeIdentities as G,recordSettledTurn as J,setPresence as x,subscriptionsOf as X,updateNode as S,updateNodeTelemetry as Y}from"../../../core/canvas/canvas.js";import{recordExecutionPid as V}from"../../../core/canvas/executions.js";import{bindSession as z,readLiveSession as U,transferSession as H}from"../../../core/canvas/sessions.js";import{isSafeNodeId as K}from"../../../core/canvas/paths.js";import{appForNode as h}from"../../../core/canvas/node-agent-paths.js";import{isPidAlive as Q}from"../../../core/canvas/pid.js";import{editorLabel as T}from"../../../core/canvas/labels.js";import{assembleNodeSubject as P}from"../../../core/substrate/subject.js";import{withCanvasWrite as f}from"../../../core/canvas/db.js";import{notFound as _,usage as d}from"../../../core/errors.js";import{ApiError as Z}from"../../../api/errors.js";import{hasUnseenWakeMail as C}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as ee}from"../../../core/runtime/kickoff.js";import{forkSourceNode as te}from"../../../core/runtime/nodes.js";import{transition as k}from"../../../core/runtime/lifecycle.js";import{focusOf as w,tearDownNode as O}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as ne}from"../viewer-presence.js";import{evaluateStop as oe}from"../../../core/runtime/stop-guard.js";import{clearFault as b,recordFault as re}from"../../../core/canvas/recovery.js";import{updateModelRecipe as ie}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as se}from"../../review/finish.js";import{emitEvent as E}from"../../../core/events/emit.js";import{consumePendingPark as ae,recordPendingParkActivity as de}from"../../park-pending.js";import{shouldParkAfterSummary as ce}from"../../park-activity.js";import{ownerOnly as ue}from"../router.js";import{requireCurrentExecution as p}from"./broker-recovery.js";import{ensureRunObserver as le}from"../../runs/observer.js";import{buildContextBearings as pe}from"../../../core/runtime/bearings.js";import{renderPreferencesForNodeSubject as me}from"../../../core/runtime/broker-extension-render.js";import{automaticMemoryTarget as A}from"../../../core/spaces/permissions.js";import{buildRefInventory as fe}from"../../../core/memory/inline-ref-inventory.js";import{clearSessionCache as he}from"../../../core/substrate/session-cache.js";import{insertMemoryReads as be}from"../../../core/canvas/memory-reads.js";import{MAX_MEMORY_READ_EVENTS as F,MAX_MEMORY_READ_TEXT as B}from"./memory-reads.js";import{memoryEvents as ye}from"../../../core/substrate/memory-events.js";import{cloneContextExposureState as R,cloneTranscriptExposureState as _e,emptyContextExposureState as j,exposureTarget as N,freezePreferenceSnapshot as ke,hasTranscriptExposure as we,loadContextExposureState as I,restoreContextExposure as ge,saveContextExposureState as ve,snapshotContextExposure as $}from"../../../core/substrate/injected-store.js";import{renderOnReadDocsForSubject as xe,renderOnCommandDocsForSubject as Se,renderPreCommandDocsForSubject as Pe,demotePreCommandExposures as Oe}from"../../../core/substrate/on-read.js";import{renderConfigChangeDelta as Ae}from"../../../core/substrate/render.js";function l(t,e){if(typeof t!="object"||t===null||Array.isArray(t))throw d(`${e} requires a JSON body`);return t}s(l,"objectBody");function Ne(t){const e=l(t,"broker session-bound");if(typeof e.executionId!="string"||e.executionId==="")throw d("executionId must be a non-empty string");if(typeof e.piSessionId!="string"||e.piSessionId==="")throw d("piSessionId must be a non-empty string");if(e.sessionFile!==null&&typeof e.sessionFile!="string")throw d("sessionFile must be a string or null");if(!Number.isSafeInteger(e.pid)||e.pid<=0)throw d("pid must be a positive safe integer");if(e.reason!==null&&typeof e.reason!="string")throw d("reason must be a string or null");if(!Array.isArray(e.reviewBoundaryIds)||!e.reviewBoundaryIds.every(n=>typeof n=="string"))throw d("reviewBoundaryIds must be an array of strings");return e}s(Ne,"parseSessionBoundBody");function Te(t){const e=l(t,"broker settle");if(typeof e.stopReason!="string")throw d("stopReason must be a string");for(const n of["backgroundJobsRunning","pushedFinal"])if(typeof e[n]!="boolean")throw d(`${n} must be a boolean`);return e}s(Te,"parseSettleBody");function Ce(t){const e=l(t,"broker park-complete");if(e.outcome!=="completed"&&e.outcome!=="failed")throw d("outcome must be completed or failed");return e}s(Ce,"parseParkCompleteBody");function Ee(t){const e=l(t,"broker telemetry");if(typeof e.expected_execution_id!="string"||e.expected_execution_id==="")throw d("expected_execution_id must be a non-empty string");if(typeof e.tokens_in!="number"||!Number.isFinite(e.tokens_in)||e.tokens_in<0)throw d("tokens_in must be a non-negative finite number");if(e.context_tokens!==null&&(typeof e.context_tokens!="number"||!Number.isFinite(e.context_tokens)||e.context_tokens<0))throw d("context_tokens must be a non-negative finite number or null");if(e.last_activity!==null&&typeof e.last_activity!="string")throw d("last_activity must be a string or null");if(typeof e.updated_at!="string"||Number.isNaN(Date.parse(e.updated_at)))throw d("updated_at must be an ISO timestamp");return{...e,updated_at:new Date(e.updated_at).toISOString()}}s(Ee,"parseTelemetryBody");function Fe(t){const e=l(t,"broker model");if(typeof e.spec!="string"||e.spec.trim()==="")throw d("spec must be a non-empty string");const n=e.intent;if(n!==void 0){const r=n!==null&&typeof n=="object"?n:void 0;if(r===void 0||typeof r.family!="string"||r.family===""||!["ultra","strong","medium","light"].includes(r.strength))throw d("intent must be { family, strength } with strength ultra|strong|medium|light when present")}if(typeof e.userSelected!="boolean")throw d("userSelected must be a boolean");return e}s(Fe,"parseModelCommitBody");function m(t){const e=y(t);if(e===null)throw _(`unknown node: ${t}`,{received:t});return e}s(m,"requireNode");function g(t){return{node_id:t.node_id,grantee:h(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}}s(g,"extensionNode");function Be(t){const e=m(t),n=[],r=new Set([t]);let o=e.parent??null;for(;o!==null&&o!==""&&!r.has(o);){r.add(o);const c=y(o);if(c===null)break;n.unshift(g(c)),o=c.parent??null}const a=X(t).map(c=>y(c.node_id)).filter(c=>c!==null&&c.kind!=="human").sort((c,v)=>c.status===v.status?0:c.status==="active"?-1:v.status==="active"?1:0).map(g),i=typeof e.fork_source_file=="string"?te(e.fork_source_file):null,u=P(t);if(u===null)throw _(`unknown node: ${t}`,{received:t});return{node:g(e),warm_spare:W(t),ancestors:n,children:a,fork_source:i===null?null:g(i),subject:u,report_nodes:G().map(c=>({...c,grantee:h(c.node_id)}))}}s(Be,"extensionState");function M(t,e){return t?.kind===e.kind&&t?.mode===e.mode&&t?.lifecycle===e.lifecycle}s(M,"samePersona");function Re(t){const e=l(t,"broker generated-name");if(e.kind!=="initial"&&e.kind!=="recap")throw d("kind must be initial or recap");if(typeof e.description!="string"||typeof e.title!="string"||typeof e.icon!="string")throw d("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(r=>typeof n[r]!="string"))throw d("recap expected must contain name, description, title, icon, and kind strings");return e}s(Re,"parseGeneratedNameBody");function je(t){const e=l(t,"broker persona-ack"),n=s(r=>{const o=e[r];if(typeof o!="object"||o===null||Array.isArray(o)||typeof o.kind!="string"||o.mode!=="base"&&o.mode!=="orchestrator"||o.lifecycle!=="terminal"&&o.lifecycle!=="resident")throw d(`${r} must be a persona state`);return o},"parse");return{expected_execution_id:e.expected_execution_id,from:n("from"),to:n("to")}}s(je,"parsePersonaAckBody");function Ie(t){const e=t.params.id,n=Ne(t.body),r=n.sessionFile===null?null:D(n.sessionFile);return{status:200,body:f(()=>{const a=m(e);if(V(n.executionId,e,n.pid)==="shutdown")return{action:"shutdown"};const i=a.review_binding?.review_id;if(i!==void 0&&!n.reviewBoundaryIds.includes(i))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&&r===null)return{action:"shutdown"};const u=r===null?null:L(r);if(u!==null&&u.node_id!==e){if(Q(u.pi_pid))return re(e,{link:"daemon\u2192node",op:"session-file-ownership",kind:"protocol",retry:{disposition:"fatal"},message:`refusing to bind ${r}: it is owned by live node ${u.node_id}`}),{action:"shutdown"};const c=U(u.node_id);if(c===null||H({fromNodeId:u.node_id,fromBindingId:c.bindingId,toNodeId:e,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:r})!=="transferred")return{action:"shutdown"}}else if(z(e,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:r})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(ee(e),a.intent==="refresh"&&k(e,"revive")),{action:"none"}})}}s(Ie,"handleSessionBound");function $e(t,e){const n=y(t);if(n===null){if(e.pushedFinal)return{action:"shutdown"};throw _(`unknown node: ${t}`,{received:t})}if(J(t,new Date().toISOString()),e.stopReason==="quit")return(n.status==="active"||n.status==="idle")&&n.intent===null&&(k(t,"finish"),b(t),w(t)!==null&&O(t),x(t,{pane:null,tmux_session:null,window:null})),{action:"shutdown"};if(e.stopReason!=="stop"&&e.stopReason!=="length")return b(t,{link:"daemon\u2192node"}),n.intent==="refresh"?{action:"shutdown"}:{action:"stay_dormant"};const r={pushedFinal:e.pushedFinal};if(r.pushedFinal||n.status==="done")return b(t),w(t)!==null&&O(t),x(t,{pane:null,tmux_session:null,window:null}),{action:"shutdown"};if(n.intent==="refresh")return b(t),{action:"shutdown"};const o=oe(t,r,e.backgroundJobsRunning);return b(t),o.action==="reprompt"?{action:"reprompt",prompt:o.message}:o.reason==="finished"?C(t)?{action:"stay_dormant"}:{action:"shutdown"}:o.reason!=="awaiting"&&o.reason!=="scheduled"?{action:"stay_dormant"}:w(t)!==null||ne(t)||C(t)?{action:"stay_dormant"}:(k(t,"release"),{action:"shutdown"})}s($e,"settleBroker");function Me(t){const e=t.params.id,n=Te(t.body);p(e,n.expected_execution_id);const r=f(()=>$e(e,n));return r.action!=="reprompt"&&se(e),{status:200,body:r}}s(Me,"handleSettle");function qe(t){const e=t.params.id,n=Ce(t.body);return p(e,n.expected_execution_id),{status:200,body:f(()=>{const o=ae(e);if(o===void 0)return{action:"stay_dormant"};const a=m(e);return ce(e,a,o)?(b(e),k(e,"park"),w(e)!==null&&O(e),x(e,{pane:null,tmux_session:null,window:null}),E({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...K(e)?{node_id:e}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}})}}s(qe,"handleParkComplete");function De(t){const e=t.params.id;return p(e,l(t.body,"broker park-activity").expected_execution_id),{status:200,body:f(()=>({activity:de(e)?"recorded":"none"}))}}s(De,"handleParkActivity");function Le(t){const e=t.params.id,n=Ee(t.body);return p(e,n.expected_execution_id),f(()=>{Y(e,{tokensIn:n.tokens_in,contextTokens:n.context_tokens,lastActivity:n.last_activity,updatedAt:n.updated_at})}),{status:204}}s(Le,"handleTelemetry");function We(t){const e=t.params.id,n=Fe(t.body);return p(e,n.expected_execution_id),{status:200,body:{modelOverride:f(()=>ie(m(e),n.spec,n.intent,n.userSelected)).model_override}}}s(We,"handleModelCommit");function Ge(t){const e=t.params.id,n=m(e);return n.run_id&&le(e,n.run_id),{status:200,body:Be(e)}}s(Ge,"handleExtensionState");function Je(t){const e=t.params.id,n=l(t.body,"broker context");if(p(e,n.expected_execution_id),n.mode!=="baseline"&&n.mode!=="compact"&&n.mode!=="preferences")throw d("invalid broker context mode");const r=m(e),o=n.mode==="baseline"?j():I(e),a=n.mode==="compact"&&we(o),i=a?_e(o):n.mode==="preferences"?R(o):j(),u=[],c=n.mode!=="preferences"&&!a?pe(e,N(i,"transcript",u)):"";return i.preferenceSnapshot===null&&ke(i,me(e,P(e),N(i,"system",u),h(e),A({...r,grantee:h(e)}))),{status:200,body:{content:c,compact:a,snapshot:$(i),loads:u}}}s(Je,"handleContext");function Xe(t){const e=t.params.id,n=l(t.body,"broker memory refs");p(e,n.expected_execution_id);const r=m(e);he();const o=fe(A({...r,grantee:h(e)}));return{status:200,body:{refs:o.refs,names:[...o.names]}}}s(Xe,"handleMemoryRefs");function Ye(t){if(t===void 0)return[];if(!Array.isArray(t)||t.length>F)throw d(`loads must be an array of at most ${F} entries`);const e=s((n,r,o)=>{if(typeof n!="string"||n===""||n.length>B)throw d(`loads[${o}].${r} must be a non-empty string of at most ${B} characters`);return n},"field");return t.map((n,r)=>{if(typeof n!="object"||n===null||Array.isArray(n))throw d(`loads[${r}] must be an object`);const o=n,a=Object.keys(o).filter(i=>i!=="name"&&i!=="scope");if(a.length>0)throw d(`loads[${r}] has unknown field: ${a.join(", ")}`);return{name:e(o.name,"name",r),scope:e(o.scope,"scope",r)}})}s(Ye,"parseLoads");function Ve(t,e){if(e.length!==0)try{be(t,ye(e,"loaded"))}catch(n){E({level:"warn",event:"memory_reads.insert_failed",error:n,fields:{node_id:t}})}}s(Ve,"recordLoaded");function ze(t){const e=t.params.id,n=l(t.body,"broker context commit");p(e,n.expected_execution_id);const r=Ye(n.loads);return ve(e,ge(n.snapshot)),Ve(e,r),{status:204}}s(ze,"handleContextCommit");function Ue(t){const e=t.params.id,n=l(t.body,"broker context event");if(p(e,n.expected_execution_id),!["read","command","pre-command","compact","persona"].includes(n.event))throw d("invalid broker context event");if(["read","command","pre-command"].includes(n.event)&&(typeof n.value!="string"||n.value===""))throw d("broker context event requires a value");const r=m(e),o=P(e);if(o===null)throw _(`unknown node: ${e}`);const a=R(I(e)),i=A({...r,grantee:h(e)});if(n.event==="read"&&(typeof n.value!="string"||!n.value.startsWith("/")||i.allowsProject?.(n.value)===!1))throw new Z(403,"scope_missing","read file is outside the run mounts");const u=[],c=N(a,"transcript",u);return{status:200,body:{content:n.event==="read"?xe(o,n.value,c,void 0,i):n.event==="command"?Se(o,n.value,c,void 0,i):n.event==="pre-command"?Pe(o,n.value,c,void 0,i):n.event==="persona"?Ae(o,e,c,h(e),i):(Oe(a,i),""),compact:!1,snapshot:$(a),loads:u}}}s(Ue,"handleContextEvent");function He(t){const e=t.params.id,n=Re(t.body);return p(e,n.expected_execution_id),{status:200,body:f(()=>{const o=m(e);if(n.kind==="initial"){if((o.description??"").trim()!=="")return{applied:!1};const u=S(e,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:T(u),description:u.description??"",title:u.title??"",icon:u.icon??""}}const a=n.expected;if(o.name!==a.name||(o.description??"")!==a.description||(o.title??"")!==a.title||(o.icon??"")!==a.icon||o.kind!==a.kind)return{applied:!1};const i=S(e,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:T(i),description:i.description??"",title:i.title??"",icon:i.icon??""}})}}s(He,"handleGeneratedName");function Ke(t){const e=t.params.id,n=je(t.body);return p(e,n.expected_execution_id),{status:200,body:f(()=>{const o=m(e),a={kind:o.kind,mode:o.mode,lifecycle:o.lifecycle},i=o.persona_ack,u=i===void 0?a:{kind:i.kind??o.kind,mode:i.mode,lifecycle:i.lifecycle};return!M(a,n.to)||!M(u,n.from)?{applied:!1}:(S(e,{persona_ack:n.to}),{applied:!0})})}}s(Ke,"handlePersonaAck");const $t=ue([{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:Ie},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:Me},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:qe},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:De},{method:"POST",pattern:"/v1/nodes/:id/broker/telemetry",handler:Le},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:We},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:Ge},{method:"POST",pattern:"/v1/nodes/:id/broker/context",handler:Je},{method:"POST",pattern:"/v1/nodes/:id/broker/memory-refs",handler:Xe},{method:"POST",pattern:"/v1/nodes/:id/broker/context/commit",handler:ze},{method:"POST",pattern:"/v1/nodes/:id/broker/context/event",handler:Ue},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:He},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:Ke}]);export{$t as brokerOperationRoutes};
@@ -1,2 +1,2 @@
1
- import type { RouteTable } from '../router.js';
1
+ import { type RouteTable } from '../router.js';
2
2
  export declare const canvasRoutes: RouteTable;
@@ -1,6 +1,6 @@
1
- var P=Object.defineProperty;var u=(t,e)=>P(t,"name",{value:e,configurable:!0});import{graphNodes as I,pruneNodes as K,pruneToLimit as A,rosterEdges as C,rosterNodes as D}from"../../../core/canvas/canvas.js";import{activeBackgroundBashJobs as q}from"../../../core/bash-jobs.js";import{contextDir as H}from"../../../core/canvas/paths.js";import{nowIso as k}from"../../../core/fs-utils.js";import{isPidPresent as J}from"../../../core/canvas/pid.js";import{dashboardRowsAllFromSource as z,enrichRowsFromSource as Q}from"../../../core/canvas/render-source.js";import{localCanvasSource as M}from"../../../core/canvas/source.js";import{ticketCountsForNodes as j,ticketsAcrossCanvas as U}from"../../../core/canvas/attention.js";import{buildCorpus as Y,groupCorpus as V,resolveRef as W}from"../../../core/canvas/history.js";import{listFocuses as R,reapEmptyNodes as X}from"../../../core/runtime/placement.js";import{notFound as Z,usage as p}from"../../../core/errors.js";import{toGraphNodeDTO as ee}from"../map.js";function te(){return{status:200,body:{items:U().map(e=>({node_id:e.node_id,name:e.name,cwd:e.cwd,count:e.count,subjects:e.subjects}))}}}u(te,"handleAttention");function ne(t){const e=t.body;if(e===null||typeof e!="object"||!Array.isArray(e.node_ids))throw p("attention count request requires node_ids: string[]");const n=e.node_ids;if(!n.every(s=>typeof s=="string"))throw p("attention count request node_ids must contain only strings");return{status:200,body:{counts:j(n)}}}u(ne,"handleAttentionCounts");function B(t){return Buffer.from(String(t),"utf8").toString("base64")}u(B,"encodeCursor");function O(t){const e=Number(Buffer.from(t,"base64").toString("utf8"));if(!Number.isInteger(e)||e<0)throw p(`invalid cursor: ${t}`);return e}u(O,"decodeCursor");function oe(t,e,n){const s=t.loadBody().split(`
2
- `);if(e.length>0){const i=s.findIndex(d=>{const o=d.toLowerCase();return e.some(c=>o.includes(c))});if(i!==-1)return s.slice(i,i+n).map(d=>d.trim()).filter(d=>d!=="").join(" \u23CE ")}const a=s.map(i=>i.trim()).filter(i=>i!=="").slice(0,n).join(" \u23CE ");return a!==""?a:t.title}u(oe,"snippet");function re(t,e,n){const r=[...t];return e==="relevance"&&n!==void 0?r.sort((s,a)=>(n.get(a.ref)??0)-(n.get(s.ref)??0)||a.tsMs-s.tsMs||s.ref.localeCompare(a.ref)):e==="oldest"?r.sort((s,a)=>s.tsMs-a.tsMs||s.ref.localeCompare(a.ref)):r.sort((s,a)=>a.tsMs-s.tsMs||s.ref.localeCompare(a.ref)),r}u(re,"sortArtifacts");function se(t){if(t==null)return{};if(typeof t!="object")throw p("history search body must be a JSON object");return t}u(se,"parseSearchBody");function ie(t){if(t===null||typeof t!="object")throw p("history grep body must be a JSON object");const e=t;if(typeof e.pattern!="string"||e.pattern==="")throw p("history grep body requires a non-empty pattern");return e}u(ie,"parseGrepBody");function $(t){const e={cwd:t.cwd,allCwds:t.all_cwds===!0,under:t.under,nodes:t.nodes},n={types:t.types,reportKind:t.report_kind,kinds:t.kinds,statuses:t.statuses,sinceMs:t.since_ms,untilMs:t.until_ms,origins:t.origins,roles:t.roles,from:t.from};return Y(e,n)}u($,"buildCorpusFromQuery");function de(t){if(t==null)return{};if(typeof t!="object")throw p("history stats body must be a JSON object");return t}u(de,"parseStatsBody");const x=["origin","node","kind","day","type","role"];function ae(t){const e=de(t.body),n=e.group_by??"type";if(!x.includes(n))throw p(`--group-by must be one of: ${x.join(", ")}; received: ${String(e.group_by)}`);const r=$(e),s=V(r,n);return{status:200,body:{group_by:n,groups:s,total:s.reduce((i,d)=>i+d.count,0),scanned:r.length}}}u(ae,"handleHistoryStats");function ce(t){const e=ie(t.body),n=Math.min(100,Math.max(1,e.limit??20)),r=$(e),s=e.cursor!==void 0?O(e.cursor):0;let a;try{a=new RegExp(e.pattern,"i")}catch{throw p(`invalid regex pattern: ${e.pattern}`)}const i=[];for(const f of r)f.loadBody().split(`
3
- `).forEach((y,b)=>{a.test(y)&&i.push({ref:f.ref,node:`${f.nodeName} (${f.nodeId})`,ts:f.ts,line:b+1,text:y.trim()})});i.sort((f,m)=>f.ref.localeCompare(m.ref)||f.line-m.line);const d=i.slice(s,s+n),o=s+n<i.length?B(s+n):null;return{status:200,body:{hits:d,next_cursor:o,total:i.length}}}u(ce,"handleHistoryGrep");function ue(t){const e=se(t.body),n=(e.query??"").trim(),r=e.weigh_body===!0,s=e.full===!0,a=Math.max(1,e.snippet_lines??1),i=Math.min(100,Math.max(1,e.limit??20)),d=$(e),o=e.cursor!==void 0?O(e.cursor):0,c=n.toLowerCase().split(/\s+/).filter(l=>l.length>0);let f=d,m;const y=e.sort??(c.length>0?"relevance":"recency");if(c.length>0&&y==="relevance"){m=new Map;const l=[];for(const h of d){const S=h.title.toLowerCase(),F=h.nodeName.toLowerCase(),G=h.nodeDesc.toLowerCase(),N=r?h.loadBody().toLowerCase():null;let _=0;for(const v of c)S.includes(v)&&(_+=10),F.includes(v)&&(_+=5),G.includes(v)&&(_+=3),N!==null&&N.includes(v)&&(_+=1);_>0&&(m.set(h.ref,_),l.push(h))}f=l}else c.length>0&&(f=d.filter(l=>{const h=`${l.title}
4
- ${l.nodeName}
5
- ${l.nodeDesc}${r?`
6
- `+l.loadBody():""}`.toLowerCase();return c.some(S=>h.includes(S))}));const b=re(f,y,m),T=b.slice(o,o+i),E=o+i<b.length?B(o+i):null;return{status:200,body:{hits:T.map(l=>{const h={ref:l.ref,node:`${l.nodeName} (${l.nodeId})`,kind:l.nodeKind,source:l.source==="report"&&l.reportKind?`report:${l.reportKind}`:l.source,ts:l.ts};return y==="relevance"&&m!==void 0&&(h.score=m.get(l.ref)??0),s?h.body=l.loadBody():h.snippet=oe(l,c,a),h}),next_cursor:E,total:b.length}}}u(ue,"handleHistorySearch");function le(t){const e=(t.query.get("ref")??"").trim(),n=t.query.get("frontmatter")==="true";if(!e.includes(":"))throw p(`ref must be <node-id>:<relpath>; received: ${e}`,{received:e,next:"Get a valid ref from `crtr canvas history search` or `crtr node inspect artifacts <node-id>`."});let r;try{r=W(e)}catch(o){throw p(`ref rejected: ${o.message}`,{received:e,next:"Refs come verbatim from `crtr canvas history search`; do not hand-construct relpaths."})}if(r===null)throw Z(`no artifact for ref: ${e}`,{ref:e,next:"The node or file may not exist. Re-run `crtr canvas history search` for a current ref, or `crtr node inspect artifacts <node-id>` to list a node's artifacts."});const s=r.source==="report"&&r.reportKind?`report:${r.reportKind}`:r.source,i=(t.query.get("format")==="raw"||n)&&r.raw!==null?r.raw:r.body;return{status:200,body:{ref:e,node:`${r.nodeName} (${r.nodeId})`,source:s,ts:r.ts,content:i}}}u(le,"handleHistoryRead");function fe(t){for(const[r]of t.query)if(r!=="live")throw p(`unknown snapshot query parameter: ${r}`);const e=t.query.getAll("live");if(e.length>1)throw p("live must appear at most once");const n=e[0];if(n===void 0||n==="false"||n==="0")return!1;if(n==="true"||n==="1")return!0;throw p("live must be true or false")}u(fe,"snapshotLiveOnly");async function me(t){const e=new Set(R().map(o=>o.node_id)),n=await z(M,e,fe(t)),r=j(n.map(o=>o.node_id));await Q(M,n,r);const s=n.map(o=>{const c=o.srcRow,f=c?.host_kind??"tmux";return{node_id:o.node_id,name:o.name,title:o.handle??o.name,description:o.description??null,kind:o.kind,mode:o.mode,lifecycle:o.lifecycle??c?.lifecycle,status:o.status,cwd:o.cwd,profile_id:o.profile_id??null,parent:c?.parent??null,created:o.created,host_kind:f,enterable:f==="broker",attention_count:o.asks,...c?.cycles!=null?{cycles:c.cycles}:{},...o.mtimeMs!==void 0?{last_activity:new Date(o.mtimeMs).toISOString()}:{},ctx_tokens:o.ctx_tokens,streaming:o.streaming??!1,jobs_active:c!==void 0&&J(c.pi_pid)?q(H(o.node_id)).length:0,waiting_for:c?.waiting_for??null,hanging:o.hanging??null,viewed:o.viewed??!1,final_report:c?.final_report??null,finalized_at:c?.finalized_at??null}}),a=new Map;for(const o of C()){const c=a.get(o.from_id);c===void 0?a.set(o.from_id,[o.to_id]):c.push(o.to_id)}const i=Object.fromEntries(n.map(o=>[o.node_id,a.get(o.node_id)??[]]));return{status:200,body:{generated_at:k(),nodes:s,subscriptions:i}}}u(me,"handleSnapshot");function L(){const t=D().map(n=>{const r=n.host_kind??"tmux";return{node_id:n.node_id,name:n.name,kind:n.kind,mode:n.mode,lifecycle:n.lifecycle,status:n.status,cwd:n.cwd,host_kind:r,enterable:r==="broker",parent:n.parent,created:n.created}}),e=C().map(n=>({from_id:n.from_id,to_id:n.to_id,active:n.active,created:n.created}));return{generated_at:k(),nodes:t,edges:e}}u(L,"buildRoster");let g=null,w=null;function pe(){return g===null?(g=Promise.resolve().then(()=>L()).finally(()=>{g=null}),g):(w===null&&(w=g.then(()=>L()).finally(()=>{w=null})),w)}u(pe,"rosterCoalesced");async function he(){return{status:200,body:await pe()}}u(he,"handleRoster");function ye(){return{status:200,body:{generated_at:k(),nodes:I().map(ee),edges:C().map(e=>({from_id:e.from_id,to_id:e.to_id,active:e.active,created:e.created})),focused_node_ids:R().map(e=>e.node_id)}}}u(ye,"handleGraph");function _e(t){if(t==null)return{};if(typeof t!="object")throw p("prune body must be a JSON object");const e=t,n=u(f=>{const m=e[f];if(m!==void 0){if(typeof m!="number"||!Number.isFinite(m))throw p(`${f} must be a number`);return m}},"num"),r=u(f=>{const m=e[f];if(m!==void 0){if(typeof m!="boolean")throw p(`${f} must be a boolean`);return m}},"bool"),s={},a=n("limit");a!==void 0&&(s.limit=a);const i=n("ttl_days");i!==void 0&&(s.ttl_days=i);const d=r("include_stale");d!==void 0&&(s.include_stale=d);const o=r("empty");o!==void 0&&(s.empty=o);const c=r("dry_run");return c!==void 0&&(s.dry_run=c),s}u(_e,"parsePruneBody");function be(t){const e=_e(t.body),n=e.ttl_days??14,r=e.dry_run??!1;let s;return e.limit!==void 0?s=A({maxNodes:e.limit,dryRun:r}).pruned.map(d=>({node_id:d.node_id,status:d.status,created:d.created})):e.empty===!0?s=X({dryRun:r}).map(d=>({node_id:d,status:"empty",created:""})):s=K({ttlDays:n,dryRun:r,includeStale:e.include_stale??!1}).pruned.map(d=>({node_id:d.node_id,status:d.status,created:d.created})),{status:200,body:{pruned:s,dry_run:r,ttl_days:n}}}u(be,"handlePrune");const Te=[{method:"GET",pattern:"/v1/canvas/attention",handler:te},{method:"POST",pattern:"/v1/canvas/attention/counts",handler:ne},{method:"POST",pattern:"/v1/canvas/history/search",handler:ue},{method:"POST",pattern:"/v1/canvas/history/grep",handler:ce},{method:"GET",pattern:"/v1/canvas/history/read",handler:le},{method:"POST",pattern:"/v1/canvas/history/stats",handler:ae},{method:"GET",pattern:"/v1/canvas/snapshot",handler:me},{method:"GET",pattern:"/v1/canvas/roster",handler:he},{method:"GET",pattern:"/v1/canvas/graph",handler:ye},{method:"POST",pattern:"/v1/canvas/prune",ownerOnly:!0,handler:be}];export{Te as canvasRoutes};
1
+ var H=Object.defineProperty;var c=(t,e)=>H(t,"name",{value:e,configurable:!0});import{graphNodes as q,listNodes as M,pruneNodes as x,pruneToLimit as J,rosterEdges as N,rosterNodes as z}from"../../../core/canvas/canvas.js";import{activeBackgroundBashJobs as Q}from"../../../core/bash-jobs.js";import{contextDir as U}from"../../../core/canvas/node-agent-paths.js";import{nowIso as k}from"../../../core/fs-utils.js";import{isPidPresent as Y}from"../../../core/canvas/pid.js";import{dashboardRowsAllFromSource as V,enrichRowsFromSource as W}from"../../../core/canvas/render-source.js";import{localCanvasSource as j}from"../../../core/canvas/source.js";import{ticketCountsForNodes as B,ticketsAcrossCanvas as X}from"../../../core/canvas/attention.js";import{buildCorpus as Z,groupCorpus as ee,resolveRef as te}from"../../../core/canvas/history.js";import{listFocuses as O,reapEmptyNodes as ne}from"../../../core/runtime/placement.js";import{boundFleet as oe}from"../../../core/runtime/fleet.js";import{retentionHold as re}from"../../reconcilers/live-obligation.js";import{notFound as se,usage as p}from"../../../core/errors.js";import{toGraphNodeDTO as ie}from"../map.js";import{canReadNode as L,canReadRun as de}from"../router.js";import{ApiError as ae}from"../../../api/errors.js";function g(t){return t.principal.class==="person"?null:new Set(M().filter(e=>L(t.principal,e.grantee??"app:terminal")).map(e=>e.node_id))}c(g,"visibleNodes");function T(t){return t.principal.class==="person"?null:new Set(M().filter(e=>e.run_id?de(t.principal,e.grantee??"app:terminal"):L(t.principal,e.grantee??"app:terminal")).map(e=>e.node_id))}c(T,"visibleHistoryNodes");function ce(t){const e=g(t);return{status:200,body:{items:X().filter(n=>e===null||e.has(n.node_id)).map(n=>({node_id:n.node_id,name:n.name,cwd:n.cwd,count:n.count,subjects:n.subjects}))}}}c(ce,"handleAttention");function le(t){const e=t.body;if(e===null||typeof e!="object"||!Array.isArray(e.node_ids))throw p("attention count request requires node_ids: string[]");const o=e.node_ids;if(!o.every(i=>typeof i=="string"))throw p("attention count request node_ids must contain only strings");const n=g(t);return{status:200,body:{counts:B(o.filter(i=>n===null||n.has(i)))}}}c(le,"handleAttentionCounts");function E(t){return Buffer.from(String(t),"utf8").toString("base64")}c(E,"encodeCursor");function F(t){const e=Number(Buffer.from(t,"base64").toString("utf8"));if(!Number.isInteger(e)||e<0)throw p(`invalid cursor: ${t}`);return e}c(F,"decodeCursor");function ue(t,e,o){const s=t.loadBody().split(`
2
+ `);if(e.length>0){const a=s.findIndex(u=>{const l=u.toLowerCase();return e.some(m=>l.includes(m))});if(a!==-1)return s.slice(a,a+o).map(u=>u.trim()).filter(u=>u!=="").join(" \u23CE ")}const i=s.map(a=>a.trim()).filter(a=>a!=="").slice(0,o).join(" \u23CE ");return i!==""?i:t.title}c(ue,"snippet");function fe(t,e,o){const n=[...t];return e==="relevance"&&o!==void 0?n.sort((s,i)=>(o.get(i.ref)??0)-(o.get(s.ref)??0)||i.tsMs-s.tsMs||s.ref.localeCompare(i.ref)):e==="oldest"?n.sort((s,i)=>s.tsMs-i.tsMs||s.ref.localeCompare(i.ref)):n.sort((s,i)=>i.tsMs-s.tsMs||s.ref.localeCompare(i.ref)),n}c(fe,"sortArtifacts");function pe(t){if(t==null)return{};if(typeof t!="object")throw p("history search body must be a JSON object");return t}c(pe,"parseSearchBody");function me(t){if(t===null||typeof t!="object")throw p("history grep body must be a JSON object");const e=t;if(typeof e.pattern!="string"||e.pattern==="")throw p("history grep body requires a non-empty pattern");return e}c(me,"parseGrepBody");function $(t,e){const o={cwd:t.cwd,allCwds:t.all_cwds===!0,under:t.under,nodes:t.nodes},n={types:t.types,reportKind:t.report_kind,kinds:t.kinds,statuses:t.statuses,sinceMs:t.since_ms,untilMs:t.until_ms,origins:t.origins,roles:t.roles,from:t.from},s=T(e);return Z(o,n).filter(i=>s===null||s.has(i.nodeId))}c($,"buildCorpusFromQuery");function he(t){if(t==null)return{};if(typeof t!="object")throw p("history stats body must be a JSON object");return t}c(he,"parseStatsBody");const I=["origin","node","kind","day","type","role"];function ye(t){const e=he(t.body),o=e.group_by??"type";if(!I.includes(o))throw p(`--group-by must be one of: ${I.join(", ")}; received: ${String(e.group_by)}`);const n=$(e,t),s=ee(n,o);return{status:200,body:{group_by:o,groups:s,total:s.reduce((a,u)=>a+u.count,0),scanned:n.length}}}c(ye,"handleHistoryStats");function _e(t){const e=me(t.body),o=Math.min(100,Math.max(1,e.limit??20)),n=$(e,t),s=e.cursor!==void 0?F(e.cursor):0;let i;try{i=new RegExp(e.pattern,"i")}catch{throw p(`invalid regex pattern: ${e.pattern}`)}const a=[];for(const r of n)r.loadBody().split(`
3
+ `).forEach((y,b)=>{i.test(y)&&a.push({ref:r.ref,node:`${r.nodeName} (${r.nodeId})`,ts:r.ts,line:b+1,text:y.trim()})});a.sort((r,d)=>r.ref.localeCompare(d.ref)||r.line-d.line);const u=a.slice(s,s+o),l=s+o<a.length?E(s+o):null;return{status:200,body:{hits:u,next_cursor:l,total:a.length}}}c(_e,"handleHistoryGrep");function be(t){const e=pe(t.body),o=(e.query??"").trim(),n=e.weigh_body===!0,s=e.full===!0,i=Math.max(1,e.snippet_lines??1),a=Math.min(100,Math.max(1,e.limit??20)),u=$(e,t),l=e.cursor!==void 0?F(e.cursor):0,m=o.toLowerCase().split(/\s+/).filter(f=>f.length>0);let r=u,d;const y=e.sort??(m.length>0?"relevance":"recency");if(m.length>0&&y==="relevance"){d=new Map;const f=[];for(const h of u){const C=h.title.toLowerCase(),K=h.nodeName.toLowerCase(),D=h.nodeDesc.toLowerCase(),R=n?h.loadBody().toLowerCase():null;let _=0;for(const w of m)C.includes(w)&&(_+=10),K.includes(w)&&(_+=5),D.includes(w)&&(_+=3),R!==null&&R.includes(w)&&(_+=1);_>0&&(d.set(h.ref,_),f.push(h))}r=f}else m.length>0&&(r=u.filter(f=>{const h=`${f.title}
4
+ ${f.nodeName}
5
+ ${f.nodeDesc}${n?`
6
+ `+f.loadBody():""}`.toLowerCase();return m.some(C=>h.includes(C))}));const b=fe(r,y,d),P=b.slice(l,l+a),A=l+a<b.length?E(l+a):null;return{status:200,body:{hits:P.map(f=>{const h={ref:f.ref,node:`${f.nodeName} (${f.nodeId})`,kind:f.nodeKind,source:f.source==="report"&&f.reportKind?`report:${f.reportKind}`:f.source,ts:f.ts};return y==="relevance"&&d!==void 0&&(h.score=d.get(f.ref)??0),s?h.body=f.loadBody():h.snippet=ue(f,m,i),h}),next_cursor:A,total:b.length}}}c(be,"handleHistorySearch");function ge(t){const e=(t.query.get("ref")??"").trim(),o=t.query.get("frontmatter")==="true";if(!e.includes(":"))throw p(`ref must be <node-id>:<relpath>; received: ${e}`,{received:e,next:"Get a valid ref from `crtr canvas history search` or `crtr node inspect artifacts <node-id>`."});let n;try{n=te(e)}catch(l){throw p(`ref rejected: ${l.message}`,{received:e,next:"Refs come verbatim from `crtr canvas history search`; do not hand-construct relpaths."})}if(n===null)throw se(`no artifact for ref: ${e}`,{ref:e,next:"The node or file may not exist. Re-run `crtr canvas history search` for a current ref, or `crtr node inspect artifacts <node-id>` to list a node's artifacts."});if(T(t)?.has(n.nodeId)===!1)throw new ae(404,"not_found","artifact not found");const s=n.source==="report"&&n.reportKind?`report:${n.reportKind}`:n.source,a=(t.query.get("format")==="raw"||o)&&n.raw!==null?n.raw:n.body;return{status:200,body:{ref:e,node:`${n.nodeName} (${n.nodeId})`,source:s,ts:n.ts,content:a}}}c(ge,"handleHistoryRead");function ve(t){for(const[n]of t.query)if(n!=="live")throw p(`unknown snapshot query parameter: ${n}`);const e=t.query.getAll("live");if(e.length>1)throw p("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 p("live must be true or false")}c(ve,"snapshotLiveOnly");async function we(t){const e=new Set(O().map(r=>r.node_id)),o=g(t),n=(await V(j,e,ve(t))).filter(r=>o===null||o.has(r.node_id)),s=B(n.map(r=>r.node_id));await W(j,n,s);const i=n.map(r=>{const d=r.srcRow,y=d?.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??d?.lifecycle,status:r.status,cwd:r.cwd,profile_id:r.profile_id??null,parent:d?.parent??null,created:r.created,host_kind:y,enterable:y==="broker",attention_count:r.asks,...d?.cycles!=null?{cycles:d.cycles}:{},...r.mtimeMs!==void 0?{last_activity:new Date(r.mtimeMs).toISOString()}:{},ctx_tokens:r.ctx_tokens,streaming:r.streaming??!1,jobs_active:d!==void 0&&Y(d.pi_pid)?Q(U(r.node_id)).length:0,waiting_for:d?.waiting_for??null,hanging:r.hanging??null,viewed:r.viewed??!1,final_report:d?.final_report??null,finalized_at:d?.finalized_at??null}}),a=new Map;for(const r of N()){const d=a.get(r.from_id);d===void 0?a.set(r.from_id,[r.to_id]):d.push(r.to_id)}const u=new Set(n.map(r=>r.node_id)),l=Object.fromEntries(n.map(r=>[r.node_id,(a.get(r.node_id)??[]).filter(d=>u.has(d))]));return{status:200,body:{generated_at:k(),nodes:i,subscriptions:l}}}c(we,"handleSnapshot");function G(){const t=z().map(o=>{const n=o.host_kind??"tmux";return{node_id:o.node_id,name:o.name,kind:o.kind,mode:o.mode,lifecycle:o.lifecycle,status:o.status,cwd:o.cwd,host_kind:n,enterable:n==="broker",parent:o.parent,created:o.created}}),e=N().map(o=>({from_id:o.from_id,to_id:o.to_id,active:o.active,created:o.created}));return{generated_at:k(),nodes:t,edges:e}}c(G,"buildRoster");let v=null,S=null;function Se(){return v===null?(v=Promise.resolve().then(()=>G()).finally(()=>{v=null}),v):(S===null&&(S=v.then(()=>G()).finally(()=>{S=null})),S)}c(Se,"rosterCoalesced");async function Ce(t){const e=await Se(),o=g(t);return o===null?{status:200,body:e}:{status:200,body:{...e,nodes:e.nodes.filter(n=>o.has(n.node_id)),edges:e.edges.filter(n=>o.has(n.from_id)&&o.has(n.to_id))}}}c(Ce,"handleRoster");function Ne(t){const e=g(t);return{status:200,body:{generated_at:k(),nodes:q().filter(n=>e===null||e.has(n.node_id)).map(ie),edges:N().filter(n=>e===null||e.has(n.from_id)&&e.has(n.to_id)).map(n=>({from_id:n.from_id,to_id:n.to_id,active:n.active,created:n.created})),focused_node_ids:O().map(n=>n.node_id).filter(n=>e===null||e.has(n))}}}c(Ne,"handleGraph");function ke(t){if(t==null)return{};if(typeof t!="object")throw p("prune body must be a JSON object");const e=t,o=c(r=>{const d=e[r];if(d!==void 0){if(typeof d!="number"||!Number.isFinite(d))throw p(`${r} must be a number`);return d}},"num"),n=c(r=>{const d=e[r];if(d!==void 0){if(typeof d!="boolean")throw p(`${r} must be a boolean`);return d}},"bool"),s={},i=o("limit");i!==void 0&&(s.limit=i);const a=o("ttl_days");a!==void 0&&(s.ttl_days=a);const u=n("include_stale");u!==void 0&&(s.include_stale=u);const l=n("empty");l!==void 0&&(s.empty=l);const m=n("dry_run");return m!==void 0&&(s.dry_run=m),s}c(ke,"parsePruneBody");function $e(t){const e=ke(t.body),o=e.ttl_days??14,n=e.dry_run??!1,s=re(oe());let i;return e.limit!==void 0?i=J({maxNodes:e.limit,held:s,dryRun:n}).pruned.map(l=>({node_id:l.node_id,status:l.status,created:l.created})):e.empty===!0?i=ne({dryRun:n}).map(l=>({node_id:l,status:"empty",created:""})):i=x({ttlDays:o,held:s,dryRun:n,includeStale:e.include_stale??!1}).pruned.map(l=>({node_id:l.node_id,status:l.status,created:l.created})),{status:200,body:{pruned:i,dry_run:n,ttl_days:o}}}c($e,"handlePrune");const ze=[{method:"GET",pattern:"/v1/canvas/attention",handler:ce},{method:"POST",pattern:"/v1/canvas/attention/counts",handler:le},{method:"POST",pattern:"/v1/canvas/history/search",handler:be},{method:"POST",pattern:"/v1/canvas/history/grep",handler:_e},{method:"GET",pattern:"/v1/canvas/history/read",handler:ge},{method:"POST",pattern:"/v1/canvas/history/stats",handler:ye},{method:"GET",pattern:"/v1/canvas/snapshot",handler:we},{method:"GET",pattern:"/v1/canvas/roster",handler:Ce},{method:"GET",pattern:"/v1/canvas/graph",handler:Ne},{method:"POST",pattern:"/v1/canvas/prune",ownerOnly:!0,handler:$e}];export{ze as canvasRoutes};
@@ -1 +1 @@
1
- var z=Object.defineProperty;var o=(e,n)=>z(e,"name",{value:n,configurable:!0});import{randomUUID as B}from"node:crypto";import{ApiError as d}from"../../../api/errors.js";import{armCron as G,cancelCron as L,getCron as l,listCrons as y,listCronRuns as j,pokeHeldCrons as Z,setCronState as q}from"../../../core/canvas/crons.js";import{getNode as k}from"../../../core/canvas/canvas.js";import{assertScope as C}from"../../../core/scopes.js";import{InputError as t}from"../../../core/io.js";import{nextSlotAfter as H}from"../../../core/wake.js";import{executeCron as Y,markSelfCanceledCronRun as F}from"../../cron-run.js";import{toCronDTO as f,toCronRunDTO as N}from"../map.js";import{assertCeiling as K}from"../router.js";function h(e,n){const r=e[n];if(typeof r!="string"||r.trim()==="")throw new t({error:"missing_field",message:`cron arm request requires a non-empty "${n}"`,field:n,next:`Send a non-empty string "${n}".`});return r}o(h,"requireString");function m(e,n,r,s){if(e==null)return s;if(typeof e=="string"&&r.includes(e))return e;throw new t({error:`bad_${n}`,message:`"${String(e)}" is not a valid ${n}`,field:n,next:`Use one of: ${r.join(", ")}.`})}o(m,"requireEnum");function M(e){if(e==="human")return JSON.stringify({human:!0});if(e.startsWith("node:")){const n=e.slice(5).trim();if(n==="")throw new t({error:"bad_sink",message:"node sink requires a node id",field:"sink",next:'Use sink "node:<node-id>".'});if(k(n)===null)throw new t({error:"sink_node_not_found",message:`sink node ${n} does not exist on the canvas`,field:"sink",next:"Name a live node id, or use spawn:<kind> for a delivery that outlives any one node."});return JSON.stringify({node:n})}if(e.startsWith("spawn:")){const n=e.slice(6).trim();if(n==="")throw new t({error:"bad_sink",message:"spawn sink requires a node kind",field:"sink",next:'Use sink "spawn:<kind>" (e.g. spawn:general).'});return JSON.stringify({spawn:n})}throw new t({error:"bad_sink",message:`"${e}" is not a valid sink`,field:"sink",next:"Use node:<node-id>, spawn:<kind>, or human."})}o(M,"parseSinkSpec");const Q=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;function T(e,n){if(!Q.test(e)||Number.isNaN(Date.parse(e)))throw new t({error:`bad_${n}`,message:`"${e}" is not a UTC ISO instant`,field:n,next:'Send a resolved UTC instant like "2026-06-07T09:00:00.000Z" (the client resolves the time grammar).'});return e}o(T,"requireUtcIso");function V(e){try{H(e,new Date)}catch(n){throw new t({error:"bad_recur",message:`recur is not advanceable: ${n instanceof Error?n.message:String(n)}`,field:"recur",next:'Send recur JSON the daemon can advance: {"every":"6h"} or {"cron":"0 9 * * *","tz":"America/New_York"}.'})}return e}o(V,"requireRecur");function X(e){let n;try{n=JSON.parse(e)}catch{throw new t({error:"bad_env_json",message:"env_json is not valid JSON",field:"env_json",next:'Send a JSON object of string values, e.g. {"API_BASE":"https://x"}.'})}if(typeof n!="object"||n===null||Array.isArray(n))throw new t({error:"bad_env_json",message:"env_json must be a JSON object",field:"env_json",next:'Send a JSON object of string values, e.g. {"API_BASE":"https://x"}.'});for(const[r,s]of Object.entries(n))if(typeof s!="string")throw new t({error:"bad_env_json",message:`env_json value for "${r}" is not a string`,field:"env_json",next:"Every env value must be a string."});return e}o(X,"requireEnvJson");function b(e){const n=e.query.get("profile");return n!==null&&n.trim()!==""?n.trim():null}o(b,"callerProfile");function E(e,n){return n===null||e.scope==="global"||e.profile===n}o(E,"inScope");function nn(e){const n=e.body??{},r=h(n,"name"),s=h(n,"command"),a=T(h(n,"fire_at"),"fire_at"),P=h(n,"cwd"),A=typeof n.recur=="string"&&n.recur!==""?V(n.recur):null,J=typeof n.expires_at=="string"&&n.expires_at!==""?T(n.expires_at,"expires_at"):null,U=typeof n.env_json=="string"&&n.env_json!==""?X(n.env_json):null,i=typeof n.sink=="string"&&n.sink.trim()!==""?n.sink.trim():null,c=m(n.on_output,"on_output",["silent","on-failure","always","on-change"],i?.startsWith("node:")?"on-change":"on-failure"),R=m(n.overlap,"overlap",["skip","queue","replace"],"skip"),D=m(n.tier,"tier",["normal","urgent","critical"],"normal"),x=c==="always"||c==="on-change";if(x&&i===null)throw new t({error:"sink_required",message:`on_output "${c}" delivers stdout every qualifying run \u2014 it needs a sink`,field:"sink",next:"Pass sink node:<node-id> (a living node's inbox), spawn:<kind> (birth a fresh node per delivery), or human (the humanloop inbox)."});if(!x&&i!==null)throw new t({error:"sink_unused",message:`on_output "${c}" never delivers stdout \u2014 a sink would be dead config`,field:"sink",next:'Drop the sink, or use on_output "always"/"on-change" if delivery is the point.'});const W=i!==null?M(i):"{}";i?.startsWith("spawn:")&&K(e.ceiling,"act");const g=typeof n.created_by=="string"&&n.created_by!==""?n.created_by:null;if(g!==null){const v=k(g);v!==null&&(C(v,"schedule"),i?.startsWith("spawn:")&&C(v,"act"))}const u=typeof n.anchor_node=="string"&&n.anchor_node!==""?n.anchor_node:null;if(u!==null&&k(u)===null)throw new t({error:"anchor_not_found",message:`anchor node ${u} does not exist on the canvas`,field:"anchor_node",next:"Name a live node id, or drop the anchor \u2014 an unanchored cron outlives every node."});const O=n.cancel_on_wake===!0;if(O&&u===null)throw new t({error:"cancel_on_wake_needs_anchor",message:"cancel_on_wake couples the cron to a node's dormancy \u2014 it requires an anchor node",field:"anchor_node",next:"Pass anchor_node with the node whose wake should cancel this cron."});const p=n.run_timeout_s??300;if(typeof p!="number"||!Number.isInteger(p)||p<=0)throw new t({error:"bad_run_timeout",message:`run_timeout_s must be a positive integer (got ${String(n.run_timeout_s)})`,field:"run_timeout_s",next:"Send the timeout in whole seconds, e.g. 300."});const w=typeof n.profile=="string"&&n.profile!==""?n.profile:null,$=m(n.scope,"scope",["profile","global"],w!==null?"profile":"global");if($==="profile"&&w===null)throw new t({error:"scope_needs_profile",message:'scope "profile" names the profile the cron lists and cancels within \u2014 it requires a profile',field:"profile",next:'Send a profile, or use scope "global" for a canvas-home-wide cron.'});const I=B();return G({cron_id:I,name:r,created_by:g,command:s,fire_at:a,recur:A,tz:typeof n.tz=="string"?n.tz:null,expires_at:J,anchor_node:u,cancel_on_wake:O,cwd:P,env_json:U,profile:w,scope:$,run_timeout_s:p,overlap:R,on_output:c,sink:W,tier:D}),{status:201,body:f(l(I),null)}}o(nn,"handleArm");function en(e){const n=b(e);return{status:200,body:(n===null?y({all:!0}):[...y({profile:n}),...y({global:!0})].sort((s,a)=>s.fire_at<a.fire_at?-1:s.fire_at>a.fire_at?1:0)).map(s=>f(s,S(s)))}}o(en,"handleList");function S(e){return j(e.cron_id)[0]??null}o(S,"lastRunOf");function _(e){const n=e.params.cronId,r=l(n);if(r===null)throw new d(404,"cron_not_found",`no cron ${n}`);if(!E(r,b(e)))throw new d(404,"cron_not_found",`no cron ${n} in this profile \u2014 it is scoped to another profile`);return r}o(_,"requireCron");function rn(e){const n=_(e),r=j(n.cron_id);return{status:200,body:{cron:f(n,r[0]??null),runs:r.map(N)}}}o(rn,"handleShow");function on(e){const n=_(e);q(n.cron_id,"paused");const r=l(n.cron_id);return{status:200,body:f(r,S(r))}}o(on,"handlePause");function tn(e){const n=_(e);q(n.cron_id,"active");const r=l(n.cron_id);return{status:200,body:f(r,S(r))}}o(tn,"handleResume");async function sn(e){const n=_(e);if(n.run_state==="running")throw new d(409,"cron_running",`cron ${n.cron_id} has a run in flight \u2014 wait for it to settle`);const r=await Y(n,{outOfBand:!0});if(r===null)throw new d(409,"cron_running",`cron ${n.cron_id} was claimed by a concurrent run \u2014 check \`cron show\` for its result`);return{status:200,body:N(r)}}o(sn,"handleRun");function an(){const e=new Date().toISOString();return{status:200,body:{unparked:Z(e),at:e}}}o(an,"handlePoke");function cn(e){const n=e.params.cronId,r=l(n);if(r!==null&&!E(r,b(e)))throw new d(404,"cron_not_found",`no cron ${n} in this profile \u2014 it is scoped to another profile`);const s=e.query.get("run_id"),a=s!==null&&F(n,s);return L(n,{preserveRunningProcess:a}),{status:204}}o(cn,"handleCancel");const yn=[{method:"POST",pattern:"/v1/crons",scope:"schedule",handler:nn},{method:"GET",pattern:"/v1/crons",handler:en},{method:"GET",pattern:"/v1/crons/:cronId",handler:rn},{method:"POST",pattern:"/v1/crons/:cronId/pause",scope:"schedule",handler:on},{method:"POST",pattern:"/v1/crons/:cronId/resume",scope:"schedule",handler:tn},{method:"POST",pattern:"/v1/crons/poke",scope:"schedule",handler:an},{method:"POST",pattern:"/v1/crons/:cronId/run",scope:"schedule",handler:sn},{method:"DELETE",pattern:"/v1/crons/:cronId",scope:"schedule",handler:cn}];export{yn as cronRoutes};
1
+ var Z=Object.defineProperty;var o=(e,n)=>Z(e,"name",{value:n,configurable:!0});import{randomUUID as H}from"node:crypto";import{ApiError as c}from"../../../api/errors.js";import{armCron as Y,cancelCron as F,getCron as d,listCrons as S,listCronRuns as N,pokeHeldCrons as K,setCronState as T}from"../../../core/canvas/crons.js";import{getNode as p}from"../../../core/canvas/canvas.js";import{assertScope as P}from"../../../core/scopes.js";import{InputError as t}from"../../../core/io.js";import{nextSlotAfter as M}from"../../../core/wake.js";import{executeCron as Q,markSelfCanceledCronRun as V}from"../../cron-run.js";import{toCronDTO as f,toCronRunDTO as A}from"../map.js";import{assertCeiling as X,canReadNode as nn}from"../router.js";import{requireUsableProfile as en}from"./profiles.js";function m(e,n){const r=e[n];if(typeof r!="string"||r.trim()==="")throw new t({error:"missing_field",message:`cron arm request requires a non-empty "${n}"`,field:n,next:`Send a non-empty string "${n}".`});return r}o(m,"requireString");function g(e,n,r,s){if(e==null)return s;if(typeof e=="string"&&r.includes(e))return e;throw new t({error:`bad_${n}`,message:`"${String(e)}" is not a valid ${n}`,field:n,next:`Use one of: ${r.join(", ")}.`})}o(g,"requireEnum");function rn(e){if(e==="human")return JSON.stringify({human:!0});if(e.startsWith("node:")){const n=e.slice(5).trim();if(n==="")throw new t({error:"bad_sink",message:"node sink requires a node id",field:"sink",next:'Use sink "node:<node-id>".'});if(p(n)===null)throw new t({error:"sink_node_not_found",message:`sink node ${n} does not exist on the canvas`,field:"sink",next:"Name a live node id, or use spawn:<kind> for a delivery that outlives any one node."});return JSON.stringify({node:n})}if(e.startsWith("spawn:")){const n=e.slice(6).trim();if(n==="")throw new t({error:"bad_sink",message:"spawn sink requires a node kind",field:"sink",next:'Use sink "spawn:<kind>" (e.g. spawn:general).'});return JSON.stringify({spawn:n})}throw new t({error:"bad_sink",message:`"${e}" is not a valid sink`,field:"sink",next:"Use node:<node-id>, spawn:<kind>, or human."})}o(rn,"parseSinkSpec");const on=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;function E(e,n){if(!on.test(e)||Number.isNaN(Date.parse(e)))throw new t({error:`bad_${n}`,message:`"${e}" is not a UTC ISO instant`,field:n,next:'Send a resolved UTC instant like "2026-06-07T09:00:00.000Z" (the client resolves the time grammar).'});return e}o(E,"requireUtcIso");function tn(e){try{M(e,new Date)}catch(n){throw new t({error:"bad_recur",message:`recur is not advanceable: ${n instanceof Error?n.message:String(n)}`,field:"recur",next:'Send recur JSON the daemon can advance: {"every":"6h"} or {"cron":"0 9 * * *","tz":"America/New_York"}.'})}return e}o(tn,"requireRecur");function sn(e){let n;try{n=JSON.parse(e)}catch{throw new t({error:"bad_env_json",message:"env_json is not valid JSON",field:"env_json",next:'Send a JSON object of string values, e.g. {"API_BASE":"https://x"}.'})}if(typeof n!="object"||n===null||Array.isArray(n))throw new t({error:"bad_env_json",message:"env_json must be a JSON object",field:"env_json",next:'Send a JSON object of string values, e.g. {"API_BASE":"https://x"}.'});for(const[r,s]of Object.entries(n))if(typeof s!="string")throw new t({error:"bad_env_json",message:`env_json value for "${r}" is not a string`,field:"env_json",next:"Every env value must be a string."});return e}o(sn,"requireEnvJson");function O(e){const n=e.query.get("profile");return n!==null&&n.trim()!==""?n.trim():null}o(O,"callerProfile");function U(e,n){return n===null||e.scope==="global"||e.profile===n}o(U,"inScope");function J(e){return e.principal.class==="person"?null:e.principal.app}o(J,"callerApp");function $(e,n){return nn(e.principal,n.grantee)}o($,"visibleTo");function an(e){const n=e.body??{},r=m(n,"name"),s=m(n,"command"),l=E(m(n,"fire_at"),"fire_at"),R=m(n,"cwd"),D=typeof n.recur=="string"&&n.recur!==""?tn(n.recur):null,W=typeof n.expires_at=="string"&&n.expires_at!==""?E(n.expires_at,"expires_at"):null,z=typeof n.env_json=="string"&&n.env_json!==""?sn(n.env_json):null,a=typeof n.sink=="string"&&n.sink.trim()!==""?n.sink.trim():null,u=g(n.on_output,"on_output",["silent","on-failure","always","on-change"],a?.startsWith("node:")?"on-change":"on-failure"),B=g(n.overlap,"overlap",["skip","queue","replace"],"skip"),G=g(n.tier,"tier",["normal","urgent","critical"],"normal"),q=u==="always"||u==="on-change";if(q&&a===null)throw new t({error:"sink_required",message:`on_output "${u}" delivers stdout every qualifying run \u2014 it needs a sink`,field:"sink",next:"Pass sink node:<node-id> (a living node's inbox), spawn:<kind> (birth a fresh node per delivery), or human (the humanloop inbox)."});if(!q&&a!==null)throw new t({error:"sink_unused",message:`on_output "${u}" never delivers stdout \u2014 a sink would be dead config`,field:"sink",next:'Drop the sink, or use on_output "always"/"on-change" if delivery is the point.'});const L=a!==null?rn(a):"{}";a?.startsWith("spawn:")&&X(e.ceiling,"crtr:act");const y=e.principal.class==="person"?"app:terminal":e.principal.app,k=typeof n.created_by=="string"&&n.created_by!==""?n.created_by:null;if(k!==null){const _=p(k);if(_!==null){if(_.grantee!==y)throw new t({error:"creator_app_mismatch",message:"creator node belongs to another app",field:"created_by",next:"Use a node of the calling app."});P(_,"crtr:schedule"),a?.startsWith("spawn:")&&P(_,"crtr:act")}}const i=typeof n.anchor_node=="string"&&n.anchor_node!==""?n.anchor_node:null;if(i!==null&&p(i)!==null&&p(i).grantee!==y)throw new t({error:"anchor_app_mismatch",message:"anchor node belongs to another app",field:"anchor_node",next:"Use an anchor of the calling app."});if(i!==null&&p(i)===null)throw new t({error:"anchor_not_found",message:`anchor node ${i} does not exist on the canvas`,field:"anchor_node",next:"Name a live node id, or drop the anchor \u2014 an unanchored cron outlives every node."});const j=n.cancel_on_wake===!0;if(j&&i===null)throw new t({error:"cancel_on_wake_needs_anchor",message:"cancel_on_wake couples the cron to a node's dormancy \u2014 it requires an anchor node",field:"anchor_node",next:"Pass anchor_node with the node whose wake should cancel this cron."});const h=n.run_timeout_s??300;if(typeof h!="number"||!Number.isInteger(h)||h<=0)throw new t({error:"bad_run_timeout",message:`run_timeout_s must be a positive integer (got ${String(n.run_timeout_s)})`,field:"run_timeout_s",next:"Send the timeout in whole seconds, e.g. 300."});const b=typeof n.profile=="string"&&n.profile!==""?en(e,n.profile).profileId:null,x=g(n.scope,"scope",["profile","global"],b!==null?"profile":"global");if(x==="profile"&&b===null)throw new t({error:"scope_needs_profile",message:'scope "profile" names the profile the cron lists and cancels within \u2014 it requires a profile',field:"profile",next:'Send a profile, or use scope "global" for a canvas-home-wide cron.'});const C=H();return Y({cron_id:C,name:r,created_by:k,grantee:y,command:s,fire_at:l,recur:D,tz:typeof n.tz=="string"?n.tz:null,expires_at:W,anchor_node:i,cancel_on_wake:j,cwd:R,env_json:z,profile:b,scope:x,run_timeout_s:h,overlap:B,on_output:u,sink:L,tier:G}),{status:201,body:f(d(C),null)}}o(an,"handleArm");function cn(e){const n=O(e);return{status:200,body:(n===null?S({all:!0}):[...S({profile:n}),...S({global:!0})].sort((s,l)=>s.fire_at<l.fire_at?-1:s.fire_at>l.fire_at?1:0)).filter(s=>$(e,s)).map(s=>f(s,I(s)))}}o(cn,"handleList");function I(e){return N(e.cron_id)[0]??null}o(I,"lastRunOf");function w(e){const n=e.params.cronId,r=d(n);if(r===null||!$(e,r))throw new c(404,"cron_not_found",`no cron ${n}`);if(!U(r,O(e)))throw new c(404,"cron_not_found",`no cron ${n} in this profile \u2014 it is scoped to another profile`);return r}o(w,"requireCron");function v(e,n){const r=J(e);if(r!==null&&n.grantee!==r)throw new c(403,"other_app_run",`cron ${n.cron_id} belongs to another app`);return n}o(v,"requireOwnCron");function ln(e){const n=w(e),r=N(n.cron_id);return{status:200,body:{cron:f(n,r[0]??null),runs:r.map(A)}}}o(ln,"handleShow");function un(e){const n=v(e,w(e));T(n.cron_id,"paused");const r=d(n.cron_id);return{status:200,body:f(r,I(r))}}o(un,"handlePause");function dn(e){const n=v(e,w(e));T(n.cron_id,"active");const r=d(n.cron_id);return{status:200,body:f(r,I(r))}}o(dn,"handleResume");async function pn(e){const n=v(e,w(e));if(n.run_state==="running")throw new c(409,"cron_running",`cron ${n.cron_id} has a run in flight \u2014 wait for it to settle`);const r=await Q(n,{outOfBand:!0});if(r===null)throw new c(409,"cron_running",`cron ${n.cron_id} was claimed by a concurrent run \u2014 check \`cron show\` for its result`);return{status:200,body:A(r)}}o(pn,"handleRun");function fn(e){const n=new Date().toISOString();return{status:200,body:{unparked:K(n,J(e)),at:n}}}o(fn,"handlePoke");function hn(e){const n=e.params.cronId,r=d(n);if(r!==null&&!$(e,r))throw new c(404,"cron_not_found",`no cron ${n}`);if(r!==null&&!U(r,O(e)))throw new c(404,"cron_not_found",`no cron ${n} in this profile \u2014 it is scoped to another profile`);r!==null&&v(e,r);const s=e.query.get("run_id"),l=s!==null&&V(n,s);return F(n,{preserveRunningProcess:l}),{status:204}}o(hn,"handleCancel");const qn=[{method:"POST",pattern:"/v1/crons",scope:"crtr:schedule",handler:an},{method:"GET",pattern:"/v1/crons",handler:cn},{method:"GET",pattern:"/v1/crons/:cronId",handler:ln},{method:"POST",pattern:"/v1/crons/:cronId/pause",scope:"crtr:schedule",handler:un},{method:"POST",pattern:"/v1/crons/:cronId/resume",scope:"crtr:schedule",handler:dn},{method:"POST",pattern:"/v1/crons/poke",scope:"crtr:schedule",handler:fn},{method:"POST",pattern:"/v1/crons/:cronId/run",scope:"crtr:schedule",handler:pn},{method:"DELETE",pattern:"/v1/crons/:cronId",scope:"crtr:schedule",handler:hn}];export{qn as cronRoutes};
@@ -1,2 +1,2 @@
1
- import type { RouteTable } from '../router.js';
1
+ import { type RouteTable } from '../router.js';
2
2
  export declare const fileRoutes: RouteTable;
@@ -1 +1 @@
1
- var E=Object.defineProperty;var c=(e,t)=>E(e,"name",{value:t,configurable:!0});import{closeSync as y,fsyncSync as S,fstatSync as T,lstatSync as $,mkdirSync as A,openSync as g,readSync as q,readdirSync as _,realpathSync as I,renameSync as L,statSync as N,unlinkSync as k,writeSync as z}from"node:fs";import{randomUUID as B}from"node:crypto";import{basename as M,dirname as F,isAbsolute as O,join as b}from"node:path";import{ApiError as d}from"../../../api/index.js";import{notFound as P,usage as u}from"../../../core/errors.js";import{InputError as D}from"../../../core/io.js";const m=512*1024,w=1024*1024,R=1e3;function h(e,t){if(e===null||e==="")throw u(`a file ${t} requires a \`path\` ${t==="write"?"body field":"query param"}`);if(!O(e))throw u(`file ${t} path must be absolute`,{received:e});return e}c(h,"requireAbsolutePath");function p(e){if(e==null)return"utf8";if(e==="utf8"||e==="base64")return e;throw u("encoding must be `utf8` or `base64`",{received:e})}c(p,"parseEncoding");function l(e,t,n){if(e instanceof d||e instanceof D)throw e;const r=e.code;throw r==="ENOENT"?P(`no such file: ${t}`,{received:t}):r==="EACCES"||r==="EPERM"?new d(403,"forbidden",`permission denied ${n} ${t}`):new d(500,"internal",`cannot ${n} ${t}: ${e instanceof Error?e.message:String(e)}`)}c(l,"mapFilesystemError");function U(e,t){let n;try{n=g(e,"r")}catch(r){return l(r,e,"reading")}try{const r=T(n);if(r.isDirectory())throw u(`file peek path is a directory: ${e}`,{received:e});const f=Buffer.allocUnsafe(Math.min(r.size,m)+1),o=q(n,f,0,f.length,0),i=o>m,s=f.subarray(0,Math.min(o,m)).toString(t);return{path:e,content:s,truncated:i}}catch(r){return l(r,e,"reading")}finally{y(n)}}c(U,"readHead");function j(e){const t=h(e.query.get("path"),"peek");return{status:200,body:U(t,p(e.query.get("encoding")))}}c(j,"handlePeek");function C(e){return e.length%4===0&&/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(e)}c(C,"isBase64");function W(e){if(typeof e!="object"||e===null||Array.isArray(e))throw u("file write requires an object body");const t=e,n=h(typeof t.path=="string"?t.path:null,"write");if(typeof t.content!="string")throw u("file write requires a string `content` body field");const r=p(t.encoding);if(r==="base64"&&!C(t.content))throw u("base64 file content must be valid base64");return{path:n,content:t.content,encoding:r}}c(W,"parseWriteBody");function Z(e){try{if(!$(e).isSymbolicLink())return e}catch(t){return t.code!=="ENOENT"?l(t,e,"resolving"):e}try{return I(e)}catch(t){return l(t,e,"resolving")}}c(Z,"writeTarget");function v(e,t){if(t.byteLength>w)throw new d(413,"file_too_large",`file content exceeds the ${w} byte limit`);const n=Z(e),r=F(n);try{A(r,{recursive:!0})}catch(i){return l(i,e,"creating parent directory for")}const f=b(r,`.${M(e)}.${B()}.tmp`);let o;try{o=g(f,"wx",384);let i=0;for(;i<t.length;)i+=z(o,t,i,t.length-i);return S(o),y(o),o=void 0,L(f,n),{path:e,bytes_written:t.byteLength}}catch(i){return l(i,e,"writing")}finally{o!==void 0&&y(o);try{k(f)}catch(i){if(i.code!=="ENOENT")throw i}}}c(v,"writeAtomically");function G(e){const{path:t,content:n,encoding:r}=W(e.body);return{status:200,body:v(t,Buffer.from(n,r))}}c(G,"handleWrite");function X(e){if(e===null)return R;const t=Number(e);if(!Number.isInteger(t)||t<1)throw u("file list limit must be a positive integer",{received:e});return t}c(X,"parseLimit");function Y(e){const t=h(e.query.get("path"),"list"),n=X(e.query.get("limit"));let r;try{r=_(t,{withFileTypes:!0}).sort((s,a)=>s.name.localeCompare(a.name))}catch(s){return l(s,t,"listing")}const f=r.slice(0,n),o=[];try{for(const s of f){const a=N(b(t,s.name));o.push({name:s.name,type:a.isFile()?"file":a.isDirectory()?"dir":"other",size:a.size,modified:a.mtime.toISOString()})}}catch(s){return l(s,t,"listing")}return{status:200,body:{path:t,entries:o,truncated:r.length>n}}}c(Y,"handleList");const te=[{method:"GET",pattern:"/v1/files/peek",scope:"act",handler:j},{method:"POST",pattern:"/v1/files/write",scope:"act",handler:G},{method:"GET",pattern:"/v1/files/list",scope:"act",handler:Y}];export{te as fileRoutes};
1
+ var w=Object.defineProperty;var i=(e,t)=>w(e,"name",{value:t,configurable:!0});import{closeSync as E,constants as $,fstatSync as A,readSync as S}from"node:fs";import{isAbsolute as _}from"node:path";import{ApiError as a}from"../../../api/index.js";import{notFound as q,usage as c}from"../../../core/errors.js";import{InputError as B}from"../../../core/io.js";import{RunError as m}from"../../../core/runs/operations.js";import{isBeneathRefusal as T,listBeneath as L,openBeneath as R,writeFileBeneath as I}from"../../../core/spaces/open-beneath.js";import{fileRoot as z}from"../../../core/spaces/permissions.js";import{resolvedScopes as F}from"../router.js";const p=512*1024,g=1024*1024,M=1e3;function y(e,t){if(e===null||e==="")throw c(`a file ${t} requires a \`path\` ${t==="write"?"body field":"query param"}`);if(!_(e))throw c(`file ${t} path must be absolute`,{received:e});return e}i(y,"requireAbsolutePath");function b(e){if(e==null)return"utf8";if(e==="utf8"||e==="base64")return e;throw c("encoding must be `utf8` or `base64`",{received:e})}i(b,"parseEncoding");function u(e,t,r){if(e instanceof a||e instanceof B||e instanceof m)throw e;if(T(e))throw new m(400,"invalid_request",`${t} meets a symlink, leaves its permitted root, or is not a regular file`,"path");const n=e.code;throw n==="ENOENT"?q(`no such file: ${t}`,{received:t}):n==="EACCES"||n==="EPERM"?new a(403,"forbidden",`permission denied ${r} ${t}`):new a(500,"internal",`cannot ${r} ${t}: ${e instanceof Error?e.message:String(e)}`)}i(u,"mapFilesystemError");function h(e,t,r){const n=e.principal,o=n.class==="person"?null:n.class==="app"?{app:n.app,resolved:n.scopes,launched:null}:{app:n.app,resolved:F(n),launched:n.scopes},s=z(o,t,r);if("root"in s)return s.root;throw new m(403,"scope_missing",s.missing?`missing scope ${s.missing}`:`no permission names ${t}`,void 0,void 0,s.missing??void 0)}i(h,"rootFor");function k(e,t,r){let n;try{n=R(e,t,$.O_RDONLY)}catch(o){return u(o,t,"reading")}try{const o=A(n);if(o.isDirectory())throw c(`file peek path is a directory: ${t}`,{received:t});const s=Buffer.allocUnsafe(Math.min(o.size,p)+1),d=S(n,s,0,s.length,0),l=d>p,f=s.subarray(0,Math.min(d,p)).toString(r);return{path:t,content:f,truncated:l}}catch(o){return u(o,t,"reading")}finally{E(n)}}i(k,"readHead");function N(e){const t=y(e.query.get("path"),"peek");return{status:200,body:k(h(e,t,"read"),t,b(e.query.get("encoding")))}}i(N,"handlePeek");function O(e){return e.length%4===0&&/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(e)}i(O,"isBase64");function P(e){if(typeof e!="object"||e===null||Array.isArray(e))throw c("file write requires an object body");const t=e,r=y(typeof t.path=="string"?t.path:null,"write");if(typeof t.content!="string")throw c("file write requires a string `content` body field");const n=b(t.encoding);if(n==="base64"&&!O(t.content))throw c("base64 file content must be valid base64");return{path:r,content:t.content,encoding:n}}i(P,"parseWriteBody");function v(e,t,r){if(r.byteLength>g)throw new a(413,"file_too_large",`file content exceeds the ${g} byte limit`);try{return I(e,t,r,{mode:process.platform==="linux"?432:384,atomic:!0}),{path:t,bytes_written:r.byteLength}}catch(n){return u(n,t,"writing")}}i(v,"writeAtomically");function D(e){const{path:t,content:r,encoding:n}=P(e.body);return{status:200,body:v(h(e,t,"rw"),t,Buffer.from(r,n))}}i(D,"handleWrite");function W(e){if(e===null)return M;const t=Number(e);if(!Number.isInteger(t)||t<1)throw c("file list limit must be a positive integer",{received:e});return t}i(W,"parseLimit");function Y(e){const t=y(e.query.get("path"),"list"),r=W(e.query.get("limit")),n=h(e,t,"read");let o;try{o=L(n,t,r+1)}catch(l){return u(l,t,"listing")}const s=o.slice(0,r).map(({name:l,stat:f})=>({name:l,type:f.isFile()?"file":f.isDirectory()?"dir":"other",size:f.size,modified:f.mtime.toISOString()}));return{status:200,body:{path:t,entries:s,truncated:o.length>r}}}i(Y,"handleList");const V=[{method:"GET",pattern:"/v1/files/peek",scope:"crtr:act",handler:N},{method:"POST",pattern:"/v1/files/write",scope:"crtr:act",handler:D},{method:"GET",pattern:"/v1/files/list",scope:"crtr:act",handler:Y}];export{V as fileRoutes};
@@ -1,4 +1,4 @@
1
- var u=Object.defineProperty;var e=(o,t)=>u(o,"name",{value:t,configurable:!0});import{openDb as n}from"../../../core/canvas/db.js";import{apiSocketPath as i}from"../../../core/canvas/paths.js";import{currentVersion as c}from"../../../core/self-update.js";import{API_VERSION as p}from"../../../api/index.js";import{DEFAULT_INTERVAL_MS as d}from"../../supervise-cadence.js";import{isPidAlive as l}from"../../../core/canvas/pid.js";import{boundDaemonControl as s}from"../../control.js";const _=d;function a(){try{return n().prepare("SELECT 1 FROM nodes LIMIT 1").get(),!0}catch{return!1}}e(a,"canvasAccessible");function m(){const o={},t=n().prepare(`
1
+ var u=Object.defineProperty;var e=(o,t)=>u(o,"name",{value:t,configurable:!0});import{openDb as n}from"../../../core/canvas/db.js";import{apiSocketPath as c}from"../../../core/canvas/paths.js";import{currentVersion as i}from"../../../core/self-update.js";import{API_VERSION as p}from"../../../api/index.js";import{DEFAULT_INTERVAL_MS as d}from"../../supervise-cadence.js";import{isPidPresent as l}from"../../../core/canvas/pid.js";import{boundDaemonControl as s}from"../../control.js";const _=d;function a(){try{return n().prepare("SELECT 1 FROM nodes LIMIT 1").get(),!0}catch{return!1}}e(a,"canvasAccessible");function m(){const o={},t=n().prepare(`
2
2
  SELECT status, COUNT(*) AS count
3
3
  FROM node_rows
4
4
  WHERE node_id NOT IN (SELECT node_id FROM warm_pool)
@@ -11,4 +11,4 @@ var u=Object.defineProperty;var e=(o,t)=>u(o,"name",{value:t,configurable:!0});i
11
11
  AND pi_pid IS NOT NULL
12
12
  AND turn_open_at IS NOT NULL
13
13
  AND turn_closed_at IS NULL
14
- `).all().filter(t=>l(t.pi_pid)).length}e(h,"busyNodeCount");function E(){const o=a(),t=s()?.startupBlock()??null,r={ok:o&&t===null,daemon_up:!0,store_accessible:o,brokers_reconciled:t===null,startup_phase:t?.phase??"ready",...t===null?{}:{startup_blocked:t.message}};return{status:r.ok?200:503,body:r}}e(E,"handleHealthz");function f(o){if(!a())throw{status:503,code:"store_unavailable",message:"canvas store is inaccessible"};return{status:200,body:{daemon_pid:process.pid,tick_interval_ms:_,node_counts:m(),busy_node_count:h(),listeners:{socket_path:i(),tcp:o()},runtime_version:c(),api_version:p,startup_phase:s()?.startupBlock()?.phase??"ready"}}}e(f,"handleStatus");function R(o){return[{method:"GET",pattern:"/healthz",handler:e(t=>E(),"handler")},{method:"GET",pattern:"/v1/status",handler:e(t=>f(o),"handler")}]}e(R,"healthRoutes");export{R as healthRoutes};
14
+ `).all().filter(t=>l(t.pi_pid)).length}e(h,"busyNodeCount");function E(){const o=a(),t=s()?.startupBlock()??null,r={ok:o&&t===null,daemon_up:!0,store_accessible:o,brokers_reconciled:t===null,startup_phase:t?.phase??"ready",...t===null?{}:{startup_blocked:t.message}};return{status:r.ok?200:503,body:r}}e(E,"handleHealthz");function f(o){if(!a())throw{status:503,code:"store_unavailable",message:"canvas store is inaccessible"};return{status:200,body:{daemon_pid:process.pid,tick_interval_ms:_,node_counts:m(),busy_node_count:h(),listeners:{socket_path:c(),tcp:o()},runtime_version:i(),api_version:p,startup_phase:s()?.startupBlock()?.phase??"ready"}}}e(f,"handleStatus");function A(o){return[{method:"GET",pattern:"/healthz",handler:e(t=>E(),"handler")},{method:"GET",pattern:"/v1/status",handler:e(t=>f(o),"handler")}]}e(A,"healthRoutes");export{A as healthRoutes};
@@ -0,0 +1,2 @@
1
+ import type { RouteTable } from '../router.js';
2
+ export declare const hookExecRoutes: RouteTable;
@@ -0,0 +1 @@
1
+ var v=Object.defineProperty;var u=(o,n)=>v(o,"name",{value:n,configurable:!0});import{realpathSync as q}from"node:fs";import{isAbsolute as y,relative as x,sep as E}from"node:path";import{ApiError as i}from"../../../api/index.js";import{coreHookCatalog as T}from"../../../build-root.js";import{getNode as O}from"../../../core/canvas/canvas.js";import{isSafeNodeId as P}from"../../../core/canvas/paths.js";import{discoverHookRegistry as I}from"../../../core/command-hooks/discovery.js";import{EXEC_HOOK_TIMEOUT_MS as S}from"../../../core/command-hooks/transport/exec-invoke.js";import{buildAppProcessEnv as A}from"../../../core/runtime/spawn-env.js";import{compileLaunch as H}from"../../../core/spaces/mounts.js";import{appProcessSandboxed as N,launchAppProcess as M}from"../../../core/spaces/process.js";import{requireCurrentExecution as R}from"./broker-recovery.js";function _(o,n,t){const r=o.params.id;if(r===void 0?o.principal.class!=="person":!P(r)||o.principal.class!=="broker"||o.principal.node!==r)throw new i(403,"permission_error","hook execution requires its current node or the person");const e=r===void 0?null:O(r);if(r!==void 0&&!e)throw new i(404,"not_found","node not found");if(r!==void 0&&R(r,n),typeof t!="string"||!y(t))throw new i(400,"invalid_request","hook cwd must be absolute");if(!N())throw new i(400,"invalid_request","hook routes require the root launcher");let s;try{s=q(t)}catch(d){throw d.code==="ENOENT"?new i(400,"invalid_request","hook cwd does not exist"):d}if(e){const d=H({nodeId:r,app:o.principal.class==="broker"?o.principal.app:"app:terminal",sub:e.sub??"user:local",grantId:e.grant_id??null,scopes:e.scopes??null,command:[],env:{},auditMissing:u(()=>{},"auditMissing")}),h=u(a=>{const p=x(a,s);return p===""||p!==".."&&!p.startsWith(`..${E}`)&&!y(p)},"within");if(!d.mounts.some(a=>h(a.source)))throw new i(403,"permission_error","hook cwd is outside the node mounts")}return{id:r,node:e,cwd:s,app:e&&o.principal.class==="broker"?o.principal.app:"app:terminal"}}u(_,"checkedContext");async function g(o,n){const t=I(await T(),o,n);if(!t.valid)throw new i(422,"hook_registry_invalid","the effective hook registry is invalid");return t}u(g,"currentRegistry");async function B(o){const{node:n,cwd:t}=_(o,o.query.get("expected_execution_id"),o.query.get("cwd"));return{status:200,body:{hooks:(await g(t,n.profile_id??null)).hooks.filter(e=>e.plugin.scope==="user").map(e=>({id:e.id,plugin:e.plugin.name,target:e.target,phase:e.phase,op:e.op,description:e.description,effects:e.effects,declarationIndex:e.declarationIndex}))}}}u(B,"handleHookPlan");async function k(o){const n=o.body;if(!n||typeof n!="object"||Array.isArray(n))throw new i(400,"invalid_request","hook execution requires a JSON body");const t=n,{id:r,node:e,cwd:s,app:d}=_(o,t.expected_execution_id,t.cwd);if(typeof t.hook_id!="string"||typeof t.request!="string")throw new i(400,"invalid_request","hook execution requires hook_id and request");const a=(await g(s,e?.profile_id??null)).hooks.find(c=>c.id===t.hook_id);if(!a)throw new i(404,"hook_not_registered","hook id is not registered for this cwd");const p=A(s,e?.profile_id??null,d),f=await M({...r===void 0?{}:{nodeId:r},app:d,command:[a.executable,"--crtr-hook-protocol","1"],cwd:s,pluginRoot:a.plugin.root,env:p,stdin:t.request,stdoutBytes:10*1024*1024,stderrBytes:64*1024});let l,m=!1;try{const c=await Promise.race([f.completion,new Promise((C,w)=>{l=setTimeout(()=>{m=!0,f.stop().then(()=>w(new i(504,"hook_timeout","hook executable timed out")),b=>w(b))},S)})]);if(m)throw new i(504,"hook_timeout","hook executable timed out");if(c.stdoutTruncated)throw new i(502,"hook_output_limit","hook stdout exceeded the 10 MiB cap");return{status:200,body:{stdout:c.stdout,status:c.exitCode,signal:c.signal}}}finally{l&&clearTimeout(l)}}u(k,"handleHookExec");const V=[{method:"GET",pattern:"/v1/nodes/:id/hooks/plan",handler:B},{method:"POST",pattern:"/v1/nodes/:id/hooks/exec",handler:k},{method:"POST",pattern:"/v1/hooks/exec",handler:k}];export{V as hookExecRoutes};
@@ -1 +1 @@
1
- var R=Object.defineProperty;var o=(e,t)=>R(e,"name",{value:t,configurable:!0});import{statSync as j}from"node:fs";import{isAbsolute as E}from"node:path";import{ApiError as s}from"../../../api/index.js";import{readExternalActionDelivery as N}from"../../../core/canvas/deliveries.js";import{isSafeNodeId as P}from"../../../core/canvas/paths.js";import{getNode as x}from"../../../core/canvas/canvas.js";import{assertScope as T}from"../../../core/scopes.js";import{resolvePageComponents as C}from"../../../core/config.js";import{resolveHumanAction as I}from"../../../core/human-actions.js";import{HUMAN_ACTION_NAME_PATTERN as $}from"../../../core/human/action-binding.js";import{createPageRequest as D,getRequest as J}from"../../../core/human/requests.js";import{preparePageSource as F}from"../../../core/human/page-authoring.js";import{publishPage as M,validatePageTicketResponses as H}from"../../../core/human/tickets.js";import{cancelHumanTicket as L,resolvePageTicket as U}from"../../human/finish.js";import{inboxPageProjection as B}from"./inbox-page.js";const G=1e3,_=200,p={placement:"inline",inbox:!0,reply:!1},b=["sessionName","askedBy","emittedAt","profileName","nodeId"];function c(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}o(c,"isPlainObject");function l(e,t,n){for(const r of Object.keys(e))if(!t.includes(r))throw new s(400,"invalid_request",`unexpected field in ${n}: ${r}`)}o(l,"requireNoExtraKeys");function i(e){return new s(400,"invalid_request",e)}o(i,"invalid");function g(e){if(!c(e))throw i("`page` must be an object");if(l(e,["dialect","source"],"`page`"),e.dialect!=="jsx"&&e.dialect!=="html")throw i('`page.dialect` must be "jsx" or "html"');if(typeof e.source!="string"||e.source.trim()==="")throw i("`page.source` must be the authored page text");return{dialect:e.dialect,source:e.source}}o(g,"validatePage");function q(e,t){const n=e??t;if(n!=="inline"&&n!=="panel")throw i('`delivery.placement` must be "inline" or "panel"');return n}o(q,"validatePlacement");function K(e,t){if(e===void 0)return p;if(!c(e))throw i("`delivery` must be an object");l(e,["placement","inbox","reply"],"`delivery`");const n=e.inbox??p.inbox,r=e.reply??p.reply;if(typeof n!="boolean")throw i("`delivery.inbox` must be boolean");if(typeof r!="boolean")throw i("`delivery.reply` must be boolean");if(r&&t===null)throw i("`delivery.reply` requires `requester_node_id`");return{placement:q(e.placement,p.placement),inbox:n,reply:r}}o(K,"validateCreateDelivery");function X(e,t){if(e===void 0)return t;if(!c(e))throw i("`delivery` must be an object");return l(e,["placement"],"`delivery`"),{...t,placement:q(e.placement,t.placement)}}o(X,"validateReplaceDelivery");function z(e){if(e===void 0)return;if(!c(e))throw i("`source` must be an object");l(e,b,"`source`");const t={};for(const n of b){const r=e[n];if(r!==void 0){if(typeof r!="string"||r==="")throw i(`\`source.${n}\` must be a nonempty string`);t[n]=r}}return t}o(z,"validateSource");function V(e){if(typeof e!="string"||e==="")throw i("`creator_cwd` is required");if(!E(e))throw i("`creator_cwd` must be an absolute path");try{if(!j(e).isDirectory())throw i(`\`creator_cwd\` is not a directory: ${e}`)}catch(t){throw t instanceof s?t:i(`\`creator_cwd\` does not exist: ${e}`)}return e}o(V,"validateCreatorCwd");function Y(e){if(e!==void 0){if(!c(e))throw i("`action` must be an object");if(l(e,["name","payload"],"`action`"),typeof e.name!="string"||!$.test(e.name))throw i("`action.name` must be a declared action name");return{name:e.name,payload:e.payload??null}}}o(Y,"validateActionSelection");function Q(e){if(e==null)return null;if(typeof e!="string"||!P(e))throw i("`requester_node_id` must be a safe node id or null");return e}o(Q,"validateRequesterNodeId");function W(e){if(!c(e))throw i("request body is required");l(e,["page","delivery","source","requester_node_id","creator_cwd","action"],"the request body");const t=z(e.source),n=Q(e.requester_node_id),r=Y(e.action);return{page:g(e.page),delivery:K(e.delivery,n),...t===void 0?{}:{source:t},requesterNodeId:n,creatorCwd:V(e.creator_cwd),...r===void 0?{}:{action:r}}}o(W,"validateCreateRequest");function Z(e,t){if(!c(e))throw i("request body is required");return l(e,["page","delivery"],"the request body"),{page:g(e.page),delivery:X(e.delivery,t)}}o(Z,"validateReplaceRequest");function y(e,t,n){if(e!==void 0){if(typeof e!="string"||e.trim()===""||e.length>n)throw i(`\`${t}\` must be nonempty after trim and at most ${n} characters`);return e}}o(y,"optionalBoundedString");function ee(e){if(!c(e))throw i("request body is required");if(l(e,["responses","actor"],"the request body"),!c(e.responses))throw i("`responses` must be an object");const t=y(e.actor,"actor",_);return{responses:e.responses,...t===void 0?{}:{actor:t}}}o(ee,"validateRespondRequest");function te(e){if(e===void 0)return{};if(!c(e))throw i("request body must be an object");l(e,["reason","actor"],"the request body");const t=y(e.reason,"reason",G),n=y(e.actor,"actor",_);return{...t===void 0?{}:{reason:t},...n===void 0?{}:{actor:n}}}o(te,"validateSettleRequest");function m(e){const t=e.params.request_id;if(typeof t!="string"||t==="")throw i("request id is required");return t}o(m,"requestId");function f(e){const t=J(e);if(t===null||t.kind!=="page")throw new s(404,"not_found","no request with that id");return t}o(f,"requirePageRequest");function v(e){try{const t=JSON.parse(e.specification_json);if(!c(t))throw new Error("not an object");return t}catch{throw new s(500,"internal","the request specification could not be read")}}o(v,"manifest");function ne(e){if(e.result_json===null)return null;try{return JSON.parse(e.result_json)}catch{throw new s(500,"internal","the request result could not be read")}}o(ne,"terminalResult");function re(e){if(e.action_json===null)return null;try{const t=JSON.parse(e.action_json);if(t.schema!=="crtr.human-action-binding/v1"||typeof t.name!="string")throw new Error("invalid action");return t}catch{throw new s(500,"internal","the request action could not be read")}}o(re,"frozenAction");function oe(e){return e.state!=="settled"?"pending":e.outcome==="answered"?"answered":e.outcome==="dismissed"?"dismissed":"canceled"}o(oe,"requestState");function ie(e){if(e.action_delivery_id===null)return{state:"none",attempt:0};const t=N(`human-action:${e.inbox_ticket_id}`);if(t===null)return{state:"none",attempt:0};const n=t.state==="acknowledged"?"accepted":t.state==="permanent_failed"?"permanent_failed":t.state==="handed_off"?"running":"pending",r={state:n,attempt:t.attempts};return n==="pending"&&t.nextAttemptAt!==null&&(r.next_attempt_at=new Date(t.nextAttemptAt).toISOString()),t.acknowledgedAt!==null&&(r.accepted_at=new Date(t.acknowledgedAt).toISOString()),t.failedAt!==null&&(r.permanent_failed_at=new Date(t.failedAt).toISOString()),t.lastFailure!==null&&(r.last_failure=t.lastFailure),r}o(ie,"deliveryDetail");function h(e){const t=v(e),n=ne(e),r=oe(e),a={request_id:e.request_id,inbox_ticket_id:e.inbox_ticket_id,request_dir:e.request_dir,kind:e.kind,state:r,title:e.title,source:t.source??{},emitted_at:t.source?.emittedAt??e.created_at};e.subtitle!==null&&(a.subtitle=e.subtitle),e.kind==="page"&&(a.page=B(e)),n!==null&&(a.settled_at=e.settled_at??e.updated_at,n.kind==="page"&&r==="answered"&&(a.responses=n.responses),n.kind==="canceled"&&n.reason!==void 0&&(a.reason=n.reason),n.kind==="page"&&n.actor!==void 0&&(a.actor=n.actor),n.kind==="canceled"&&n.actor!==void 0&&(a.actor=n.actor));const u=re(e);return u!==null&&(a.action={name:u.name,payload:u.payload},a.delivery=ie(e)),a}o(h,"requestToDTO");function w(e,t,n,r){try{return F({dialect:e,document:t,source:n,delivery:r,productKinds:C()})}catch(a){throw i(a instanceof Error?a.message:"the page could not be prepared")}}o(w,"prepareOrReject");function ae(e){const t=W(e.body),n=t.requesterNodeId??t.source?.nodeId;if(n!=null){const d=x(n);d!==null&&T(d,"ask")}let r;if(t.action!==void 0){const d=I(t.action.name,t.creatorCwd);if("kind"in d){const O=d.kind==="unknown_action"?`no action named ${d.name} is declared from ${t.creatorCwd}`:`${d.name} is declared in ${d.configOrigin} but unusable: ${d.reason}`;throw new s(400,d.kind,O)}r=JSON.stringify({schema:"crtr.human-action-binding/v1",name:t.action.name,payload:t.action.payload,creatorCwd:t.creatorCwd,configOrigin:d.configOrigin,argv:d.argv,cwd:d.cwd})}const a=w(t.page.dialect,t.page.source,t.source,t.delivery),u=D({prepared:a,requester_node_id:t.requesterNodeId,...r===void 0?{}:{action_json:r}});return{status:201,body:{request_id:u.request_id,request_dir:u.request_dir,state:"pending",...t.action===void 0?{}:{action:{name:t.action.name}},delivery_state:"none"}}}o(ae,"handleCreate");function se(e){return{status:200,body:h(f(m(e)))}}o(se,"handleGet");function de(e){const t=f(m(e));if(t.state==="settled")throw new s(409,"already_settled","the request already has a terminal result");const n=v(t),r=Z(e.body,n.delivery),a=w(r.page.dialect,r.page.source,n.source,r.delivery);try{M(t.request_dir,a)}catch(u){throw u instanceof Error&&u.message===`page request is not open: ${t.request_id}`?new s(409,"already_settled","the request already has a terminal result"):u}return{status:200,body:h(f(t.request_id))}}o(de,"handleReplace");function S(e){return e instanceof s?e:e instanceof Error&&e.message.includes("unknown page request")?new s(404,"not_found","no request with that id"):e instanceof Error&&e.message==="page_has_no_response_lifecycle"?new s(409,"not_settleable","this request carries no response lifecycle"):new s(500,"internal","the request could not be settled")}o(S,"settlementError");function k(e){if(e.state==="settled")throw new s(409,"already_settled","the request already has a terminal result");if(!e.settleable)throw new s(409,"not_settleable","this request carries no response lifecycle")}o(k,"requireSettleable");async function ce(e){const t=f(m(e)),n=ee(e.body);k(t);try{H(t.request_dir,n.responses)}catch(r){throw i(r instanceof Error?r.message:"the response map is invalid")}try{await U(t.request_id,n.responses,n.actor===void 0?{}:{actor:n.actor})}catch(r){throw S(r)}return{status:200,body:h(f(t.request_id))}}o(ce,"handleRespond");async function A(e,t){const n=f(m(e)),r=te(e.body);k(n);try{await L(n.request_id,{...r,disposition:t})}catch(a){throw S(a)}return{status:200,body:h(f(n.request_id))}}o(A,"settle");const Oe=[{method:"POST",pattern:"/v1/human/requests",scope:"ask",handler:ae},{method:"GET",pattern:"/v1/human/requests/:request_id",handler:se},{method:"POST",pattern:"/v1/human/requests/:request_id/replace",handler:de},{method:"POST",pattern:"/v1/human/requests/:request_id/respond",handler:ce},{method:"POST",pattern:"/v1/human/requests/:request_id/dismiss",handler:o(e=>A(e,"dismissed"),"handler")},{method:"POST",pattern:"/v1/human/requests/:request_id/cancel",handler:o(e=>A(e,"canceled"),"handler")}];export{Oe as humanRequestRoutes};
1
+ var N=Object.defineProperty;var o=(e,t)=>N(e,"name",{value:t,configurable:!0});import{statSync as P}from"node:fs";import{isAbsolute as T}from"node:path";import{ApiError as s}from"../../../api/index.js";import{readExternalActionDelivery as C}from"../../../core/canvas/deliveries.js";import{isSafeNodeId as I}from"../../../core/canvas/paths.js";import{getNode as b}from"../../../core/canvas/canvas.js";import{assertScope as $}from"../../../core/scopes.js";import{resolvePageComponents as g}from"../../../core/config.js";import{resolveHumanAction as x}from"../../../core/human-actions.js";import{HUMAN_ACTION_NAME_PATTERN as D}from"../../../core/human/action-binding.js";import{createPageRequest as J,getRequest as F}from"../../../core/human/requests.js";import{preparePageSource as M}from"../../../core/human/page-authoring.js";import{publishPage as G,validatePageTicketResponses as H}from"../../../core/human/tickets.js";import{cancelHumanTicket as L,resolvePageTicket as U}from"../../human/finish.js";import{inboxPageProjection as B}from"./inbox-page.js";const K=1e3,q=200,m={placement:"inline",inbox:!0,reply:!1},v=["sessionName","askedBy","emittedAt","profileName","nodeId"];function c(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}o(c,"isPlainObject");function l(e,t,n){for(const r of Object.keys(e))if(!t.includes(r))throw new s(400,"invalid_request",`unexpected field in ${n}: ${r}`)}o(l,"requireNoExtraKeys");function i(e){return new s(400,"invalid_request",e)}o(i,"invalid");function w(e){if(!c(e))throw i("`page` must be an object");if(l(e,["dialect","source"],"`page`"),e.dialect!=="jsx"&&e.dialect!=="html")throw i('`page.dialect` must be "jsx" or "html"');if(typeof e.source!="string"||e.source.trim()==="")throw i("`page.source` must be the authored page text");return{dialect:e.dialect,source:e.source}}o(w,"validatePage");function S(e,t){const n=e??t;if(n!=="inline"&&n!=="panel")throw i('`delivery.placement` must be "inline" or "panel"');return n}o(S,"validatePlacement");function X(e,t){if(e===void 0)return m;if(!c(e))throw i("`delivery` must be an object");l(e,["placement","inbox","reply"],"`delivery`");const n=e.inbox??m.inbox,r=e.reply??m.reply;if(typeof n!="boolean")throw i("`delivery.inbox` must be boolean");if(typeof r!="boolean")throw i("`delivery.reply` must be boolean");if(r&&t===null)throw i("`delivery.reply` requires `requester_node_id`");return{placement:S(e.placement,m.placement),inbox:n,reply:r}}o(X,"validateCreateDelivery");function z(e,t){if(e===void 0)return t;if(!c(e))throw i("`delivery` must be an object");return l(e,["placement"],"`delivery`"),{...t,placement:S(e.placement,t.placement)}}o(z,"validateReplaceDelivery");function V(e){if(e===void 0)return;if(!c(e))throw i("`source` must be an object");l(e,v,"`source`");const t={};for(const n of v){const r=e[n];if(r!==void 0){if(typeof r!="string"||r==="")throw i(`\`source.${n}\` must be a nonempty string`);t[n]=r}}return t}o(V,"validateSource");function Y(e){if(typeof e!="string"||e==="")throw i("`creator_cwd` is required");if(!T(e))throw i("`creator_cwd` must be an absolute path");try{if(!P(e).isDirectory())throw i(`\`creator_cwd\` is not a directory: ${e}`)}catch(t){throw t instanceof s?t:i(`\`creator_cwd\` does not exist: ${e}`)}return e}o(Y,"validateCreatorCwd");function Q(e){if(e!==void 0){if(!c(e))throw i("`action` must be an object");if(l(e,["name","payload"],"`action`"),typeof e.name!="string"||!D.test(e.name))throw i("`action.name` must be a declared action name");return{name:e.name,payload:e.payload??null}}}o(Q,"validateActionSelection");function W(e){if(e==null)return null;if(typeof e!="string"||!I(e))throw i("`requester_node_id` must be a safe node id or null");return e}o(W,"validateRequesterNodeId");function Z(e){if(!c(e))throw i("request body is required");l(e,["page","delivery","source","requester_node_id","creator_cwd","action"],"the request body");const t=V(e.source),n=W(e.requester_node_id),r=Q(e.action);return{page:w(e.page),delivery:X(e.delivery,n),...t===void 0?{}:{source:t},requesterNodeId:n,creatorCwd:Y(e.creator_cwd),...r===void 0?{}:{action:r}}}o(Z,"validateCreateRequest");function ee(e,t){if(!c(e))throw i("request body is required");return l(e,["page","delivery"],"the request body"),{page:w(e.page),delivery:z(e.delivery,t)}}o(ee,"validateReplaceRequest");function _(e,t,n){if(e!==void 0){if(typeof e!="string"||e.trim()===""||e.length>n)throw i(`\`${t}\` must be nonempty after trim and at most ${n} characters`);return e}}o(_,"optionalBoundedString");function te(e){if(!c(e))throw i("request body is required");if(l(e,["responses","actor"],"the request body"),!c(e.responses))throw i("`responses` must be an object");const t=_(e.actor,"actor",q);return{responses:e.responses,...t===void 0?{}:{actor:t}}}o(te,"validateRespondRequest");function ne(e){if(e===void 0)return{};if(!c(e))throw i("request body must be an object");l(e,["reason","actor"],"the request body");const t=_(e.reason,"reason",K),n=_(e.actor,"actor",q);return{...t===void 0?{}:{reason:t},...n===void 0?{}:{actor:n}}}o(ne,"validateSettleRequest");function h(e){const t=e.params.request_id;if(typeof t!="string"||t==="")throw i("request id is required");return t}o(h,"requestId");function f(e){const t=F(e);if(t===null||t.kind!=="page")throw new s(404,"not_found","no request with that id");return t}o(f,"requirePageRequest");function A(e){try{const t=JSON.parse(e.specification_json);if(!c(t))throw new Error("not an object");return t}catch{throw new s(500,"internal","the request specification could not be read")}}o(A,"manifest");function re(e){if(e.result_json===null)return null;try{return JSON.parse(e.result_json)}catch{throw new s(500,"internal","the request result could not be read")}}o(re,"terminalResult");function oe(e){if(e.action_json===null)return null;try{const t=JSON.parse(e.action_json);if(t.schema!=="crtr.human-action-binding/v1"||typeof t.name!="string")throw new Error("invalid action");return t}catch{throw new s(500,"internal","the request action could not be read")}}o(oe,"frozenAction");function ie(e){return e.state!=="settled"?"pending":e.outcome==="answered"?"answered":e.outcome==="dismissed"?"dismissed":"canceled"}o(ie,"requestState");function ae(e){if(e.action_delivery_id===null)return{state:"none",attempt:0};const t=C(`human-action:${e.inbox_ticket_id}`);if(t===null)return{state:"none",attempt:0};const n=t.state==="acknowledged"?"accepted":t.state==="permanent_failed"?"permanent_failed":t.state==="handed_off"?"running":"pending",r={state:n,attempt:t.attempts};return n==="pending"&&t.nextAttemptAt!==null&&(r.next_attempt_at=new Date(t.nextAttemptAt).toISOString()),t.acknowledgedAt!==null&&(r.accepted_at=new Date(t.acknowledgedAt).toISOString()),t.failedAt!==null&&(r.permanent_failed_at=new Date(t.failedAt).toISOString()),t.lastFailure!==null&&(r.last_failure=t.lastFailure),r}o(ae,"deliveryDetail");function y(e){const t=A(e),n=re(e),r=ie(e),a={request_id:e.request_id,inbox_ticket_id:e.inbox_ticket_id,request_dir:e.request_dir,kind:e.kind,state:r,title:e.title,source:t.source??{},emitted_at:t.source?.emittedAt??e.created_at};e.subtitle!==null&&(a.subtitle=e.subtitle),e.kind==="page"&&(a.page=B(e)),n!==null&&(a.settled_at=e.settled_at??e.updated_at,n.kind==="page"&&r==="answered"&&(a.responses=n.responses),n.kind==="canceled"&&n.reason!==void 0&&(a.reason=n.reason),n.kind==="page"&&n.actor!==void 0&&(a.actor=n.actor),n.kind==="canceled"&&n.actor!==void 0&&(a.actor=n.actor));const u=oe(e);return u!==null&&(a.action={name:u.name,payload:u.payload},a.delivery=ae(e)),a}o(y,"requestToDTO");function k(e,t,n,r){try{return M({dialect:e,document:t,source:n,delivery:r,productKinds:g()})}catch(a){throw i(a instanceof Error?a.message:"the page could not be prepared")}}o(k,"prepareOrReject");function se(e){const t=Z(e.body),n=t.requesterNodeId??t.source?.nodeId;if(n!=null){const d=b(n);d!==null&&$(d,"crtr:act")}let r;if(t.action!==void 0){const d=x(t.action.name,t.creatorCwd);if("kind"in d){const E=d.kind==="unknown_action"?`no action named ${d.name} is declared from ${t.creatorCwd}`:`${d.name} is declared in ${d.configOrigin} but unusable: ${d.reason}`;throw new s(400,d.kind,E)}const p=n==null?null:b(n);if(n&&!p)throw new s(404,"not_found","action requester node not found");if(p&&e.principal.class!=="person"&&p.grantee!==e.principal.app)throw new s(403,"permission_error","action requester belongs to another app");r=JSON.stringify({schema:"crtr.human-action-binding/v1",name:t.action.name,payload:t.action.payload,creatorCwd:t.creatorCwd,configOrigin:d.configOrigin,argv:d.argv,cwd:d.cwd,app:p?.grantee??(e.principal.class==="broker"?e.principal.app:"app:terminal")})}const a=k(t.page.dialect,t.page.source,t.source,t.delivery),u=J({prepared:a,requester_node_id:t.requesterNodeId,...r===void 0?{}:{action_json:r}});return{status:201,body:{request_id:u.request_id,request_dir:u.request_dir,state:"pending",...t.action===void 0?{}:{action:{name:t.action.name}},delivery_state:"none"}}}o(se,"handleCreate");function de(e){return{status:200,body:y(f(h(e)))}}o(de,"handleGet");function ce(e){const t=f(h(e));if(t.state==="settled")throw new s(409,"already_settled","the request already has a terminal result");const n=A(t),r=ee(e.body,n.delivery),a=k(r.page.dialect,r.page.source,n.source,r.delivery);try{G(t.request_dir,a)}catch(u){throw u instanceof Error&&u.message===`page request is not open: ${t.request_id}`?new s(409,"already_settled","the request already has a terminal result"):u}return{status:200,body:y(f(t.request_id))}}o(ce,"handleReplace");function O(e){return e instanceof s?e:e instanceof Error&&e.message.includes("unknown page request")?new s(404,"not_found","no request with that id"):e instanceof Error&&e.message==="page_has_no_response_lifecycle"?new s(409,"not_settleable","this request carries no response lifecycle"):new s(500,"internal","the request could not be settled")}o(O,"settlementError");function R(e){if(e.state==="settled")throw new s(409,"already_settled","the request already has a terminal result");if(!e.settleable)throw new s(409,"not_settleable","this request carries no response lifecycle")}o(R,"requireSettleable");async function ue(e){const t=f(h(e)),n=te(e.body);R(t);try{H(t.request_dir,n.responses)}catch(r){throw i(r instanceof Error?r.message:"the response map is invalid")}try{await U(t.request_id,n.responses,n.actor===void 0?{}:{actor:n.actor})}catch(r){throw O(r)}return{status:200,body:y(f(t.request_id))}}o(ue,"handleRespond");async function j(e,t){const n=f(h(e)),r=ne(e.body);R(n);try{await L(n.request_id,{...r,disposition:t})}catch(a){throw O(a)}return{status:200,body:y(f(n.request_id))}}o(j,"settle");function le(){return{status:200,body:{components:[...g()]}}}o(le,"handleComponents");const je=[{method:"GET",pattern:"/v1/human/components",handler:o(()=>le(),"handler")},{method:"POST",pattern:"/v1/human/requests",scope:"crtr:act",handler:se},{method:"GET",pattern:"/v1/human/requests/:request_id",handler:de},{method:"POST",pattern:"/v1/human/requests/:request_id/replace",handler:ce},{method:"POST",pattern:"/v1/human/requests/:request_id/respond",handler:ue},{method:"POST",pattern:"/v1/human/requests/:request_id/dismiss",handler:o(e=>j(e,"dismissed"),"handler")},{method:"POST",pattern:"/v1/human/requests/:request_id/cancel",handler:o(e=>j(e,"canceled"),"handler")}];export{je as humanRequestRoutes};
@@ -1 +1 @@
1
- var _=Object.defineProperty;var r=(e,t)=>_(e,"name",{value:t,configurable:!0});import{ApiError as n}from"../../../api/index.js";import{inboxPageProjection as b}from"./inbox-page.js";import{getRequestByInboxTicket as w}from"../../../core/human/requests.js";import{parsePage as m}from"../../../core/human/page.js";import{scanInbox as g,scanPageHistory as v}from"../../../core/human/scan.js";import{readPageTicket as u,readTicketResult as p,selectedPageDir as y,validatePageTicketResponses as q,writePageProgress as T}from"../../../core/human/tickets.js";import{describePageAnswer as I}from"../../../core/human/answer.js";import{cancelHumanTicket as x,resolvePageTicket as A}from"../../human/finish.js";const P="Canceled from the inbox.",E=1e3,R=/^[a-f0-9]{64}$/;function d(e){const t=w(e);return t===null?null:{ticketId:t.request_id,dir:t.request_dir,kind:t.kind}}r(d,"resolveTicket");function c(e){const t=e.ticket_id;if(t===void 0||!R.test(t))throw new n(400,"invalid_request","invalid ticket id");return t}r(c,"requireTicketId");function l(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}r(l,"isPlainObject");function h(e,t){for(const i of Object.keys(e))if(!t.includes(i))throw new n(400,"invalid_request",`unexpected field: ${i}`)}r(h,"requireNoExtraKeys");function O(e){if(!l(e))throw new n(400,"invalid_request","respond body is required");if(h(e,["responses"]),!l(e.responses))throw new n(400,"invalid_request","`responses` must be an object");return{responses:e.responses}}r(O,"validateRespondRequest");function S(e){if(!l(e))throw new n(400,"invalid_request","progress body is required");if(h(e,["responses"]),!l(e.responses))throw new n(400,"invalid_request","`responses` must be an object");return{responses:e.responses}}r(S,"validateProgressRequest");function C(e){if(e===void 0)return{};if(!l(e))throw new n(400,"invalid_request","cancel body must be an object");if(h(e,["reason"]),e.reason===void 0)return{};const t=e.reason;if(typeof t!="string")throw new n(400,"invalid_request","`reason` must be a string");if(t.trim()===""||t.length>E)throw new n(400,"invalid_request","`reason` must be nonempty after trim and at most 1000 characters");return{reason:t}}r(C,"validateCancelRequest");const D=[/^slot ".*?" /,/^response names unknown or non-response-bearing slot id/,/^final page response is missing response-bearing slot id/];function k(e){return e instanceof Error&&D.some(t=>t.test(e.message))}r(k,"isSlotValidationError");function f(e){const t={request_id:e.id,request_dir:e.dir,ticket_id:e.inboxTicketId,kind:"page",title:e.title,placement:e.placement,dialect:e.dialect,steps:e.steps,emitted_at:e.emittedAt,source:e.source,slot_kinds:e.slotKinds,inbox:e.inbox,awaits_response:e.awaitsResponse,state:e.state};return e.subtitle!==""&&(t.subtitle=e.subtitle),e.answerDigest!==void 0&&(t.answer_digest=e.answerDigest),e.recommendedOptions.length>0&&(t.recommended_options=e.recommendedOptions.map(i=>({slot_id:i.slotId,option_id:i.optionId,label:i.label}))),e.fastAction!==void 0&&(t.fast_action={kind:e.fastAction.kind,responses:e.fastAction.responses}),t}r(f,"pageSummaryToDTO");function N(){return{status:200,body:{tickets:g().map(t=>{if(t.kind==="page")return f(t);if(t.kind==="review")return{request_id:t.id,request_dir:t.dir,ticket_id:t.inboxTicketId,kind:"review",title:t.title,subtitle:t.subtitle,blocked_since:t.blockedSince,source:t.source};throw new Error(`unknown ticket kind: ${t.kind}`)}).sort((t,i)=>{const s=r(a=>a.kind==="page"?a.emitted_at:a.blocked_since,"pageTime"),o=Date.parse(s(i))-Date.parse(s(t));return o!==0?o:t.ticket_id.localeCompare(i.ticket_id)})}}}r(N,"handleList");function j(e){const t=e.query.get("node_id");if(t==="")throw new n(400,"invalid_request","node_id must be nonempty when present");return{status:200,body:{tickets:v(t??void 0).map(f)}}}r(j,"handleHistory");function G(e){const t=c(e.params),i=d(t);if(i===null)throw new n(404,"ticket_not_found","no matching ticket");if(i.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets have no page read operation");const s=w(t);if(s===null||s.kind!=="page")throw new n(404,"ticket_not_found","no matching ticket");try{return{status:200,body:b(s)}}catch{throw new n(500,"internal","the ticket could not be read")}}r(G,"handleGetPage");async function L(e){const t=c(e.params),i=O(e.body),s=d(t);if(s===null)throw new n(404,"ticket_not_found","no matching ticket");if(s.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets submit through their own path");if(u(s.dir).state==="passive")throw new n(409,"page_has_no_response_lifecycle","this page has no response lifecycle");const o=p(s.dir);if(o!==null&&o.kind!=="canceled")throw new n(409,"ticket_already_resolved","ticket was already resolved");if(o?.kind==="canceled")throw new n(409,"ticket_canceled","canceled tickets cannot be answered");try{q(s.dir,i.responses)}catch(a){throw k(a)?new n(400,"invalid_ticket_response",a.message):new n(500,"internal","validation failed")}try{const a=await A(s.ticketId,i.responses);if(a.kind!=="page")throw new n(409,"ticket_kind_mismatch","unexpected result kind");return{status:200,body:a}}catch(a){throw a instanceof n?a:k(a)?new n(400,"invalid_ticket_response",a.message):new n(500,"internal","the ticket could not be finalized")}}r(L,"handleRespond");function H(e){const t=c(e.params),i=S(e.body),s=d(t);if(s===null)throw new n(404,"ticket_not_found","no matching ticket");if(s.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets do not support progress autosave");if(u(s.dir).state==="passive")throw new n(409,"page_has_no_response_lifecycle","this page has no response lifecycle");const o=p(s.dir);if(o!==null&&o.kind!=="canceled")throw new n(409,"ticket_already_resolved","ticket was already resolved");try{return T(s.dir,i.responses),{status:200,body:{}}}catch(a){throw k(a)?new n(400,"invalid_ticket_response",a.message):new n(500,"internal","progress could not be saved")}}r(H,"handleProgress");async function K(e){const t=c(e.params),i=C(e.body),s=d(t);if(s===null)throw new n(404,"ticket_not_found","no matching ticket");if(s.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets have their own cancel path");if(u(s.dir).state==="passive")throw new n(409,"page_has_no_response_lifecycle","this page has no response lifecycle");try{const o=await x(s.ticketId,{reason:i.reason??P,actor:"human",disposition:"dismissed"});if(o.outcome==="already_settled"||o.result.kind!=="canceled")throw new n(409,"ticket_already_resolved","ticket was already resolved");return{status:200,body:o.result}}catch(o){throw o instanceof n?o:new n(500,"internal","the ticket could not be canceled")}}r(K,"handleCancel");function $(e){const t=c(e.params),i=d(t);if(i===null)throw new n(404,"ticket_not_found","no matching ticket");if(i.kind==="review")throw new n(409,"ticket_kind_unsupported","review tickets fetch responses through their own path");const s=p(i.dir);if(s===null)throw new n(404,"ticket_pending","ticket has no response yet");if(s.kind==="canceled")throw new n(404,"ticket_canceled","canceled tickets have no response");if(s.kind!=="page")throw new n(409,"ticket_kind_mismatch","unexpected result kind");try{const o=m(y(i.dir));return{status:200,body:{...s,answer:I(o,s.responses,{completedAt:s.completedAt})}}}catch{throw new n(500,"internal","the ticket answer could not be read")}}r($,"handleGetResponse");const W=[{method:"GET",pattern:"/v1/human/inbox",handler:N},{method:"GET",pattern:"/v1/human/inbox/history",handler:j},{method:"GET",pattern:"/v1/human/inbox/:ticket_id",handler:G},{method:"GET",pattern:"/v1/human/inbox/:ticket_id/response",handler:$},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/respond",handler:L},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/progress",handler:H},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/cancel",handler:K}];export{W as inboxRoutes,c as requireTicketId,d as resolveTicket};
1
+ var g=Object.defineProperty;var a=(e,n)=>g(e,"name",{value:n,configurable:!0});import{ApiError as t}from"../../../api/index.js";import{inboxPageProjection as v}from"./inbox-page.js";import{getRequestByInboxTicket as p}from"../../../core/human/requests.js";import{getNode as _}from"../../../core/canvas/canvas.js";import{canReadNode as m}from"../router.js";import{parsePage as y}from"../../../core/human/page.js";import{scanInbox as q,scanPageHistory as T}from"../../../core/human/scan.js";import{readPageTicket as h,readTicketResult as k,selectedPageDir as I,validatePageTicketResponses as A,writePageProgress as P}from"../../../core/human/tickets.js";import{describePageAnswer as x}from"../../../core/human/answer.js";import{cancelHumanTicket as E,resolvePageTicket as R}from"../../human/finish.js";const O="Canceled from the inbox.",N=1e3,S=/^[a-f0-9]{64}$/;function c(e){const n=p(e);return n===null?null:{ticketId:n.request_id,dir:n.request_dir,kind:n.kind}}a(c,"resolveTicket");function l(e){const n=e.ticket_id;if(n===void 0||!S.test(n))throw new t(400,"invalid_request","invalid ticket id");return n}a(l,"requireTicketId");function u(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}a(u,"isPlainObject");function f(e,n){for(const r of Object.keys(e))if(!n.includes(r))throw new t(400,"invalid_request",`unexpected field: ${r}`)}a(f,"requireNoExtraKeys");function C(e){if(!u(e))throw new t(400,"invalid_request","respond body is required");if(f(e,["responses"]),!u(e.responses))throw new t(400,"invalid_request","`responses` must be an object");return{responses:e.responses}}a(C,"validateRespondRequest");function D(e){if(!u(e))throw new t(400,"invalid_request","progress body is required");if(f(e,["responses"]),!u(e.responses))throw new t(400,"invalid_request","`responses` must be an object");return{responses:e.responses}}a(D,"validateProgressRequest");function j(e){if(e===void 0)return{};if(!u(e))throw new t(400,"invalid_request","cancel body must be an object");if(f(e,["reason"]),e.reason===void 0)return{};const n=e.reason;if(typeof n!="string")throw new t(400,"invalid_request","`reason` must be a string");if(n.trim()===""||n.length>N)throw new t(400,"invalid_request","`reason` must be nonempty after trim and at most 1000 characters");return{reason:n}}a(j,"validateCancelRequest");const G=[/^slot ".*?" /,/^response names unknown or non-response-bearing slot id/,/^final page response is missing response-bearing slot id/];function w(e){return e instanceof Error&&G.some(n=>n.test(e.message))}a(w,"isSlotValidationError");function b(e){const n={request_id:e.id,request_dir:e.dir,ticket_id:e.inboxTicketId,kind:"page",title:e.title,placement:e.placement,dialect:e.dialect,steps:e.steps,emitted_at:e.emittedAt,source:e.source,slot_kinds:e.slotKinds,inbox:e.inbox,awaits_response:e.awaitsResponse,state:e.state};return e.subtitle!==""&&(n.subtitle=e.subtitle),e.answerDigest!==void 0&&(n.answer_digest=e.answerDigest),e.recommendedOptions.length>0&&(n.recommended_options=e.recommendedOptions.map(r=>({slot_id:r.slotId,option_id:r.optionId,label:r.label}))),e.fastAction!==void 0&&(n.fast_action={kind:e.fastAction.kind,responses:e.fastAction.responses}),n}a(b,"pageSummaryToDTO");function L(e){return{status:200,body:{tickets:q().filter(r=>{if(e.principal.class==="person")return!0;const i=p(r.inboxTicketId),s=i?.requester_node_id?_(i.requester_node_id):null;return s!==null&&m(e.principal,s.grantee??"app:terminal")}).map(r=>{if(r.kind==="page")return b(r);if(r.kind==="review")return{request_id:r.id,request_dir:r.dir,ticket_id:r.inboxTicketId,kind:"review",title:r.title,subtitle:r.subtitle,blocked_since:r.blockedSince,source:r.source};throw new Error(`unknown ticket kind: ${r.kind}`)}).sort((r,i)=>{const s=a(d=>d.kind==="page"?d.emitted_at:d.blocked_since,"pageTime"),o=Date.parse(s(i))-Date.parse(s(r));return o!==0?o:r.ticket_id.localeCompare(i.ticket_id)})}}}a(L,"handleList");function H(e){const n=e.query.get("node_id");if(n==="")throw new t(400,"invalid_request","node_id must be nonempty when present");return{status:200,body:{tickets:T(n??void 0).filter(s=>{if(e.principal.class==="person")return!0;const o=p(s.inboxTicketId),d=o?.requester_node_id?_(o.requester_node_id):null;return d!==null&&m(e.principal,d.grantee??"app:terminal")}).map(b)}}}a(H,"handleHistory");function K(e){const n=l(e.params),r=c(n);if(r===null)throw new t(404,"ticket_not_found","no matching ticket");if(r.kind==="review")throw new t(409,"ticket_kind_unsupported","review tickets have no page read operation");const i=p(n);if(i===null||i.kind!=="page")throw new t(404,"ticket_not_found","no matching ticket");try{return{status:200,body:v(i)}}catch{throw new t(500,"internal","the ticket could not be read")}}a(K,"handleGetPage");async function $(e){const n=l(e.params),r=C(e.body),i=c(n);if(i===null)throw new t(404,"ticket_not_found","no matching ticket");if(i.kind==="review")throw new t(409,"ticket_kind_unsupported","review tickets submit through their own path");if(h(i.dir).state==="passive")throw new t(409,"page_has_no_response_lifecycle","this page has no response lifecycle");const s=k(i.dir);if(s!==null&&s.kind!=="canceled")throw new t(409,"ticket_already_resolved","ticket was already resolved");if(s?.kind==="canceled")throw new t(409,"ticket_canceled","canceled tickets cannot be answered");try{A(i.dir,r.responses)}catch(o){throw w(o)?new t(400,"invalid_ticket_response",o.message):new t(500,"internal","validation failed")}try{const o=await R(i.ticketId,r.responses);if(o.kind!=="page")throw new t(409,"ticket_kind_mismatch","unexpected result kind");return{status:200,body:o}}catch(o){throw o instanceof t?o:w(o)?new t(400,"invalid_ticket_response",o.message):new t(500,"internal","the ticket could not be finalized")}}a($,"handleRespond");function V(e){const n=l(e.params),r=D(e.body),i=c(n);if(i===null)throw new t(404,"ticket_not_found","no matching ticket");if(i.kind==="review")throw new t(409,"ticket_kind_unsupported","review tickets do not support progress autosave");if(h(i.dir).state==="passive")throw new t(409,"page_has_no_response_lifecycle","this page has no response lifecycle");const s=k(i.dir);if(s!==null&&s.kind!=="canceled")throw new t(409,"ticket_already_resolved","ticket was already resolved");try{return P(i.dir,r.responses),{status:200,body:{}}}catch(o){throw w(o)?new t(400,"invalid_ticket_response",o.message):new t(500,"internal","progress could not be saved")}}a(V,"handleProgress");async function z(e){const n=l(e.params),r=j(e.body),i=c(n);if(i===null)throw new t(404,"ticket_not_found","no matching ticket");if(i.kind==="review")throw new t(409,"ticket_kind_unsupported","review tickets have their own cancel path");if(h(i.dir).state==="passive")throw new t(409,"page_has_no_response_lifecycle","this page has no response lifecycle");try{const s=await E(i.ticketId,{reason:r.reason??O,actor:"human",disposition:"dismissed"});if(s.outcome==="already_settled"||s.result.kind!=="canceled")throw new t(409,"ticket_already_resolved","ticket was already resolved");return{status:200,body:s.result}}catch(s){throw s instanceof t?s:new t(500,"internal","the ticket could not be canceled")}}a(z,"handleCancel");function B(e){const n=l(e.params),r=c(n);if(r===null)throw new t(404,"ticket_not_found","no matching ticket");if(r.kind==="review")throw new t(409,"ticket_kind_unsupported","review tickets fetch responses through their own path");const i=k(r.dir);if(i===null)throw new t(404,"ticket_pending","ticket has no response yet");if(i.kind==="canceled")throw new t(404,"ticket_canceled","canceled tickets have no response");if(i.kind!=="page")throw new t(409,"ticket_kind_mismatch","unexpected result kind");try{const s=y(I(r.dir));return{status:200,body:{...i,answer:x(s,i.responses,{completedAt:i.completedAt})}}}catch{throw new t(500,"internal","the ticket answer could not be read")}}a(B,"handleGetResponse");const ne=[{method:"GET",pattern:"/v1/human/inbox",handler:L},{method:"GET",pattern:"/v1/human/inbox/history",handler:H},{method:"GET",pattern:"/v1/human/inbox/:ticket_id",handler:K},{method:"GET",pattern:"/v1/human/inbox/:ticket_id/response",handler:B},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/respond",handler:$},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/progress",handler:V},{method:"POST",pattern:"/v1/human/inbox/:ticket_id/cancel",handler:z}];export{ne as inboxRoutes,l as requireTicketId,c as resolveTicket};
@@ -0,0 +1,2 @@
1
+ import type { RouteTable } from '../router.js';
2
+ export declare const llmRoutes: RouteTable;
@@ -0,0 +1,3 @@
1
+ var f=Object.defineProperty;var i=(a,t)=>f(a,"name",{value:t,configurable:!0});import{randomUUID as p}from"node:crypto";import{parseLlmRequest as _,runLlm as y}from"../../../core/llm/run.js";import{RunError as n}from"../../../core/runs/operations.js";import{getNode as h}from"../../../core/canvas/canvas.js";import{socketPrincipal as b}from"../server.js";const R=[{method:"POST",pattern:"/v1/llm",scope:"crtr:llm",handler:i(async({body:a,res:t,req:c})=>{const s=p();t.setHeader("Request-Id",s);const l=new AbortController,d=i(()=>l.abort(),"abort");t.on("close",d);try{const e=_(a),r=b(c),o=r?.class==="broker"?h(r.node):null;if(r?.class==="broker"&&!o)throw new n(401,"unauthorized","node not found");const u=await y(e,l.signal,e.stream?m=>{t.headersSent||t.writeHead(200,{"content-type":"application/x-ndjson; charset=utf-8","cache-control":"no-cache"}),t.write(`${JSON.stringify(m)}
2
+ `)}:void 0,o?{cwd:o.cwd,profileId:o.profile_id??null}:void 0);return e.stream?(t.headersSent||t.writeHead(200,{"content-type":"application/x-ndjson; charset=utf-8","cache-control":"no-cache"}),t.end(),{status:200}):{status:200,body:u.completion}}catch(e){if(t.headersSent){const r=e instanceof n?e:new n(503,"model_unavailable","model stream failed");return t.end(`${JSON.stringify({error:{code:r.code,message:r.message,type:"server_error",origin:"runtime",retryable:r.retryable,request_id:s}})}
3
+ `),{status:200}}if(e instanceof n)return e.code==="all_routes_exhausted"&&t.setHeader("Retry-After",String(e.details.retry_after_s)),{status:e.status,body:{error:{code:e.code,message:e.message,...e.details===void 0?{}:{details:e.details},type:e.status===429?"rate_limit_error":e.status<500?"invalid_request_error":"server_error",...e.param?{param:e.param}:{},origin:"runtime",retryable:e.retryable,request_id:s,...e.code==="all_routes_exhausted"?{retry_after_s:e.details.retry_after_s}:{}}}};throw e}finally{t.off("close",d)}},"handler")}];export{R as llmRoutes};
@@ -0,0 +1,4 @@
1
+ import type { RouteTable } from '../router.js';
2
+ export declare const MAX_MEMORY_READ_EVENTS = 500;
3
+ export declare const MAX_MEMORY_READ_TEXT = 512;
4
+ export declare const memoryReadsRoutes: RouteTable;
@@ -0,0 +1 @@
1
+ var l=Object.defineProperty;var i=(e,t)=>l(e,"name",{value:t,configurable:!0});import{ApiError as f}from"../../../api/index.js";import{getNode as b}from"../../../core/canvas/canvas.js";import{insertMemoryReads as v}from"../../../core/canvas/memory-reads.js";const p=500,u=512,w=/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,3})?Z$/;function r(e){return new f(400,"invalid_request",e)}i(r,"invalid");function y(e,t,o){if(typeof e!="string"||e.length===0||e.length>u)throw r(`events[${o}].${t} must be a non-empty string of at most ${u} characters`);return e}i(y,"text");function g(e){if(typeof e!="object"||e===null||Array.isArray(e))throw r("body must be an object");const t=Object.keys(e).filter(n=>n!=="events");if(t.length>0)throw r(`unknown body field: ${t.join(", ")}`);const o=e.events;if(!Array.isArray(o)||o.length<1||o.length>p)throw r(`events must be an array of 1\u2013${p} events`);return o.map((n,a)=>{if(typeof n!="object"||n===null||Array.isArray(n))throw r(`events[${a}] must be an object`);const s=n,m=Object.keys(s).filter(h=>!["name","scope","at","type"].includes(h));if(m.length>0)throw r(`events[${a}] has unknown field: ${m.join(", ")}`);if(s.type!=="read"&&s.type!=="loaded")throw r(`events[${a}].type must be "read" or "loaded"`);const d=s.at,c=typeof d=="string"&&w.test(d)?Date.parse(d):Number.NaN;if(!Number.isFinite(c))throw r(`events[${a}].at must be an ISO UTC timestamp`);return{name:y(s.name,"name",a),scope:y(s.scope,"scope",a),at:new Date(c).toISOString(),type:s.type}})}i(g,"parseEvents");function A(e){const t=e.params.id??"",o=g(e.body),n=b(t);if(!n||n.kind==="human")throw new f(404,"not_found","node not found");return v(t,o),{status:204}}i(A,"handleMemoryReads");const M=[{method:"POST",pattern:"/v1/nodes/:id/memory-reads",handler:A}];export{p as MAX_MEMORY_READ_EVENTS,u as MAX_MEMORY_READ_TEXT,M as memoryReadsRoutes};