@north-light/cli 0.3.530 → 0.3.531

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (495) hide show
  1. package/dist/clients/attach/session/connection.js +1 -1
  2. package/dist/clients/attach/session/reconnect.js +1 -1
  3. package/dist/clients/attach/viewer.js +3 -3
  4. package/dist/core/async-array.d.ts +7 -0
  5. package/dist/core/async-array.js +1 -0
  6. package/dist/core/audit.d.ts +1 -1
  7. package/dist/core/audit.js +2 -2
  8. package/dist/core/canvas/attention.d.ts +4 -4
  9. package/dist/core/canvas/attention.js +1 -1
  10. package/dist/core/canvas/boot.d.ts +4 -4
  11. package/dist/core/canvas/boot.js +1 -1
  12. package/dist/core/canvas/canvas.d.ts +59 -59
  13. package/dist/core/canvas/canvas.js +19 -19
  14. package/dist/core/canvas/context-strip.js +2 -2
  15. package/dist/core/canvas/crons.d.ts +27 -27
  16. package/dist/core/canvas/crons.js +11 -11
  17. package/dist/core/canvas/daemon-actions.d.ts +10 -10
  18. package/dist/core/canvas/daemon-actions.js +8 -8
  19. package/dist/core/canvas/daemon-owner.d.ts +3 -3
  20. package/dist/core/canvas/daemon-owner.js +2 -2
  21. package/dist/core/canvas/db.d.ts +19 -30
  22. package/dist/core/canvas/db.js +3 -2
  23. package/dist/core/canvas/deliveries.d.ts +16 -16
  24. package/dist/core/canvas/deliveries.js +24 -24
  25. package/dist/core/canvas/executions.d.ts +8 -8
  26. package/dist/core/canvas/executions.js +1 -1
  27. package/dist/core/canvas/focuses.d.ts +8 -8
  28. package/dist/core/canvas/focuses.js +1 -1
  29. package/dist/core/canvas/history.d.ts +3 -3
  30. package/dist/core/canvas/history.js +9 -9
  31. package/dist/core/canvas/install-id.d.ts +1 -1
  32. package/dist/core/canvas/install-id.js +1 -1
  33. package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +1 -1
  34. package/dist/core/canvas/managed-worktree-sweep-candidates.js +2 -2
  35. package/dist/core/canvas/memory-reads.d.ts +6 -6
  36. package/dist/core/canvas/memory-reads.js +1 -1
  37. package/dist/core/canvas/nav-model.d.ts +13 -13
  38. package/dist/core/canvas/nav-model.js +1 -1
  39. package/dist/core/canvas/node-agent-paths.d.ts +6 -6
  40. package/dist/core/canvas/node-agent-paths.js +1 -1
  41. package/dist/core/canvas/node-tokens.d.ts +7 -7
  42. package/dist/core/canvas/node-tokens.js +3 -3
  43. package/dist/core/canvas/outcome-actions.d.ts +5 -5
  44. package/dist/core/canvas/outcome-actions.js +3 -3
  45. package/dist/core/canvas/recovery.d.ts +26 -26
  46. package/dist/core/canvas/recovery.js +2 -2
  47. package/dist/core/canvas/render-source.d.ts +1 -1
  48. package/dist/core/canvas/render-source.js +1 -1
  49. package/dist/core/canvas/sessions.d.ts +10 -10
  50. package/dist/core/canvas/sessions.js +4 -4
  51. package/dist/core/canvas/source.js +1 -1
  52. package/dist/core/canvas/structured-requests.d.ts +15 -15
  53. package/dist/core/canvas/structured-requests.js +5 -5
  54. package/dist/core/canvas/tree.d.ts +9 -9
  55. package/dist/core/canvas/tree.js +5 -5
  56. package/dist/core/canvas/waits.d.ts +13 -13
  57. package/dist/core/canvas/waits.js +6 -6
  58. package/dist/core/canvas/worktrees.d.ts +15 -15
  59. package/dist/core/canvas/worktrees.js +1 -1
  60. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  61. package/dist/core/conversation-store/file-store.d.ts +7 -7
  62. package/dist/core/conversation-store/file-store.js +9 -9
  63. package/dist/core/conversation-store/index.d.ts +16 -14
  64. package/dist/core/conversation-store/index.js +1 -1
  65. package/dist/core/conversation-store/listener.js +5 -5
  66. package/dist/core/conversation-store/patch.d.ts +3 -1
  67. package/dist/core/conversation-store/patch.js +1 -1
  68. package/dist/core/feed/feed.js +3 -3
  69. package/dist/core/feed/inbox.d.ts +2 -2
  70. package/dist/core/feed/inbox.js +1 -1
  71. package/dist/core/feed/messages.d.ts +11 -12
  72. package/dist/core/feed/messages.js +5 -5
  73. package/dist/core/feed/reports.d.ts +4 -4
  74. package/dist/core/feed/reports.js +2 -2
  75. package/dist/core/grants/cover.d.ts +1 -1
  76. package/dist/core/grants/cover.js +1 -1
  77. package/dist/core/grants/local.d.ts +1 -1
  78. package/dist/core/grants/local.js +1 -1
  79. package/dist/core/grants/mirror.d.ts +19 -19
  80. package/dist/core/grants/mirror.js +2 -2
  81. package/dist/core/grants/on-sync.d.ts +1 -1
  82. package/dist/core/grants/on-sync.js +1 -1
  83. package/dist/core/grants/remove.js +1 -1
  84. package/dist/core/grants/sync.js +1 -1
  85. package/dist/core/graph/access.d.ts +17 -17
  86. package/dist/core/graph/access.js +3 -3
  87. package/dist/core/graph/custom.d.ts +16 -16
  88. package/dist/core/graph/custom.js +9 -9
  89. package/dist/core/graph/deletion.d.ts +3 -7
  90. package/dist/core/graph/deletion.js +4 -4
  91. package/dist/core/graph/documents.d.ts +24 -27
  92. package/dist/core/graph/documents.js +7 -7
  93. package/dist/core/graph/edges.d.ts +13 -13
  94. package/dist/core/graph/edges.js +1 -1
  95. package/dist/core/graph/events.d.ts +7 -9
  96. package/dist/core/graph/events.js +8 -8
  97. package/dist/core/graph/exposures.d.ts +6 -6
  98. package/dist/core/graph/exposures.js +4 -4
  99. package/dist/core/graph/jobs.d.ts +6 -8
  100. package/dist/core/graph/jobs.js +2 -2
  101. package/dist/core/graph/kinds/action.js +1 -1
  102. package/dist/core/graph/kinds/custom.js +2 -2
  103. package/dist/core/graph/kinds/document.d.ts +1 -0
  104. package/dist/core/graph/kinds/document.js +4 -4
  105. package/dist/core/graph/kinds/dto.d.ts +2 -2
  106. package/dist/core/graph/kinds/dto.js +1 -1
  107. package/dist/core/graph/kinds/job.js +2 -2
  108. package/dist/core/graph/kinds/kind.d.ts +6 -8
  109. package/dist/core/graph/kinds/kind.js +1 -1
  110. package/dist/core/graph/kinds/node.js +5 -5
  111. package/dist/core/graph/kinds/owner.js +2 -2
  112. package/dist/core/graph/kinds/registry.d.ts +6 -9
  113. package/dist/core/graph/kinds/registry.js +1 -1
  114. package/dist/core/graph/names.d.ts +6 -6
  115. package/dist/core/graph/names.js +3 -3
  116. package/dist/core/graph/object-waits.d.ts +4 -7
  117. package/dist/core/graph/object-waits.js +1 -1
  118. package/dist/core/graph/objects.d.ts +14 -14
  119. package/dist/core/graph/objects.js +9 -9
  120. package/dist/core/graph/package-docs.d.ts +2 -7
  121. package/dist/core/graph/package-docs.js +5 -5
  122. package/dist/core/graph/package-kinds.d.ts +2 -5
  123. package/dist/core/graph/package-kinds.js +1 -1
  124. package/dist/core/graph/package-reconcile.d.ts +2 -5
  125. package/dist/core/graph/package-reconcile.js +1 -1
  126. package/dist/core/graph/reader.d.ts +18 -18
  127. package/dist/core/graph/reader.js +3 -3
  128. package/dist/core/graph/receivers.d.ts +4 -4
  129. package/dist/core/graph/receivers.js +5 -5
  130. package/dist/core/graph/repo-sync/exchange.d.ts +3 -7
  131. package/dist/core/graph/repo-sync/exchange.js +2 -2
  132. package/dist/core/graph/repo-sync/repos.d.ts +7 -5
  133. package/dist/core/graph/repo-sync/repos.js +3 -3
  134. package/dist/core/graph/repo-sync/sync.d.ts +3 -6
  135. package/dist/core/graph/repo-sync/sync.js +2 -2
  136. package/dist/core/graph/rules.d.ts +5 -5
  137. package/dist/core/graph/rules.js +3 -3
  138. package/dist/core/graph/spaces/app.js +1 -1
  139. package/dist/core/graph/spaces/index.d.ts +4 -5
  140. package/dist/core/graph/spaces/index.js +1 -1
  141. package/dist/core/graph/spaces/own-memory.d.ts +4 -4
  142. package/dist/core/graph/spaces/own-memory.js +1 -1
  143. package/dist/core/graph/spaces/person.js +3 -3
  144. package/dist/core/graph/spaces/repo.d.ts +1 -1
  145. package/dist/core/graph/spaces/repo.js +1 -1
  146. package/dist/core/graph/watches.d.ts +15 -15
  147. package/dist/core/graph/watches.js +10 -10
  148. package/dist/core/human/feedback-companion.d.ts +2 -2
  149. package/dist/core/human/feedback-companion.js +1 -1
  150. package/dist/core/human/feedback.d.ts +3 -3
  151. package/dist/core/human/feedback.js +1 -1
  152. package/dist/core/human/requests.d.ts +34 -33
  153. package/dist/core/human/requests.js +20 -20
  154. package/dist/core/human/scan.d.ts +2 -2
  155. package/dist/core/human/scan.js +1 -1
  156. package/dist/core/human/tickets.d.ts +9 -9
  157. package/dist/core/human/tickets.js +1 -1
  158. package/dist/core/llm/app-rungs.d.ts +1 -1
  159. package/dist/core/llm/app-rungs.js +1 -1
  160. package/dist/core/llm/run.js +1 -1
  161. package/dist/core/peer/directory.d.ts +1 -1
  162. package/dist/core/peer/directory.js +1 -1
  163. package/dist/core/peer/envelope.d.ts +3 -3
  164. package/dist/core/peer/envelope.js +1 -1
  165. package/dist/core/peer/home.d.ts +7 -7
  166. package/dist/core/peer/home.js +2 -2
  167. package/dist/core/peer/ingest.d.ts +6 -6
  168. package/dist/core/peer/ingest.js +1 -1
  169. package/dist/core/peer/outbox-store.d.ts +14 -14
  170. package/dist/core/peer/outbox-store.js +5 -5
  171. package/dist/core/peer/receiver.d.ts +2 -2
  172. package/dist/core/peer/receiver.js +1 -1
  173. package/dist/core/peer/stubs.d.ts +10 -10
  174. package/dist/core/peer/stubs.js +1 -1
  175. package/dist/core/providers/approval.d.ts +2 -2
  176. package/dist/core/providers/approval.js +2 -2
  177. package/dist/core/providers/audit.d.ts +3 -3
  178. package/dist/core/providers/audit.js +2 -2
  179. package/dist/core/providers/bundles.js +2 -2
  180. package/dist/core/providers/call.d.ts +2 -2
  181. package/dist/core/providers/call.js +1 -1
  182. package/dist/core/providers/files.d.ts +1 -1
  183. package/dist/core/providers/files.js +1 -1
  184. package/dist/core/providers/mint.js +1 -1
  185. package/dist/core/providers/receipts.d.ts +1 -1
  186. package/dist/core/providers/receipts.js +2 -2
  187. package/dist/core/review/birth.js +1 -1
  188. package/dist/core/review/comments.d.ts +19 -19
  189. package/dist/core/review/comments.js +5 -5
  190. package/dist/core/review/companion.d.ts +1 -1
  191. package/dist/core/review/companion.js +1 -1
  192. package/dist/core/review/document.d.ts +3 -3
  193. package/dist/core/review/document.js +2 -2
  194. package/dist/core/review/fork.js +2 -2
  195. package/dist/core/review/realize.js +1 -1
  196. package/dist/core/review/remap.d.ts +2 -2
  197. package/dist/core/review/remap.js +4 -4
  198. package/dist/core/review/stage.d.ts +1 -1
  199. package/dist/core/review/stage.js +1 -1
  200. package/dist/core/review/store.d.ts +21 -21
  201. package/dist/core/review/store.js +1 -1
  202. package/dist/core/runs/activity.d.ts +1 -1
  203. package/dist/core/runs/activity.js +5 -5
  204. package/dist/core/runs/confinement.d.ts +7 -7
  205. package/dist/core/runs/confinement.js +2 -2
  206. package/dist/core/runs/events.d.ts +12 -12
  207. package/dist/core/runs/events.js +4 -4
  208. package/dist/core/runs/operations.d.ts +11 -11
  209. package/dist/core/runs/operations.js +5 -5
  210. package/dist/core/runs/questions.d.ts +10 -10
  211. package/dist/core/runs/questions.js +3 -3
  212. package/dist/core/runtime/auth-reload.js +1 -1
  213. package/dist/core/runtime/bearings.d.ts +5 -5
  214. package/dist/core/runtime/bearings.js +6 -6
  215. package/dist/core/runtime/broker-inventory.js +1 -1
  216. package/dist/core/runtime/broker-request.js +1 -1
  217. package/dist/core/runtime/broker.js +1 -1
  218. package/dist/core/runtime/close.d.ts +3 -3
  219. package/dist/core/runtime/close.js +1 -1
  220. package/dist/core/runtime/deliver-live.js +1 -1
  221. package/dist/core/runtime/fleet.d.ts +2 -2
  222. package/dist/core/runtime/host.d.ts +3 -3
  223. package/dist/core/runtime/host.js +3 -3
  224. package/dist/core/runtime/kickoff.d.ts +12 -12
  225. package/dist/core/runtime/kickoff.js +17 -17
  226. package/dist/core/runtime/launch-target.d.ts +1 -1
  227. package/dist/core/runtime/launch-target.js +1 -1
  228. package/dist/core/runtime/ledger.d.ts +3 -3
  229. package/dist/core/runtime/ledger.js +3 -3
  230. package/dist/core/runtime/lifecycle.d.ts +1 -1
  231. package/dist/core/runtime/lifecycle.js +2 -2
  232. package/dist/core/runtime/memory-admission.js +1 -1
  233. package/dist/core/runtime/model-swap.d.ts +2 -2
  234. package/dist/core/runtime/model-swap.js +1 -1
  235. package/dist/core/runtime/node-read.d.ts +1 -1
  236. package/dist/core/runtime/node-read.js +2 -2
  237. package/dist/core/runtime/nodes.d.ts +6 -6
  238. package/dist/core/runtime/nodes.js +1 -1
  239. package/dist/core/runtime/outcome-document.d.ts +1 -1
  240. package/dist/core/runtime/outcome-document.js +1 -1
  241. package/dist/core/runtime/persona.d.ts +3 -3
  242. package/dist/core/runtime/persona.js +2 -2
  243. package/dist/core/runtime/placement.d.ts +11 -11
  244. package/dist/core/runtime/placement.js +1 -1
  245. package/dist/core/runtime/promote.d.ts +3 -3
  246. package/dist/core/runtime/promote.js +1 -1
  247. package/dist/core/runtime/recycle.js +1 -1
  248. package/dist/core/runtime/reopen.d.ts +5 -5
  249. package/dist/core/runtime/reopen.js +1 -1
  250. package/dist/core/runtime/reset.d.ts +4 -4
  251. package/dist/core/runtime/reset.js +1 -1
  252. package/dist/core/runtime/revive-all.d.ts +2 -2
  253. package/dist/core/runtime/revive-all.js +1 -1
  254. package/dist/core/runtime/revive.d.ts +4 -4
  255. package/dist/core/runtime/revive.js +2 -2
  256. package/dist/core/runtime/roadmap.d.ts +6 -6
  257. package/dist/core/runtime/roadmap.js +5 -5
  258. package/dist/core/runtime/session-branch.d.ts +1 -1
  259. package/dist/core/runtime/session-branch.js +1 -1
  260. package/dist/core/runtime/session-list-cache.js +1 -1
  261. package/dist/core/runtime/situational-live.js +1 -1
  262. package/dist/core/runtime/spawn.d.ts +2 -2
  263. package/dist/core/runtime/spawn.js +2 -2
  264. package/dist/core/runtime/stop-guard.d.ts +2 -2
  265. package/dist/core/runtime/stop-guard.js +3 -3
  266. package/dist/core/runtime/warm-pool.d.ts +2 -2
  267. package/dist/core/runtime/warm-pool.js +1 -1
  268. package/dist/core/spaces/mounts.d.ts +2 -2
  269. package/dist/core/spaces/mounts.js +1 -1
  270. package/dist/core/spaces/permissions.d.ts +1 -1
  271. package/dist/core/spaces/permissions.js +1 -1
  272. package/dist/core/spaces/process.d.ts +1 -1
  273. package/dist/core/spaces/process.js +1 -1
  274. package/dist/core/spaces/space.js +1 -1
  275. package/dist/core/spaces/stop.d.ts +3 -3
  276. package/dist/core/spaces/stop.js +2 -2
  277. package/dist/core/spaces/users.d.ts +6 -6
  278. package/dist/core/spaces/users.js +1 -1
  279. package/dist/core/storage/attachments.d.ts +2 -2
  280. package/dist/core/storage/attachments.js +1 -1
  281. package/dist/core/storage/shares.d.ts +2 -2
  282. package/dist/core/storage/shares.js +1 -1
  283. package/dist/core/storage/tables.d.ts +21 -21
  284. package/dist/core/storage/tables.js +3 -3
  285. package/dist/core/substrate/delivery/corpus.d.ts +5 -8
  286. package/dist/core/substrate/delivery/corpus.js +3 -3
  287. package/dist/core/substrate/delivery/deliver.d.ts +10 -15
  288. package/dist/core/substrate/delivery/deliver.js +3 -3
  289. package/dist/core/substrate/delivery/plan.d.ts +2 -12
  290. package/dist/core/substrate/delivery/plan.js +3 -3
  291. package/dist/core/substrate/delivery/render-boot.d.ts +4 -4
  292. package/dist/core/substrate/delivery/render-boot.js +18 -18
  293. package/dist/core/substrate/delivery/render-event.d.ts +7 -14
  294. package/dist/core/substrate/delivery/render-event.js +4 -4
  295. package/dist/core/substrate/subject.d.ts +2 -2
  296. package/dist/core/substrate/subject.js +1 -1
  297. package/dist/core/usage/ledger.d.ts +6 -6
  298. package/dist/core/usage/ledger.js +4 -4
  299. package/dist/core/worktree-close.js +4 -4
  300. package/dist/core/worktree-mutation-async.js +7 -7
  301. package/dist/core/worktree-quarantine.js +1 -1
  302. package/dist/core/worktree-sweep.d.ts +1 -1
  303. package/dist/core/worktree-sweep.js +6 -6
  304. package/dist/core/worktree.d.ts +5 -5
  305. package/dist/core/worktree.js +13 -13
  306. package/dist/daemon/analytics/compute.d.ts +2 -2
  307. package/dist/daemon/analytics/compute.js +1 -1
  308. package/dist/daemon/api/app-listener.d.ts +4 -4
  309. package/dist/daemon/api/app-listener.js +13 -13
  310. package/dist/daemon/api/bridge.js +5 -5
  311. package/dist/daemon/api/document-listener.js +6 -6
  312. package/dist/daemon/api/handlers/analytics.js +1 -1
  313. package/dist/daemon/api/handlers/attach.js +1 -1
  314. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  315. package/dist/daemon/api/handlers/bash.js +1 -1
  316. package/dist/daemon/api/handlers/broker-ops.d.ts +1 -1
  317. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  318. package/dist/daemon/api/handlers/broker-recovery.d.ts +1 -1
  319. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  320. package/dist/daemon/api/handlers/broker-signals.d.ts +2 -2
  321. package/dist/daemon/api/handlers/broker-signals.js +2 -2
  322. package/dist/daemon/api/handlers/canvas.d.ts +1 -1
  323. package/dist/daemon/api/handlers/canvas.js +4 -4
  324. package/dist/daemon/api/handlers/chat-inventory.js +1 -1
  325. package/dist/daemon/api/handlers/crons.js +1 -1
  326. package/dist/daemon/api/handlers/custom-objects.d.ts +4 -4
  327. package/dist/daemon/api/handlers/custom-objects.js +3 -3
  328. package/dist/daemon/api/handlers/delivery-retry.js +1 -1
  329. package/dist/daemon/api/handlers/delivery.js +1 -1
  330. package/dist/daemon/api/handlers/docs.d.ts +4 -4
  331. package/dist/daemon/api/handlers/docs.js +1 -1
  332. package/dist/daemon/api/handlers/feedback-comments.js +3 -3
  333. package/dist/daemon/api/handlers/files.js +1 -1
  334. package/dist/daemon/api/handlers/focus.js +1 -1
  335. package/dist/daemon/api/handlers/health.js +3 -3
  336. package/dist/daemon/api/handlers/hook-exec.js +1 -1
  337. package/dist/daemon/api/handlers/human-requests.js +1 -1
  338. package/dist/daemon/api/handlers/inbox-page.d.ts +1 -1
  339. package/dist/daemon/api/handlers/inbox-page.js +1 -1
  340. package/dist/daemon/api/handlers/inbox.d.ts +1 -1
  341. package/dist/daemon/api/handlers/inbox.js +1 -1
  342. package/dist/daemon/api/handlers/llm.d.ts +1 -1
  343. package/dist/daemon/api/handlers/llm.js +3 -3
  344. package/dist/daemon/api/handlers/memory-reads.js +1 -1
  345. package/dist/daemon/api/handlers/memory.d.ts +5 -5
  346. package/dist/daemon/api/handlers/memory.js +5 -5
  347. package/dist/daemon/api/handlers/messages.js +2 -2
  348. package/dist/daemon/api/handlers/node-events.d.ts +2 -2
  349. package/dist/daemon/api/handlers/node-events.js +3 -3
  350. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  351. package/dist/daemon/api/handlers/node-records.js +2 -2
  352. package/dist/daemon/api/handlers/nodes.d.ts +1 -1
  353. package/dist/daemon/api/handlers/nodes.js +1 -1
  354. package/dist/daemon/api/handlers/objects.js +3 -3
  355. package/dist/daemon/api/handlers/package-docs.js +1 -1
  356. package/dist/daemon/api/handlers/plugin-app-token.d.ts +1 -1
  357. package/dist/daemon/api/handlers/plugin-app-token.js +1 -1
  358. package/dist/daemon/api/handlers/profiles.d.ts +3 -3
  359. package/dist/daemon/api/handlers/profiles.js +1 -1
  360. package/dist/daemon/api/handlers/providers.d.ts +1 -1
  361. package/dist/daemon/api/handlers/providers.js +1 -1
  362. package/dist/daemon/api/handlers/questions.js +1 -1
  363. package/dist/daemon/api/handlers/reports.d.ts +1 -1
  364. package/dist/daemon/api/handlers/reports.js +5 -5
  365. package/dist/daemon/api/handlers/review-comments.js +1 -1
  366. package/dist/daemon/api/handlers/reviews.js +1 -1
  367. package/dist/daemon/api/handlers/runs.js +1 -1
  368. package/dist/daemon/api/handlers/structured-requests.js +1 -1
  369. package/dist/daemon/api/handlers/subscriptions.js +1 -1
  370. package/dist/daemon/api/handlers/transfer.js +1 -1
  371. package/dist/daemon/api/map.d.ts +3 -3
  372. package/dist/daemon/api/map.js +1 -1
  373. package/dist/daemon/api/principal.d.ts +1 -1
  374. package/dist/daemon/api/principal.js +1 -1
  375. package/dist/daemon/api/reader.d.ts +5 -5
  376. package/dist/daemon/api/reader.js +1 -1
  377. package/dist/daemon/api/router.d.ts +5 -5
  378. package/dist/daemon/api/router.js +1 -1
  379. package/dist/daemon/api/server.js +1 -1
  380. package/dist/daemon/broker-signals/bus.d.ts +1 -1
  381. package/dist/daemon/broker-signals/bus.js +1 -1
  382. package/dist/daemon/companion-retire.js +1 -1
  383. package/dist/daemon/cron/armed-context.d.ts +2 -2
  384. package/dist/daemon/cron/armed-context.js +1 -1
  385. package/dist/daemon/cron/authority.d.ts +2 -2
  386. package/dist/daemon/cron/authority.js +1 -1
  387. package/dist/daemon/cron/disposition.js +1 -1
  388. package/dist/daemon/cron/ended.d.ts +1 -1
  389. package/dist/daemon/cron/ended.js +2 -2
  390. package/dist/daemon/cron/escalation.js +3 -3
  391. package/dist/daemon/cron/folders.d.ts +1 -1
  392. package/dist/daemon/cron/folders.js +1 -1
  393. package/dist/daemon/cron/held.d.ts +1 -1
  394. package/dist/daemon/cron/held.js +1 -1
  395. package/dist/daemon/cron/lease-recovery.d.ts +1 -1
  396. package/dist/daemon/cron/lease-recovery.js +1 -1
  397. package/dist/daemon/cron/passes.d.ts +2 -2
  398. package/dist/daemon/cron/passes.js +1 -1
  399. package/dist/daemon/cron/run-socket.d.ts +1 -1
  400. package/dist/daemon/cron/run-socket.js +1 -1
  401. package/dist/daemon/cron/settle.js +1 -1
  402. package/dist/daemon/cron/sinks.d.ts +1 -1
  403. package/dist/daemon/cron/sinks.js +2 -2
  404. package/dist/daemon/cron-run.d.ts +12 -3
  405. package/dist/daemon/cron-run.js +2 -2
  406. package/dist/daemon/crtrd.js +6 -6
  407. package/dist/daemon/delivery/run-delivery.js +1 -1
  408. package/dist/daemon/due-sources.d.ts +3 -3
  409. package/dist/daemon/due-sources.js +1 -1
  410. package/dist/daemon/due.d.ts +3 -3
  411. package/dist/daemon/due.js +7 -7
  412. package/dist/daemon/fleet.d.ts +2 -2
  413. package/dist/daemon/fleet.js +11 -11
  414. package/dist/daemon/human/finish.js +3 -3
  415. package/dist/daemon/human/settle.d.ts +1 -1
  416. package/dist/daemon/human/settle.js +1 -1
  417. package/dist/daemon/human/sweep.js +1 -1
  418. package/dist/daemon/joined-owner.d.ts +2 -2
  419. package/dist/daemon/joined-owner.js +1 -1
  420. package/dist/daemon/messaging/node-message.js +1 -1
  421. package/dist/daemon/park-activity.d.ts +2 -2
  422. package/dist/daemon/park-activity.js +1 -1
  423. package/dist/daemon/peer/authority.js +1 -1
  424. package/dist/daemon/peer/forward.d.ts +6 -6
  425. package/dist/daemon/peer/forward.js +1 -1
  426. package/dist/daemon/peer/handlers.js +1 -1
  427. package/dist/daemon/peer/ingress.d.ts +4 -4
  428. package/dist/daemon/peer/ingress.js +1 -1
  429. package/dist/daemon/peer/outbox.d.ts +2 -2
  430. package/dist/daemon/peer/outbox.js +1 -1
  431. package/dist/daemon/peer/relay-service.js +1 -1
  432. package/dist/daemon/plugin-objects/read-leaf.d.ts +2 -2
  433. package/dist/daemon/plugin-objects/read-leaf.js +2 -2
  434. package/dist/daemon/profile-delete.js +1 -1
  435. package/dist/daemon/readiness.d.ts +2 -2
  436. package/dist/daemon/readiness.js +1 -1
  437. package/dist/daemon/reconcilers/action-lane.d.ts +1 -1
  438. package/dist/daemon/reconcilers/action-lane.js +1 -1
  439. package/dist/daemon/reconcilers/bash-deadline.js +2 -2
  440. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  441. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  442. package/dist/daemon/reconcilers/controller-death.d.ts +1 -1
  443. package/dist/daemon/reconcilers/controller-death.js +1 -1
  444. package/dist/daemon/reconcilers/cron-lane.d.ts +1 -1
  445. package/dist/daemon/reconcilers/cron-lane.js +1 -1
  446. package/dist/daemon/reconcilers/delivery-lane.d.ts +1 -1
  447. package/dist/daemon/reconcilers/delivery-lane.js +2 -2
  448. package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +3 -3
  449. package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
  450. package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +2 -2
  451. package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
  452. package/dist/daemon/reconcilers/live-obligation.d.ts +6 -6
  453. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  454. package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
  455. package/dist/daemon/reconcilers/node-deadline.d.ts +1 -1
  456. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  457. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  458. package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.d.ts +3 -3
  459. package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.js +1 -1
  460. package/dist/daemon/reconcilers/node-lifecycle/terminating.js +1 -1
  461. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  462. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.d.ts +1 -1
  463. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  464. package/dist/daemon/reconcilers/pending-review-submit.d.ts +1 -1
  465. package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
  466. package/dist/daemon/reconcilers/storage-due-work.js +1 -1
  467. package/dist/daemon/reconcilers/storage-maintenance.d.ts +1 -1
  468. package/dist/daemon/reconcilers/storage-maintenance.js +2 -2
  469. package/dist/daemon/reconcilers/structured-request-lane.d.ts +1 -1
  470. package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
  471. package/dist/daemon/review/comment-notify.js +2 -2
  472. package/dist/daemon/review/companion.d.ts +3 -3
  473. package/dist/daemon/review/companion.js +1 -1
  474. package/dist/daemon/review/finish.js +1 -1
  475. package/dist/daemon/review/sweep.js +1 -1
  476. package/dist/daemon/run-notices.d.ts +4 -4
  477. package/dist/daemon/run-notices.js +1 -1
  478. package/dist/daemon/runs/append-section.d.ts +2 -2
  479. package/dist/daemon/runs/append-section.js +2 -2
  480. package/dist/daemon/runs/observer.d.ts +2 -2
  481. package/dist/daemon/runs/observer.js +2 -2
  482. package/dist/daemon/structured-requests/boot.d.ts +1 -1
  483. package/dist/daemon/structured-requests/boot.js +1 -1
  484. package/dist/daemon/structured-requests/effects.js +1 -1
  485. package/dist/daemon/structured-requests/sidecar.d.ts +1 -1
  486. package/dist/daemon/structured-requests/sidecar.js +1 -1
  487. package/dist/migrations/004-canvas-documents/apply.d.ts +3 -3
  488. package/dist/migrations/004-canvas-documents/apply.js +1 -1
  489. package/dist/migrations/004-canvas-documents/index.d.ts +2 -2
  490. package/dist/migrations/004-canvas-documents/index.js +2 -2
  491. package/dist/migrations/activation.js +2 -2
  492. package/docs/public-api.md +11 -0
  493. package/package.json +3 -2
  494. package/packages/crouter-identity/package.json +1 -1
  495. package/runtime.lock.json +12 -12
@@ -1,3 +1,3 @@
1
- var Ie=Object.defineProperty;var l=(e,t)=>Ie(e,"name",{value:t,configurable:!0});import{prepared as Se}from"../../../core/sqlite-statements.js";import{ApiError as y}from"../../../api/errors.js";import{PRIVACY_LEVELS_DTO as $e}from"../../../api/dto/objects.js";import{openDb as T,withCanvasWrite as _}from"../../../core/canvas/db.js";import{actorOf as te}from"../../../core/graph/documents.js";import{readerForObject as M,readerFor as Fe}from"../../../core/graph/reader.js";import{resolveName as Ne,stubsNamed as Ae,unwrapRef as We}from"../../../core/graph/names.js";import{canRead as ne,customReachable as Le,holdsObjectsScope as Pe,mayActAs as re}from"../../../core/graph/access.js";import{customObjectRef as oe,authorizeCustom as ie,fenceArgv as G}from"./custom-objects.js";import{edgesOf as Ce}from"../../../core/graph/edges.js";import{publish as U}from"../../../core/graph/events.js";import{objectDTO as b}from"../../../core/graph/kinds/dto.js";import{isKind as De,kindNames as Me,kindOf as z}from"../../../core/graph/kinds/registry.js";import{listObjects as Ge,searchObjects as se}from"../../../core/graph/objects.js";import{checkoutsForCwd as Ue}from"../../../core/graph/repo-sync/repos.js";import{recordWatch as L,unwatch as ze,watchersOf as He,watchesOf as Ve}from"../../../core/graph/watches.js";import{armObjectWaitForWatch as P,settleObjectWaitForUnwatch as Be}from"../../../core/graph/object-waits.js";import{readerFor as v,resolveRef as H}from"../reader.js";import{readDelegationFor as ue,runReadLeaf as Ke}from"../../plugin-objects/read-leaf.js";import{invalidRequest as C,isRecord as I}from"./validate.js";import{callerNode as ae,callerStub as V,forwardVerb as ce,originates as le,queryWithoutMachine as B,relayError as D,remoteStub as Ze,unknownError as fe,forwarding as A,withMachine as K}from"../../peer/forward.js";import{getById as W,getByRowid as de}from"../../../core/graph/objects.js";import{ensureNodeStub as Je,isStub as Z,stubOf as Qe,withKindDecl as S}from"../../../core/peer/stubs.js";import{isUnreachable as Ye}from"../../../core/peer/client.js";import{normalizeMachineId as $}from"../../../core/peer/directory.js";const F=l(e=>t=>Ue(e,t),"reposFnFor");function me(e,t){return{...b(e,t),...z(e,t.type).listItem?.(e,t)}}l(me,"listItem");function Xe(e){return`no object named ${e} on this runtime; it may be on another runtime, or the name may be misspelled`}l(Xe,"remoteMessage");function he(e,t,r){try{return R(e,t,r)}catch(n){if(n instanceof y&&n.code==="not_found"&&!n.details?.deleted)return null;throw n}}l(he,"ownerFilter");function R(e,t,r){const n=H(e,t,r);if("remote"in n)throw new y(404,"not_found",Xe(n.remote),{next:"Check the name with `crtr canvas search`."});if("deleted"in n)throw new y(404,"not_found",`${n.deleted.name} is deleted`,{id:n.deleted.id,deleted:!0});return n}l(R,"liveRef");const k=l(e=>decodeURIComponent(e.params.ref),"refParam"),pe=l(e=>{const t=We(e),r=t.indexOf("/");return r>0?t.slice(0,r):t},"idOf");function we(e){const t=W(T(),pe(e));return t!==null&&Z(T(),t)?t.id:null}l(we,"stubIdOf");function xe(e,t){const r=we(e);return r!==null?{stub:r,hit:!0}:_(n=>{try{const o=v(n,t),s=l(()=>{const u=Ae(n,o,e);if(u.length>1)throw new y(409,"ambiguous_name",`'${e}' names more than one remote object`,{candidates:u.map(c=>c.id),next:"Read one by its object id."});return{stub:u[0]?.id??null,hit:!1}},"named");let i;try{i=H(n,o,e)}catch(u){if(u instanceof y&&u.code==="not_found")return s();throw u}if("remote"in i)return s();if("deleted"in i){const u=s();return u.stub===null?{stub:null,hit:!0}:u}return{stub:Z(n,i)?i.id:null,hit:!0}}catch(o){if(o instanceof y&&o.code==="ambiguous_name")throw o;return{stub:null,hit:!1}}})}l(xe,"resolvedLocally");async function J(e,t,r){const n=xe(t,e);return n.stub!==null?ce(e,n.stub,r):n.hit||!le(e.principal)?{kind:"local"}:ce(e,pe(t),r)}l(J,"forwardRef");const Q=l(e=>`/v1/objects/${encodeURIComponent(e)}`,"objectPath");function ye(e,t,r,n,o){const s=t?.object;!s?.id||!s.type||_(i=>{const u=ae(i,e);if(u===null)return;const c=Ze(i,s.id,s.type,r,{kind:s.kind??null,name:s.name??s.id,...s.preview===void 0?{}:{preview:s.preview},owner:s.owner??null,...s.kind_decl===void 0?{}:{kind_decl:s.kind_decl},...s.privacy===void 0?{}:{privacy:s.privacy}});L(i,u,c,n,o===void 0?{}:{patterns:o}),n==="ask"&&P(i,u,c)})}l(ye,"watchRemote");async function et(e){const t=k(e),r=["1","true"].includes(e.query.get("fields")??""),n=await J(e,t,{method:"GET",path:Q(t),query:B(e)});if(n.kind==="unknown")return{state:"unknown",ref:t,unreachable:n.unreachable};if(n.kind==="remote"){if(n.status>=400)throw D(n.status,n.body);return ye(e,n.body,n.machine.id,"read"),K(n.body,n.machine)}const o=l(u=>{const c=V(u,e);return c===null?v(u,e):M(u,c,F(u))},"readerOf"),s=_(u=>{const c=o(u),a=H(u,c,t);if("remote"in a)return{state:"remote",remote:a.remote};if("deleted"in a)return{state:"deleted",deleted:b(u,a.deleted)};const f=ue(u,a);if(f!==null)return{delegate:f,hitId:a.id};const{data:p,text:g}=z(u,a.type).read(u,c,a,{fields:r,reposFn:F(u)});return{state:"object",type:a.type,object:S(u,a,b(u,a)),text:g,data:p}});if(!("delegate"in s))return s;const i=await Ke(s.delegate,e.principal);return _(u=>{const c=o(u),a=W(u,s.hitId);if(a===null)throw new y(404,"not_found","object not found");if(a.deleted_at!==null)return{state:"deleted",deleted:b(u,a)};if(!ne(u,c,a))throw new y(404,"not_found","object not found");const{data:f,text:p}=z(u,a.type).read(u,c,a,{fields:r,reposFn:F(u)});return ue(u,a)===null?{state:"object",type:a.type,object:S(u,a,b(u,a)),text:p,data:f}:{state:"object",type:a.type,object:S(u,a,b(u,a)),text:"markdown"in i?i.markdown:`${p}
2
- content unavailable: ${i.unavailable}`,data:{...f,content:"markdown"in i?"live":"unavailable"}}})}l(et,"read");function Y(e,t,r,n){if(e!=null){if(!r.includes(e)){n.push({field:t,problem:`must be one of ${r.join(", ")}`,received:e});return}return e}}l(Y,"oneOf");function ge(e,t,r){if(t!=null){if(typeof t!="string"||!De(e,t)){r.push({field:"type",problem:`must be a kind: one of ${Me(e).join(", ")}`,received:t});return}return t}}l(ge,"kindName");function be(e,t,r,n){if(e==null)return n;const o=Number(e);return!Number.isInteger(o)||o<1||o>100?(r.push({field:t,problem:"must be an integer from 1 to 100",received:e}),n):o}l(be,"limitOf");function je(e){const t=e.query,r=[],n=ge(T(),t.get("type"),r),o=Y(t.get("privacy"),"privacy",$e,r),s=be(t.get("limit"),"limit",r,50),i=t.get("cursor");i!==null&&!/^\d+$/.test(i)&&r.push({field:"cursor",problem:"is not a cursor from a previous page",received:i});const u=t.get("deleted");return u!==null&&!["0","1","true","false"].includes(u)&&r.push({field:"deleted",problem:"must be true or false",received:u}),r.length>0&&C("object list request",r),_(c=>{const a=v(c,e),f={...n?{type:n}:{},...o?{privacy:o}:{},...t.get("kind")!==null?{kind:t.get("kind")}:{},...u==="1"||u==="true"?{deleted:!0}:{}},p=t.get("owner");if(p!==null){const m=he(c,a,p);if(m===null)return{items:[],next_cursor:null};f.owner=m}const g=t.get("name"),j=[];let h=i===null?0:Number(i),w=!0;for(;j.length<s&&w;){const m=Ge(c,a,f,{limit:100,after_rowid:h});w=m.length===100;for(const E of m)if(h=E.rowid,(g===null||E.name.startsWith(g))&&j.push(E),j.length===s)break}const d=j.at(-1);return{items:j.map(m=>me(c,m)),next_cursor:j.length===s&&d?String(d.rowid):null}})}l(je,"listLocal");const tt={ms:3e4},nt="self",X=l((e,t)=>e.map(r=>({...r,machine:t})),"labelItems");async function _e(e,t,r,n){const o=A.current;try{const s=await o.call(t.id,{method:"GET",path:"/v1/objects",query:r},o.envelope(e.principal),n);if(Ye(s))return{state:"unreachable",items:[],next:null};if(s.status===426)return{state:"too_old",items:[],next:null};const i=s.body;return s.status!==200||!Array.isArray(i?.items)?{state:"unreachable",items:[],next:null}:{state:"ok",items:X(i.items,t),next:i.next_cursor??null}}catch{return{state:"unreachable",items:[],next:null}}}l(_e,"remotePage");async function rt(e){const t=new Promise(r=>e.addEventListener("abort",()=>r(null),{once:!0}));return Promise.race([A.current.machines().catch(()=>null),t])}l(rt,"machinesWithin");async function ot(e){const t=e.query.get("machine");if(!le(e.principal)||!A.current.joined()||t===nt)return je(ke(e));const n=A.current.self(),o=t!==null&&$(t)!==n,s=o?null:je(ke(e)),i=new AbortController,u=setTimeout(()=>i.abort(),tt.ms);u.unref?.();try{const c=await rt(i.signal);if(c===null){if(o)throw new y(503,"runtime_unreachable",`The directory did not answer, so ${$(t)} cannot be listed.`,{machine:$(t)});return s}const a=l(d=>({id:d,name:c.find(m=>m.machine_id===d)?.name??d}),"labelOf"),f=a(n),p=c.filter(d=>d.machine_id!==n&&d.kind!=="device"),g=B(e);if(t!==null){if(!o)return{items:X(s.items,f),next_cursor:s.next_cursor,machines:[{machine_id:n,name:f.name,state:"ok",more:s.next_cursor!==null}]};const d=$(t);if(!p.some(E=>E.machine_id===d))throw new y(404,"not_found",`no machine ${d} on your account`,{machine:d});const m=await _e(e,a(d),g,i.signal);return{items:m.items,next_cursor:m.next,machines:[{machine_id:d,name:a(d).name,state:m.state,more:m.next!==null}]}}const{cursor:j,...h}=g,w=await Promise.all(p.map(d=>_e(e,a(d.machine_id),h,i.signal)));return{items:[...X(s.items,f),...w.flatMap(d=>d.items)],next_cursor:s.next_cursor,machines:[{machine_id:n,name:f.name,state:"ok",more:s.next_cursor!==null},...p.map((d,m)=>({machine_id:d.machine_id,name:d.name,state:w[m].state,more:w[m].next!==null}))]}}finally{clearTimeout(u)}}l(ot,"list");function ke(e){const t=new URLSearchParams(e.query);return t.delete("machine"),{...e,query:t}}l(ke,"withoutMachine");function it(e){const t=[],r=I(e.body)?e.body:{};I(e.body)||t.push({field:"body",problem:"must be an object",received:e.body});const n=r.text;(typeof n!="string"||n.trim()==="")&&t.push({field:"text",problem:"is required",received:n});const o=r.grep;if(o!==void 0)if(typeof o!="string")t.push({field:"grep",problem:"must be a regular expression string",received:o});else try{new RegExp(o)}catch(u){t.push({field:"grep",problem:`is not a valid regular expression: ${u.message}`,received:o})}r.body!==void 0&&typeof r.body!="boolean"&&t.push({field:"body",problem:"must be a boolean",received:r.body});const s=ge(T(),r.type,t);r.kind!==void 0&&typeof r.kind!="string"&&t.push({field:"kind",problem:"must be a string",received:r.kind}),r.owner!==void 0&&typeof r.owner!="string"&&t.push({field:"owner",problem:"must be a string",received:r.owner});const i=be(r.limit,"limit",t,50);return t.length>0&&C("object search request",t),_(u=>{const c=v(u,e),a=typeof r.owner=="string"?he(u,c,r.owner):null;if(typeof r.owner=="string"&&a===null)return{items:[]};const f=se(u,c,{text:n,body:r.body===!0||typeof o=="string"}),p=new Set(f.map(h=>h.object.rowid));return{items:(typeof o=="string"?se(u,c,{text:o,grep:!0}).filter(h=>p.has(h.object.rowid)):f).filter(h=>(!s||h.object.type===s)&&(r.kind===void 0||h.object.kind===r.kind)&&(!a||h.object.owner===a.rowid)).slice(0,i).map(h=>({object:me(u,h.object),...h.line!==void 0?{matches:[{line:h.line,text:h.text??""}]}:{}}))}})}l(it,"search");const ve=["interrupt","steer","after-turn","next-turn"],st=/^(\*|>|[A-Za-z0-9_-]+)(\.(\*|>|[A-Za-z0-9_-]+))*$/;function ut(e,t){if(e!==void 0){if(!Array.isArray(e)||e.length===0||e.some(r=>typeof r!="string"||!st.test(r)||r.includes(">")&&!r.endsWith(">"))){t.push({field:"patterns",problem:"must be a non-empty list of event patterns (dot-separated words, `*` for one word, a final `>` for the rest)",received:e});return}return e}}l(ut,"patternsOf");function at(e,t){if(e===void 0)return;if(!I(e)||Object.keys(e).length===0){t.push({field:"config",problem:"must map levels 1-10 to a delivery",received:e});return}const r=[];for(const[n,o]of Object.entries(e)){const s=Number(n);!Number.isInteger(s)||s<1||s>10?t.push({field:`config.${n}`,problem:"level must be an integer from 1 to 10"}):ve.includes(o)?r.push({threshold:s,delivery:o}):t.push({field:`config.${n}`,problem:`delivery must be one of ${ve.join(", ")}`,received:o})}return r.sort((n,o)=>o.threshold-n.threshold)}l(at,"configOf");function Oe(e){const t=we(e);if(t!==null)throw new y(400,"invalid_request",`${t} lives on another machine; an explicit watcher cannot watch it from here`,{id:t})}l(Oe,"refuseStubWatch");function x(e,t){const r=W(e,t)??(()=>{const n=Ne(e,Fe(e,{class:"person"},()=>[]),t);return"object"in n?n.object:null})();return r===null||r.deleted_at!==null||!(r.type.includes(".")||r.type==="node")?null:r}l(x,"findWatcher");const O=l(()=>{throw new y(404,"not_found","watcher not found")},"watcherNotFound");async function Ee(e,t,r){if(typeof t!="string"||r===void 0||r===null)return null;if(typeof r!="string")throw new y(400,"invalid_request","invalid watcher_machine");if(x(e,t)!==null)return null;const n=A.current;let o;try{o=await n.machines()}catch{throw new y(503,"runtime_unreachable","The directory did not answer, so the watcher machine cannot be checked.")}const s=$(r);return(s===n.self()||!o.some(i=>$(i.machine_id)===s))&&O(),s}l(Ee,"remoteWatcherMachine");function Re(e,t,r,n){if(t.publishToken||t.principal.class==="anonymous")return O();const o=v(e,t);if(o.class==="person")return O();let s;try{s=R(e,o,n)}catch{return O()}const i=s.owner===null?null:de(e,s.owner);return i===null||!re(e,o,i)||!Pe(e,o,"link",r)?O():(G(e,t,r),{actor:o.app,object:s})}l(Re,"linkWatcher");function qe(e,t,r){if(t.publishToken)return!0;if(t.principal.class==="anonymous"||!r.type.includes("."))return!1;const n=v(e,t),o=r.owner===null?null:de(e,r.owner);return o!==null&&re(e,n,o)&&Le(e,n,r)}l(qe,"ownsWatcher");async function ct(e){const t=k(e),r=I(e.body)?e.body:{};if(typeof r.watcher=="string"&&Oe(t),typeof r.watcher!="string"){const o=await J(e,t,{method:"POST",path:`${Q(t)}/watch`,body:e.body});if(o.kind==="unknown")throw fe(t,o.unreachable);if(o.kind==="remote"){if(o.status>=400)throw D(o.status,o.body);const s=o.body.patterns;return ye(e,o.body,o.machine.id,"ask",s),K(o.body,o.machine)}}const n=await Ee(T(),r.watcher,r.watcher_machine);return lt(e,n)}l(ct,"watch");function lt(e,t=null){const r=[],n=e.body===void 0?{}:I(e.body)?e.body:(r.push({field:"body",problem:"must be an object"}),{}),o=ut(n.patterns,r),s=at(n.config,r);return n.filter!==void 0&&!I(n.filter)&&r.push({field:"filter",problem:"must be an object",received:n.filter}),n.watcher!==void 0&&typeof n.watcher!="string"&&r.push({field:"watcher",problem:"must be a custom-object ref",received:n.watcher}),n.watcher_machine!==void 0&&typeof n.watcher_machine!="string"&&r.push({field:"watcher_machine",problem:"must be a machine id",received:n.watcher_machine}),r.length>0&&C("watch request",r),_(i=>{const u=typeof n.watcher=="string";if((e.publishToken||e.principal.class==="anonymous")&&!u)throw new y(404,"not_found","watcher not found");const c=o??[">"],a={patterns:c,...s?{config:s}:{},...n.filter!==void 0?{filter:n.filter}:{}};if(u){const j=n.watcher,h=t===null?null:ft(i,e,j,t),w=h??(e.publishToken?oe(i,j):x(i,j));if(w===null)return O();if(h===null&&qe(i,e,w)){const E=ie(i,e,w);G(i,e,w);const ee=M(i,w),q=R(i,ee,k(e));if(!ne(i,ee,q))throw new y(404,"not_found","object not found");return L(i,w,q,"act",a),P(i,w,q),U(i,{event:"watched",object:q,actor:E,attrs:{}},F(i)),{object:S(i,q,b(i,q)),patterns:c}}const{actor:d,object:m}=Re(i,e,w,k(e));return L(i,w,m,"act",{...a,linkApp:d}),P(i,w,m),U(i,{event:"watched",object:m,actor:d,attrs:{}},F(i)),{object:S(i,m,b(i,m)),patterns:c}}const f=v(i,e),p=V(i,e)??te(f),g=R(i,f,k(e));return L(i,p,g,"ask",a),P(i,p,g),U(i,{event:"watched",object:g,actor:p,attrs:{}},F(i)),{object:S(i,g,b(i,g)),patterns:c}})}l(lt,"watchLocal");function ft(e,t,r,n){return t.publishToken||t.principal.class==="anonymous"?O():Je(e,r,n)}l(ft,"ensureNodeStubFor");function Te(e,t,r,n){const o=l(()=>Se(e,`SELECT count(*) AS n FROM watch_subscriptions s JOIN watches w ON w.rowid = s.watch
3
- WHERE w.watcher = ? AND w.object = ?`).get(t.rowid,r.rowid).n,"count"),s=o();ze(e,t,r,n??void 0);const i=o();return i===0&&Be(e,t,r),{object:b(e,r),removed:s-i}}l(Te,"dropWatch");async function dt(e){const t=k(e);if(e.query.get("watcher")&&Oe(t),!e.query.get("watcher")){const n=await J(e,t,{method:"DELETE",path:`${Q(t)}/watch`,query:B(e)});if(n.kind==="unknown")throw fe(t,n.unreachable);if(n.kind==="remote"){const o=n.status===404?n.body.error?.details:void 0,s=o?.deleted===!0?o.id:void 0;if(n.status>=400&&s===void 0)throw D(n.status,n.body);const i=s??n.body.object?.id,u=_(c=>{const a=ae(c,e),f=i===void 0?null:W(c,i);return a===null||f===null||!Z(c,f)?null:Te(c,a,f,e.query.get("pattern"))});if(s!==void 0){if(u===null)throw D(n.status,n.body);return{...u,machine:n.machine}}return K(n.body,n.machine)}}const r=await Ee(T(),e.query.get("watcher")??void 0,e.query.get("watcher_machine")??void 0);return mt(e,r)}l(dt,"unwatchRoute");function mt(e,t=null){const r=e.query.get("pattern"),n=e.query.get("watcher");return _(o=>{if((e.publishToken||e.principal.class==="anonymous")&&!n)throw new y(404,"not_found","watcher not found");const s=l((c,a)=>Te(o,c,a,r),"drop");if(n){const c=t===null?null:(()=>{const f=W(o,n);return f!==null&&Qe(o,f)!==null?f:null})();if(t!==null&&c===null)return O();const a=c??(e.publishToken?oe(o,n):x(o,n));return a===null?O():c===null&&qe(o,e,a)?(ie(o,e,a),G(o,e,a),s(a,R(o,M(o,a),k(e)))):s(a,Re(o,e,a,k(e)).object)}const i=v(o,e),u=V(o,e)??te(i);return s(u,R(o,i,k(e)))})}l(mt,"unwatchLocal");function ht(e){const t=[],r=Y(e.query.get("type"),"type",["acted-on","links-to","watches"],t),n=Y(e.query.get("direction"),"direction",["out","in"],t);return t.length>0&&C("edges request",t),_(o=>{const s=v(o,e),i=R(o,s,k(e)),u=[];if(r!=="watches")for(const c of Ce(o,s,i,{...r?{type:r}:{},direction:n??"both"}))u.push({type:c.type,src:b(o,c.src),dst:b(o,c.dst),...c.written_as?{written_as:c.written_as}:{}});if(r===void 0||r==="watches"){const c=[...n!=="in"?Ve(o,s,i):[],...n!=="out"?He(o,s,i):[]];for(const a of c)u.push({type:"watches",src:b(o,a.watcher),dst:b(o,a.object)})}return{items:u}})}l(ht,"edges");const N=l(e=>async t=>({status:200,body:await e(t)}),"ok"),Gt=[{method:"POST",pattern:"/v1/objects/search",handler:N(it)},{method:"GET",pattern:"/v1/objects/:ref/edges",handler:N(ht)},{method:"POST",pattern:"/v1/objects/:ref/watch",handler:N(ct)},{method:"DELETE",pattern:"/v1/objects/:ref/watch",handler:N(dt)},{method:"GET",pattern:"/v1/objects/:ref",handler:N(et)},{method:"GET",pattern:"/v1/objects",handler:N(ot)}];export{tt as listBudget,Gt as objectRoutes};
1
+ var $e=Object.defineProperty;var l=(e,t)=>$e(e,"name",{value:t,configurable:!0});import{ApiError as y}from"../../../api/errors.js";import{PRIVACY_LEVELS_DTO as Ae}from"../../../api/dto/objects.js";import{openDb as T,withCanvasWrite as _}from"../../../core/canvas/db.js";import{actorOf as te}from"../../../core/graph/documents.js";import{readerForObject as M,readerFor as Fe}from"../../../core/graph/reader.js";import{resolveName as Ne,stubsNamed as Se,unwrapRef as We}from"../../../core/graph/names.js";import{canRead as ne,customReachable as Le,holdsObjectsScope as Pe,mayActAs as ae}from"../../../core/graph/access.js";import{customObjectRef as ie,authorizeCustom as re,fenceArgv as G}from"./custom-objects.js";import{edgesOf as Ce}from"../../../core/graph/edges.js";import{publish as U}from"../../../core/graph/events.js";import{objectDTO as b}from"../../../core/graph/kinds/dto.js";import{isKind as De,kindNames as Me,kindOf as z}from"../../../core/graph/kinds/registry.js";import{listObjects as Ge,searchObjects as oe}from"../../../core/graph/objects.js";import{checkoutsForCwd as Ue}from"../../../core/graph/repo-sync/repos.js";import{recordWatch as L,unwatch as ze,watchersOf as He,watchesOf as Ve}from"../../../core/graph/watches.js";import{armObjectWaitForWatch as P,settleObjectWaitForUnwatch as Be}from"../../../core/graph/object-waits.js";import{readerFor as v,resolveRef as H}from"../reader.js";import{readDelegationFor as se,runReadLeaf as Ke}from"../../plugin-objects/read-leaf.js";import{invalidRequest as C,isRecord as I}from"./validate.js";import{callerNode as ue,callerStub as V,forwardVerb as ce,originates as le,queryWithoutMachine as B,relayError as D,remoteStub as Ze,unknownError as fe,forwarding as S,withMachine as K}from"../../peer/forward.js";import{getById as W,getByRowid as we}from"../../../core/graph/objects.js";import{ensureNodeStub as Je,isStub as Z,stubOf as Qe,withKindDecl as $}from"../../../core/peer/stubs.js";import{isUnreachable as Ye}from"../../../core/peer/client.js";import{normalizeMachineId as A}from"../../../core/peer/directory.js";import{mapAsync as de}from"../../../core/async-array.js";const F=l(async e=>async t=>await Ue(e,t),"reposFnFor");async function me(e,t){return{...await b(e,t),...await(await z(e,t.type)).listItem?.(e,t)}}l(me,"listItem");function Xe(e){return`no object named ${e} on this runtime; it may be on another runtime, or the name may be misspelled`}l(Xe,"remoteMessage");async function he(e,t,a){try{return await R(e,t,a)}catch(n){if(n instanceof y&&n.code==="not_found"&&!n.details?.deleted)return null;throw n}}l(he,"ownerFilter");async function R(e,t,a){const n=await H(e,t,a);if("remote"in n)throw new y(404,"not_found",Xe(n.remote),{next:"Check the name with `crtr canvas search`."});if("deleted"in n)throw new y(404,"not_found",`${n.deleted.name} is deleted`,{id:n.deleted.id,deleted:!0});return n}l(R,"liveRef");const k=l(e=>decodeURIComponent(e.params.ref),"refParam"),pe=l(e=>{const t=We(e),a=t.indexOf("/");return a>0?t.slice(0,a):t},"idOf");async function ye(e){const t=await W(await T(),pe(e));return t!==null&&await Z(await T(),t)?t.id:null}l(ye,"stubIdOf");async function xe(e,t){const a=await ye(e);return a!==null?{stub:a,hit:!0}:await _(async n=>{try{const i=await v(n,t),o=l(async()=>{const s=await Se(n,i,e);if(s.length>1)throw new y(409,"ambiguous_name",`'${e}' names more than one remote object`,{candidates:s.map(c=>c.id),next:"Read one by its object id."});return{stub:s[0]?.id??null,hit:!1}},"named");let r;try{r=await H(n,i,e)}catch(s){if(s instanceof y&&s.code==="not_found")return await o();throw s}if("remote"in r)return await o();if("deleted"in r){const s=await o();return s.stub===null?{stub:null,hit:!0}:s}return{stub:await Z(n,r)?r.id:null,hit:!0}}catch(i){if(i instanceof y&&i.code==="ambiguous_name")throw i;return{stub:null,hit:!1}}})}l(xe,"resolvedLocally");async function J(e,t,a){const n=await xe(t,e);return n.stub!==null?ce(e,n.stub,a):n.hit||!le(e.principal)?{kind:"local"}:ce(e,pe(t),a)}l(J,"forwardRef");const Q=l(e=>`/v1/objects/${encodeURIComponent(e)}`,"objectPath");async function ge(e,t,a,n,i){const o=t?.object;!o?.id||!o.type||await _(async r=>{const s=await ue(r,e);if(s===null)return;const c=await Ze(r,o.id,o.type,a,{kind:o.kind??null,name:o.name??o.id,...o.preview===void 0?{}:{preview:o.preview},owner:o.owner??null,...o.kind_decl===void 0?{}:{kind_decl:o.kind_decl},...o.privacy===void 0?{}:{privacy:o.privacy}});await L(r,s,c,n,i===void 0?{}:{patterns:i}),n==="ask"&&await P(r,s,c)})}l(ge,"watchRemote");async function et(e){const t=k(e),a=["1","true"].includes(e.query.get("fields")??""),n=await J(e,t,{method:"GET",path:Q(t),query:B(e)});if(n.kind==="unknown")return{state:"unknown",ref:t,unreachable:n.unreachable};if(n.kind==="remote"){if(n.status>=400)throw D(n.status,n.body);return await ge(e,n.body,n.machine.id,"read"),K(n.body,n.machine)}const i=l(async s=>{const c=await V(s,e);return c===null?await v(s,e):await M(s,c,await F(s))},"readerOf"),o=await _(async s=>{const c=await i(s),u=await H(s,c,t);if("remote"in u)return{state:"remote",remote:u.remote};if("deleted"in u)return{state:"deleted",deleted:await b(s,u.deleted)};const f=await se(s,u);if(f!==null)return{delegate:f,hitId:u.id};const{data:h,text:g}=await(await z(s,u.type)).read(s,c,u,{fields:a,reposFn:await F(s)});return{state:"object",type:u.type,object:await $(s,u,await b(s,u)),text:g,data:h}});if(!("delegate"in o))return o;const r=await Ke(o.delegate,e.principal);return await _(async s=>{const c=await i(s),u=await W(s,o.hitId);if(u===null)throw new y(404,"not_found","object not found");if(u.deleted_at!==null)return{state:"deleted",deleted:await b(s,u)};if(!await ne(s,c,u))throw new y(404,"not_found","object not found");const{data:f,text:h}=await(await z(s,u.type)).read(s,c,u,{fields:a,reposFn:await F(s)});return await se(s,u)===null?{state:"object",type:u.type,object:await $(s,u,await b(s,u)),text:h,data:f}:{state:"object",type:u.type,object:await $(s,u,await b(s,u)),text:"markdown"in r?r.markdown:`${h}
2
+ content unavailable: ${r.unavailable}`,data:{...f,content:"markdown"in r?"live":"unavailable"}}})}l(et,"read");function Y(e,t,a,n){if(e!=null){if(!a.includes(e)){n.push({field:t,problem:`must be one of ${a.join(", ")}`,received:e});return}return e}}l(Y,"oneOf");async function be(e,t,a){if(t!=null){if(typeof t!="string"||!await De(e,t)){a.push({field:"type",problem:`must be a kind: one of ${(await Me(e)).join(", ")}`,received:t});return}return t}}l(be,"kindName");function je(e,t,a,n){if(e==null)return n;const i=Number(e);return!Number.isInteger(i)||i<1||i>100?(a.push({field:t,problem:"must be an integer from 1 to 100",received:e}),n):i}l(je,"limitOf");async function _e(e){const t=e.query,a=[],n=await be(await T(),t.get("type"),a),i=Y(t.get("privacy"),"privacy",Ae,a),o=je(t.get("limit"),"limit",a,50),r=t.get("cursor");r!==null&&!/^\d+$/.test(r)&&a.push({field:"cursor",problem:"is not a cursor from a previous page",received:r});const s=t.get("deleted");return s!==null&&!["0","1","true","false"].includes(s)&&a.push({field:"deleted",problem:"must be true or false",received:s}),a.length>0&&C("object list request",a),await _(async c=>{const u=await v(c,e),f={...n?{type:n}:{},...i?{privacy:i}:{},...t.get("kind")!==null?{kind:t.get("kind")}:{},...s==="1"||s==="true"?{deleted:!0}:{}},h=t.get("owner");if(h!==null){const d=await he(c,u,h);if(d===null)return{items:[],next_cursor:null};f.owner=d}const g=t.get("name"),j=[];let m=r===null?0:Number(r),p=!0;for(;j.length<o&&p;){const d=await Ge(c,u,f,{limit:100,after_rowid:m});p=d.length===100;for(const E of d)if(m=E.rowid,(g===null||E.name.startsWith(g))&&j.push(E),j.length===o)break}const w=j.at(-1);return{items:await de(j,async d=>await me(c,d)),next_cursor:j.length===o&&w?String(w.rowid):null}})}l(_e,"listLocal");const tt={ms:3e4},nt="self",X=l((e,t)=>e.map(a=>({...a,machine:t})),"labelItems");async function ke(e,t,a,n){const i=S.current;try{const o=await i.call(t.id,{method:"GET",path:"/v1/objects",query:a},await i.envelope(e.principal),n);if(Ye(o))return{state:"unreachable",items:[],next:null};if(o.status===426)return{state:"too_old",items:[],next:null};const r=o.body;return o.status!==200||!Array.isArray(r?.items)?{state:"unreachable",items:[],next:null}:{state:"ok",items:X(r.items,t),next:r.next_cursor??null}}catch{return{state:"unreachable",items:[],next:null}}}l(ke,"remotePage");async function at(e){const t=new Promise(a=>e.addEventListener("abort",()=>a(null),{once:!0}));return Promise.race([S.current.machines().catch(()=>null),t])}l(at,"machinesWithin");async function it(e){const t=e.query.get("machine");if(!le(e.principal)||!S.current.joined()||t===nt)return await _e(ve(e));const n=S.current.self(),i=t!==null&&A(t)!==n,o=i?null:await _e(ve(e)),r=new AbortController,s=setTimeout(()=>r.abort(),tt.ms);s.unref?.();try{const c=await at(r.signal);if(c===null){if(i)throw new y(503,"runtime_unreachable",`The directory did not answer, so ${A(t)} cannot be listed.`,{machine:A(t)});return o}const u=l(w=>({id:w,name:c.find(d=>d.machine_id===w)?.name??w}),"labelOf"),f=u(n),h=c.filter(w=>w.machine_id!==n&&w.kind!=="device"),g=B(e);if(t!==null){if(!i)return{items:X(o.items,f),next_cursor:o.next_cursor,machines:[{machine_id:n,name:f.name,state:"ok",more:o.next_cursor!==null}]};const w=A(t);if(!h.some(E=>E.machine_id===w))throw new y(404,"not_found",`no machine ${w} on your account`,{machine:w});const d=await ke(e,u(w),g,r.signal);return{items:d.items,next_cursor:d.next,machines:[{machine_id:w,name:u(w).name,state:d.state,more:d.next!==null}]}}const{cursor:j,...m}=g,p=await Promise.all(h.map(w=>ke(e,u(w.machine_id),m,r.signal)));return{items:[...X(o.items,f),...p.flatMap(w=>w.items)],next_cursor:o.next_cursor,machines:[{machine_id:n,name:f.name,state:"ok",more:o.next_cursor!==null},...h.map((w,d)=>({machine_id:w.machine_id,name:w.name,state:p[d].state,more:p[d].next!==null}))]}}finally{clearTimeout(s)}}l(it,"list");function ve(e){const t=new URLSearchParams(e.query);return t.delete("machine"),{...e,query:t}}l(ve,"withoutMachine");async function rt(e){const t=[],a=I(e.body)?e.body:{};I(e.body)||t.push({field:"body",problem:"must be an object",received:e.body});const n=a.text;(typeof n!="string"||n.trim()==="")&&t.push({field:"text",problem:"is required",received:n});const i=a.grep;if(i!==void 0)if(typeof i!="string")t.push({field:"grep",problem:"must be a regular expression string",received:i});else try{new RegExp(i)}catch(s){t.push({field:"grep",problem:`is not a valid regular expression: ${s.message}`,received:i})}a.body!==void 0&&typeof a.body!="boolean"&&t.push({field:"body",problem:"must be a boolean",received:a.body});const o=await be(await T(),a.type,t);a.kind!==void 0&&typeof a.kind!="string"&&t.push({field:"kind",problem:"must be a string",received:a.kind}),a.owner!==void 0&&typeof a.owner!="string"&&t.push({field:"owner",problem:"must be a string",received:a.owner});const r=je(a.limit,"limit",t,50);return t.length>0&&C("object search request",t),await _(async s=>{const c=await v(s,e),u=typeof a.owner=="string"?await he(s,c,a.owner):null;if(typeof a.owner=="string"&&u===null)return{items:[]};const f=await oe(s,c,{text:n,body:a.body===!0||typeof i=="string"}),h=new Set(f.map(m=>m.object.rowid)),j=(typeof i=="string"?(await oe(s,c,{text:i,grep:!0})).filter(m=>h.has(m.object.rowid)):f).filter(m=>(!o||m.object.type===o)&&(a.kind===void 0||m.object.kind===a.kind)&&(!u||m.object.owner===u.rowid));return{items:await de(j.slice(0,r),async m=>({object:await me(s,m.object),...m.line!==void 0?{matches:[{line:m.line,text:m.text??""}]}:{}}))}})}l(rt,"search");const Oe=["interrupt","steer","after-turn","next-turn"],ot=/^(\*|>|[A-Za-z0-9_-]+)(\.(\*|>|[A-Za-z0-9_-]+))*$/;function st(e,t){if(e!==void 0){if(!Array.isArray(e)||e.length===0||e.some(a=>typeof a!="string"||!ot.test(a)||a.includes(">")&&!a.endsWith(">"))){t.push({field:"patterns",problem:"must be a non-empty list of event patterns (dot-separated words, `*` for one word, a final `>` for the rest)",received:e});return}return e}}l(st,"patternsOf");function ut(e,t){if(e===void 0)return;if(!I(e)||Object.keys(e).length===0){t.push({field:"config",problem:"must map levels 1-10 to a delivery",received:e});return}const a=[];for(const[n,i]of Object.entries(e)){const o=Number(n);!Number.isInteger(o)||o<1||o>10?t.push({field:`config.${n}`,problem:"level must be an integer from 1 to 10"}):Oe.includes(i)?a.push({threshold:o,delivery:i}):t.push({field:`config.${n}`,problem:`delivery must be one of ${Oe.join(", ")}`,received:i})}return a.sort((n,i)=>i.threshold-n.threshold)}l(ut,"configOf");async function Ee(e){const t=await ye(e);if(t!==null)throw new y(400,"invalid_request",`${t} lives on another machine; an explicit watcher cannot watch it from here`,{id:t})}l(Ee,"refuseStubWatch");async function x(e,t){const a=await W(e,t)??await(async()=>{const n=await Ne(e,await Fe(e,{class:"person"},async()=>[]),t);return"object"in n?n.object:null})();return a===null||a.deleted_at!==null||!(a.type.includes(".")||a.type==="node")?null:a}l(x,"findWatcher");const O=l(()=>{throw new y(404,"not_found","watcher not found")},"watcherNotFound");async function Re(e,t,a){if(typeof t!="string"||a===void 0||a===null)return null;if(typeof a!="string")throw new y(400,"invalid_request","invalid watcher_machine");if(await x(e,t)!==null)return null;const n=S.current;let i;try{i=await n.machines()}catch{throw new y(503,"runtime_unreachable","The directory did not answer, so the watcher machine cannot be checked.")}const o=A(a);return(o===n.self()||!i.some(r=>A(r.machine_id)===o))&&O(),o}l(Re,"remoteWatcherMachine");async function qe(e,t,a,n){if(t.publishToken||t.principal.class==="anonymous")return O();const i=await v(e,t);if(i.class==="person")return O();let o;try{o=await R(e,i,n)}catch{return O()}const r=o.owner===null?null:await we(e,o.owner);return r===null||!await ae(e,i,r)||!await Pe(e,i,"link",a)?O():(await G(e,t,a),{actor:i.app,object:o})}l(qe,"linkWatcher");async function Te(e,t,a){if(t.publishToken)return!0;if(t.principal.class==="anonymous"||!a.type.includes("."))return!1;const n=await v(e,t),i=a.owner===null?null:await we(e,a.owner);return i!==null&&await ae(e,n,i)&&await Le(e,n,a)}l(Te,"ownsWatcher");async function ct(e){const t=k(e),a=I(e.body)?e.body:{};if(typeof a.watcher=="string"&&await Ee(t),typeof a.watcher!="string"){const i=await J(e,t,{method:"POST",path:`${Q(t)}/watch`,body:e.body});if(i.kind==="unknown")throw fe(t,i.unreachable);if(i.kind==="remote"){if(i.status>=400)throw D(i.status,i.body);const o=i.body.patterns;return await ge(e,i.body,i.machine.id,"ask",o),K(i.body,i.machine)}}const n=await Re(await T(),a.watcher,a.watcher_machine);return await lt(e,n)}l(ct,"watch");async function lt(e,t=null){const a=[],n=e.body===void 0?{}:I(e.body)?e.body:(a.push({field:"body",problem:"must be an object"}),{}),i=st(n.patterns,a),o=ut(n.config,a);return n.filter!==void 0&&!I(n.filter)&&a.push({field:"filter",problem:"must be an object",received:n.filter}),n.watcher!==void 0&&typeof n.watcher!="string"&&a.push({field:"watcher",problem:"must be a custom-object ref",received:n.watcher}),n.watcher_machine!==void 0&&typeof n.watcher_machine!="string"&&a.push({field:"watcher_machine",problem:"must be a machine id",received:n.watcher_machine}),a.length>0&&C("watch request",a),await _(async r=>{const s=typeof n.watcher=="string";if((e.publishToken||e.principal.class==="anonymous")&&!s)throw new y(404,"not_found","watcher not found");const c=i??[">"],u={patterns:c,...o?{config:o}:{},...n.filter!==void 0?{filter:n.filter}:{}};if(s){const j=n.watcher,m=t===null?null:await ft(r,e,j,t),p=m??(e.publishToken?await ie(r,j):await x(r,j));if(p===null)return O();if(m===null&&await Te(r,e,p)){const E=await re(r,e,p);await G(r,e,p);const ee=await M(r,p),q=await R(r,ee,k(e));if(!await ne(r,ee,q))throw new y(404,"not_found","object not found");return await L(r,p,q,"act",u),await P(r,p,q),await U(r,{event:"watched",object:q,actor:E,attrs:{}},await F(r)),{object:await $(r,q,await b(r,q)),patterns:c}}const{actor:w,object:d}=await qe(r,e,p,k(e));return await L(r,p,d,"act",{...u,linkApp:w}),await P(r,p,d),await U(r,{event:"watched",object:d,actor:w,attrs:{}},await F(r)),{object:await $(r,d,await b(r,d)),patterns:c}}const f=await v(r,e),h=await V(r,e)??te(f),g=await R(r,f,k(e));return await L(r,h,g,"ask",u),await P(r,h,g),await U(r,{event:"watched",object:g,actor:h,attrs:{}},await F(r)),{object:await $(r,g,await b(r,g)),patterns:c}})}l(lt,"watchLocal");async function ft(e,t,a,n){return t.publishToken||t.principal.class==="anonymous"?O():await Je(e,a,n)}l(ft,"ensureNodeStubFor");async function Ie(e,t,a,n){const i=l(async()=>(await e.prepare(`SELECT count(*) AS n FROM watch_subscriptions s JOIN watches w ON w.rowid = s.watch
3
+ WHERE w.watcher = ? AND w.object = ?`).get(t.rowid,a.rowid)).n,"count"),o=await i();await ze(e,t,a,n??void 0);const r=await i();return r===0&&await Be(e,t,a),{object:await b(e,a),removed:o-r}}l(Ie,"dropWatch");async function wt(e){const t=k(e);if(e.query.get("watcher")&&await Ee(t),!e.query.get("watcher")){const n=await J(e,t,{method:"DELETE",path:`${Q(t)}/watch`,query:B(e)});if(n.kind==="unknown")throw fe(t,n.unreachable);if(n.kind==="remote"){const i=n.status===404?n.body.error?.details:void 0,o=i?.deleted===!0?i.id:void 0;if(n.status>=400&&o===void 0)throw D(n.status,n.body);const r=o??n.body.object?.id,s=await _(async c=>{const u=await ue(c,e),f=r===void 0?null:await W(c,r);return u===null||f===null||!await Z(c,f)?null:await Ie(c,u,f,e.query.get("pattern"))});if(o!==void 0){if(s===null)throw D(n.status,n.body);return{...s,machine:n.machine}}return K(n.body,n.machine)}}const a=await Re(await T(),e.query.get("watcher")??void 0,e.query.get("watcher_machine")??void 0);return await dt(e,a)}l(wt,"unwatchRoute");async function dt(e,t=null){const a=e.query.get("pattern"),n=e.query.get("watcher");return await _(async i=>{if((e.publishToken||e.principal.class==="anonymous")&&!n)throw new y(404,"not_found","watcher not found");const o=l(async(c,u)=>await Ie(i,c,u,a),"drop");if(n){const c=t===null?null:await(async()=>{const f=await W(i,n);return f!==null&&await Qe(i,f)!==null?f:null})();if(t!==null&&c===null)return O();const u=c??(e.publishToken?await ie(i,n):await x(i,n));return u===null?O():c===null&&await Te(i,e,u)?(await re(i,e,u),await G(i,e,u),await o(u,await R(i,await M(i,u),k(e)))):await o(u,(await qe(i,e,u,k(e))).object)}const r=await v(i,e),s=await V(i,e)??te(r);return await o(s,await R(i,r,k(e)))})}l(dt,"unwatchLocal");async function mt(e){const t=[],a=Y(e.query.get("type"),"type",["acted-on","links-to","watches"],t),n=Y(e.query.get("direction"),"direction",["out","in"],t);return t.length>0&&C("edges request",t),await _(async i=>{const o=await v(i,e),r=await R(i,o,k(e)),s=[];if(a!=="watches")for(const c of await Ce(i,o,r,{...a?{type:a}:{},direction:n??"both"}))s.push({type:c.type,src:await b(i,c.src),dst:await b(i,c.dst),...c.written_as?{written_as:c.written_as}:{}});if(a===void 0||a==="watches"){const c=[...n!=="in"?await Ve(i,o,r):[],...n!=="out"?await He(i,o,r):[]];for(const u of c)s.push({type:"watches",src:await b(i,u.watcher),dst:await b(i,u.object)})}return{items:s}})}l(mt,"edges");const N=l(e=>async t=>({status:200,body:await e(t)}),"ok"),Gt=[{method:"POST",pattern:"/v1/objects/search",handler:N(rt)},{method:"GET",pattern:"/v1/objects/:ref/edges",handler:N(mt)},{method:"POST",pattern:"/v1/objects/:ref/watch",handler:N(ct)},{method:"DELETE",pattern:"/v1/objects/:ref/watch",handler:N(wt)},{method:"GET",pattern:"/v1/objects/:ref",handler:N(et)},{method:"GET",pattern:"/v1/objects",handler:N(it)}];export{tt as listBudget,Gt as objectRoutes};
@@ -1 +1 @@
1
- var a=Object.defineProperty;var o=(e,t)=>a(e,"name",{value:t,configurable:!0});import{withCanvasWrite as c}from"../../../core/canvas/db.js";import{reconcilePackages as r}from"../../../core/graph/package-reconcile.js";const m=[{method:"POST",pattern:"/v1/documents/reconcile-packages",handler:o(()=>({status:200,body:c(e=>r(e))}),"handler")}];export{m as packageDocRoutes};
1
+ var o=Object.defineProperty;var t=(a,e)=>o(a,"name",{value:e,configurable:!0});import{withCanvasWrite as c}from"../../../core/canvas/db.js";import{reconcilePackages as r}from"../../../core/graph/package-reconcile.js";const m=[{method:"POST",pattern:"/v1/documents/reconcile-packages",handler:t(async()=>({status:200,body:await c(async a=>await r(a))}),"handler")}];export{m as packageDocRoutes};
@@ -2,5 +2,5 @@ import type { PluginCallHeadersDTO, PluginCallHeadersRequestDTO } from '../../..
2
2
  import type { RequestPrincipal, RouteTable } from '../router.js';
3
3
  /** The `Crtr-Caller` and, for a call that stays on a local plugin's manifest endpoint, `Crtr-Signature` for one request of `principal` to plugin `name`.
4
4
  * The one signer: the call-headers route and crtrd's own HTTP read leaf both use it. Throws ApiError. */
5
- export declare function signCallHeaders(name: string, principal: RequestPrincipal, request: PluginCallHeadersRequestDTO): PluginCallHeadersDTO;
5
+ export declare function signCallHeaders(name: string, principal: RequestPrincipal, request: PluginCallHeadersRequestDTO): Promise<PluginCallHeadersDTO>;
6
6
  export declare const pluginAppRoutes: RouteTable;
@@ -1 +1 @@
1
- var h=Object.defineProperty;var o=(e,n)=>h(e,"name",{value:n,configurable:!0});import{ApiError as l}from"../../../api/errors.js";import{getNode as g}from"../../../core/canvas/canvas.js";import{formatCrtrCaller as y}from"../../../core/command-plugins/caller-header.js";import{isLoopbackHostname as _}from"../../../core/command-plugins/endpoint.js";import{crtrSignature as w}from"../../../core/command-plugins/transport/sign.js";import{directoryIssuer as k,ownMachineId as b}from"../../../core/peer/directory.js";import{pluginAppCredential as m}from"../../../core/plugin-app.js";import{findPluginByName as v}from"../../../core/resolver.js";import{isRecord as C}from"./validate.js";const p=/^[0-9a-f]{64}$/,c=o(e=>{throw new l(404,"not_found",`plugin "${e}" is not installed, enabled and valid`)},"notFound");function A(e){const{principal:n}=e;if(n.class==="broker"&&n.uid!==process.getuid?.())throw new l(403,"forbidden","this node may not read a plugin app token");const r=e.params.name,t=m(r);return t===null?c(r):{status:200,body:{token:t.token,socket:t.socket}}}o(A,"appToken");function R(e){const n=o(i=>{throw new l(400,"invalid_request",`invalid ${i}`)},"bad");if(!C(e))return n("call-headers request");const{method:r,url:t,body_sha256:d,header_names:s,headers_sha256:a}=e;return(typeof r!="string"||r==="")&&n("method"),typeof t!="string"&&n("url"),(typeof d!="string"||!p.test(d))&&n("body_sha256"),(!Array.isArray(s)||s.some(i=>typeof i!="string"))&&n("header_names"),(typeof a!="string"||!p.test(a))&&n("headers_sha256"),e}o(R,"parseRequest");function E(e){if(e.class==="forwarded"){const r=e.actor.kind==="app"?e.actor:null;return{node:r?.node??void 0,run:r?.place.run,machine:e.via}}const n=e.class==="broker"?e.node:void 0;return{...n===void 0?{}:{node:n,run:e.class==="broker"?e.run??void 0:void 0,profile:g(n)?.profile_id??void 0},machine:k()!==null?b():void 0}}o(E,"callerFields");function H(e,n,r){const t=v(e);if(t===null||!t.enabled||t.manifest.provider!==void 0)return c(e);const d=y(E(n)),s={};d!==""&&(s["Crtr-Caller"]=d);const a=m(e);if(a!==null&&a.endpoint!==null){let i;try{i=new URL(r.url)}catch{throw new l(400,"invalid_request","invalid url")}const u=new URL(a.endpoint);if(i.origin===u.origin&&_(u.hostname))try{s["Crtr-Signature"]=w({token:a.token,method:r.method,url:i,body_sha256:r.body_sha256,caller:d,header_names:r.header_names,headers_sha256:r.headers_sha256,now:Date.now()})}catch(f){throw new l(400,"invalid_request",f instanceof Error?f.message:"invalid signed header list")}}return{headers:s}}o(H,"signCallHeaders");function L(e){return{status:200,body:H(e.params.name,e.principal,R(e.body))}}o(L,"callHeaders");const D=[{method:"GET",pattern:"/v1/plugins/:name/app-token",handler:A},{method:"POST",pattern:"/v1/plugins/:name/call-headers",handler:L}];export{D as pluginAppRoutes,H as signCallHeaders};
1
+ var h=Object.defineProperty;var o=(e,n)=>h(e,"name",{value:n,configurable:!0});import{ApiError as l}from"../../../api/errors.js";import{getNode as g}from"../../../core/canvas/canvas.js";import{formatCrtrCaller as y}from"../../../core/command-plugins/caller-header.js";import{isLoopbackHostname as w}from"../../../core/command-plugins/endpoint.js";import{crtrSignature as _}from"../../../core/command-plugins/transport/sign.js";import{directoryIssuer as k,ownMachineId as b}from"../../../core/peer/directory.js";import{pluginAppCredential as c}from"../../../core/plugin-app.js";import{findPluginByName as v}from"../../../core/resolver.js";import{isRecord as C}from"./validate.js";const m=/^[0-9a-f]{64}$/,p=o(e=>{throw new l(404,"not_found",`plugin "${e}" is not installed, enabled and valid`)},"notFound");function A(e){const{principal:n}=e;if(n.class==="broker"&&n.uid!==process.getuid?.())throw new l(403,"forbidden","this node may not read a plugin app token");const r=e.params.name,t=c(r);return t===null?p(r):{status:200,body:{token:t.token,socket:t.socket}}}o(A,"appToken");function R(e){const n=o(i=>{throw new l(400,"invalid_request",`invalid ${i}`)},"bad");if(!C(e))return n("call-headers request");const{method:r,url:t,body_sha256:s,header_names:d,headers_sha256:a}=e;return(typeof r!="string"||r==="")&&n("method"),typeof t!="string"&&n("url"),(typeof s!="string"||!m.test(s))&&n("body_sha256"),(!Array.isArray(d)||d.some(i=>typeof i!="string"))&&n("header_names"),(typeof a!="string"||!m.test(a))&&n("headers_sha256"),e}o(R,"parseRequest");async function E(e){if(e.class==="forwarded"){const r=e.actor.kind==="app"?e.actor:null;return{node:r?.node??void 0,run:r?.place.run,machine:e.via}}const n=e.class==="broker"?e.node:void 0;return{...n===void 0?{}:{node:n,run:e.class==="broker"?e.run??void 0:void 0,profile:(await g(n))?.profile_id??void 0},machine:k()!==null?b():void 0}}o(E,"callerFields");async function H(e,n,r){const t=v(e);if(t===null||!t.enabled||t.manifest.provider!==void 0)return p(e);const s=y(await E(n)),d={};s!==""&&(d["Crtr-Caller"]=s);const a=c(e);if(a!==null&&a.endpoint!==null){let i;try{i=new URL(r.url)}catch{throw new l(400,"invalid_request","invalid url")}const u=new URL(a.endpoint);if(i.origin===u.origin&&w(u.hostname))try{d["Crtr-Signature"]=_({token:a.token,method:r.method,url:i,body_sha256:r.body_sha256,caller:s,header_names:r.header_names,headers_sha256:r.headers_sha256,now:Date.now()})}catch(f){throw new l(400,"invalid_request",f instanceof Error?f.message:"invalid signed header list")}}return{headers:d}}o(H,"signCallHeaders");async function L(e){return{status:200,body:await H(e.params.name,e.principal,R(e.body))}}o(L,"callHeaders");const D=[{method:"GET",pattern:"/v1/plugins/:name/app-token",handler:A},{method:"POST",pattern:"/v1/plugins/:name/call-headers",handler:L}];export{D as pluginAppRoutes,H as signCallHeaders};
@@ -5,10 +5,10 @@ import { type RequestContext, type RouteTable } from '../router.js';
5
5
  * object is renamed first inside the canvas transaction, which refuses with `conflict` before
6
6
  * anything is written when another live profile object holds the handle; a manifest failure then
7
7
  * rolls the object rename back. */
8
- export declare function renameProfileAndHandle(profileId: string, name: string): ProfileEntry;
8
+ export declare function renameProfileAndHandle(profileId: string, name: string): Promise<ProfileEntry>;
9
9
  /** Add a project path; each repo enclosing it starts at `preview` unless the profile already limits that
10
10
  * handle (bare or `repo:`-typed). Repos are identified before the manifest changes, so a failed lookup adds nothing. */
11
- export declare function addProjectWithDefaultLimit(profileId: string, limits: Readonly<Record<string, string>>, path: string): void;
11
+ export declare function addProjectWithDefaultLimit(profileId: string, limits: Readonly<Record<string, string>>, path: string): Promise<void>;
12
12
  /** One visible profile by exact id or unique name; a miss or an invisible profile is 404. */
13
- export declare function requireUsableProfile(ctx: RequestContext, name: string): ReturnType<typeof listProfiles>[number];
13
+ export declare function requireUsableProfile(ctx: RequestContext, name: string): Promise<ReturnType<typeof listProfiles>[number]>;
14
14
  export declare const profileRoutes: RouteTable;
@@ -1 +1 @@
1
- var N=Object.defineProperty;var a=(r,e)=>N(r,"name",{value:e,configurable:!0});import{assertLaunchKind as c}from"../../../core/runtime/launch-target.js";import{listNodesByProfile as v,shiftProfileNodeDeadlines as q}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as O}from"../../../core/canvas/executions.js";import{shiftAutoBackgroundBashDeadlines as L}from"../../../core/bash-jobs.js";import{contextDir as $}from"../../../core/canvas/node-agent-paths.js";import{boundFleet as S}from"../../../core/runtime/fleet.js";import{recordedPidLiveness as V}from"../../../core/canvas/pid.js";import{withCanvasWrite as P}from"../../../core/canvas/db.js";import{reposForCwd as F}from"../../../core/graph/repo-sync/repos.js";import{renameProfileObject as M}from"../../../core/graph/objects.js";import{usage as l}from"../../../core/errors.js";import{ApiError as f}from"../../../api/errors.js";import{scopeAllowed as w}from"../../../core/scopes.js";import{validateEnvVarName as R}from"../../../core/env-name.js";import{listProfileEnvNames as C,removeProfileEnvVar as G,setProfileEnvVar as U}from"../../../core/profiles/env-store.js";import{isDeploymentName as B,listAppEnvNames as K,removeAppEnvVar as H,setAppEnvVar as W}from"../../../core/profiles/app-env-store.js";import{addProfileProject as z,assertDeliveryLimits as J,setProfileDeliveryLimit as E,assertProfileProjects as h,createProfile as g,ensureRootProfile as Q,listProfiles as u,loadProfileManifest as y,pauseProfile as X,removeProfileProject as Y,renameProfile as Z,resumeProfile as x,setProfileDefaultKind as ee,updateProfileMetadata as re}from"../../../core/profiles/manifest.js";import{requestProfileDeletion as te}from"../../profile-delete.js";import{brokerSignalBus as ne}from"../../broker-signals/bus.js";import{toProfileDTO as d}from"../map.js";import{actsAsPerson as ie,appOf as _,resolvedScopes as oe}from"../router.js";const j="root";function m(r){return _(r.principal)??"app:terminal"}a(m,"callerApp");function A(r,e,n=null){if(u().some(t=>t.manifest.name===e&&t.profileId!==n&&(t.manifest.grantee??"app:terminal")===r))throw new f(400,"invalid_request",`${r} already has a profile named ${e}`)}a(A,"assertNameFree");function p(r,e){const n=I(r,e),t=n.manifest.grantee??"app:terminal";if(r.principal.class!=="person"&&t!==_(r.principal))throw new f(403,"permission_error",`profile ${n.profileId} belongs to ${t}; only that app changes it`);return n}a(p,"requireOwnProfile");async function ae(r){const e=r.body??{};if(typeof e.name!="string"||e.name.trim()==="")throw l("a profile name is required",{field:"name"});e.projects!==void 0&&h(e.projects);const n=m(r),t=e.name.trim();A(n,t),e.default_kind!==void 0&&await c(e.default_kind,process.cwd(),null);const i=g(t,e.projects??[],{defaultKind:e.default_kind,metadata:e.metadata,grantee:n});return{status:201,body:d(i)}}a(ae,"handleCreate");function se(r,e){const n=e.trim();if(n==="")throw l("profile name must not be empty");return P(t=>(M(t,r,n),Z(r,n)))}a(se,"renameProfileAndHandle");function de(r,e,n){const t=P(i=>F(i,n).map(o=>o.name));z(r,n);for(const i of t)e[i]===void 0&&e[`repo:${i}`]===void 0&&E(r,i,"preview")}a(de,"addProjectWithDefaultLimit");async function le(r){const{profileId:e,manifest:n}=p(r,r.params.name),t=r.body??{};return t.name!==void 0&&A(n.grantee??"app:terminal",t.name.trim(),e),t.default_kind!==void 0&&await c(t.default_kind,process.cwd(),e),t.add_project!==void 0&&h([t.add_project]),t.set_delivery_limit!==void 0&&J({[t.set_delivery_limit.owner]:t.set_delivery_limit.level}),t.name!==void 0&&se(e,t.name),t.default_kind!==void 0&&ee(e,t.default_kind),t.add_project!==void 0&&de(e,n.delivery_limits??{},t.add_project.path),t.set_delivery_limit!==void 0&&E(e,t.set_delivery_limit.owner,t.set_delivery_limit.level),t.remove_project!==void 0&&Y(e,t.remove_project),{status:200,body:d(y(e))}}a(le,"handleUpdate");function fe(r){const{profileId:e}=p(r,r.params.name);return{status:200,body:{profile_id:e,names:C(e)}}}a(fe,"handleEnvList");function b(r){const e=r.params.var,n=R(e);if(!n.isValid)throw l(`invalid env var name: ${n.errors.join("; ")}`,{field:"name",received:e});return e}a(b,"requireEnvVarName");function T(r){const e=b(r);if(B(e)&&!ie(r.principal))throw new f(403,"permission_error",`${e} is deployment-wide; only a person changes it`);return e}a(T,"requireSelfEnvVarName");function pe(r){const{profileId:e}=p(r,r.params.name),n=b(r),{value:t}=r.body??{};if(typeof t!="string"||t==="")throw l("a non-empty env value is required",{field:"value"});return{status:200,body:{profile_id:e,changed:U(e,n,t)}}}a(pe,"handleEnvSet");function me(r){const{profileId:e}=p(r,r.params.name),n=b(r);return{status:200,body:{profile_id:e,changed:G(e,n)}}}a(me,"handleEnvRemove");async function ue(r){const e=r.params.name,n=r.body??{};n.projects!==void 0&&h(n.projects);const t=m(r);if(e===j&&t==="app:terminal")return{status:200,body:d(Q())};if(e===j)throw new f(403,"permission_error","root belongs to the terminal app");const i=u().find(s=>s.manifest.name===e&&(s.manifest.grantee??"app:terminal")===t);if(i!==void 0)return{status:200,body:d(i)};n.default_kind!==void 0&&await c(n.default_kind,process.cwd(),null);const o=g(e,n.projects??[],{defaultKind:n.default_kind,metadata:n.metadata,grantee:t});return{status:200,body:d(o)}}a(ue,"handleEnsure");function ce(r){const e=p(r,r.params.name),n=r.body??{};if(typeof n!="object"||n===null||Array.isArray(n))throw l("profile metadata body must be an object",{field:"body"});const t=n,i=t.unset===void 0?[]:t.unset;if(!Array.isArray(i)||i.some(k=>typeof k!="string"))throw l("profile metadata `unset` must be an array of strings",{field:"unset"});const o=t.set===void 0?{}:t.set,s=re(e.profileId,o,i);return{status:200,body:d(s)}}a(ce,"handleSetMetadata");function ve(r){const e=y(r.params.name),n=X(e.profileId),t=v(e.profileId).filter(o=>o.status==="active"||o.status==="idle");if(t.length===0)return{status:200,body:{profile_id:e.profileId,paused_at:n.manifest.paused_at}};const i=S();for(const o of t){const s=i.get(o.node_id);if(s!==void 0){i.interruptForProfilePause(o.node_id,s.pid);continue}o.pi_pid!=null&&V(o.pi_pid,o.pi_pid_identity)==="alive"&&i.interruptForProfilePause(o.node_id,o.pi_pid)}return{status:200,body:{profile_id:e.profileId,paused_at:n.manifest.paused_at}}}a(ve,"handlePause");function he(r){const e=y(r.params.name),n=x(e.profileId);for(const t of v(e.profileId))(t.status==="active"||t.status==="idle"||O(t.node_id)!==null)&&ne.markMail(t.node_id);if(n.pausedAt!==null){const t=Date.parse(n.pausedAt);if(!Number.isNaN(t)){const i=Math.max(0,Date.now()-t);q(e.profileId,i);for(const o of v(e.profileId))o.status!=="dead"&&L($(o.node_id),i)}}return{status:200,body:{profile_id:e.profileId,paused_at:n.manifest.paused_at}}}a(he,"handleResume");function D(r){const e=r.principal;if(e.class==="person")return u();const n=oe(e);return u().filter(({profileId:t,manifest:i})=>{const o=i.grantee??"app:terminal";if(o===_(e))return!0;const s=`crtr:memory:rw:${o}:profile:${t}`;return w(n,s)&&(e.class!=="broker"||w(e.scopes,s))})}a(D,"visibleProfiles");function I(r,e){const n=D(r),t=n.find(({profileId:o})=>o===e),i=t?[t]:n.filter(({manifest:o})=>o.name===e);if(i.length===0)throw new f(404,"not_found","profile not found");if(i.length>1)throw new f(400,"ambiguous","profile name matches multiple visible profiles; use an exact id");return i[0]}a(I,"requireUsableProfile");function ye(r){return{status:200,body:D(r).map(d)}}a(ye,"handleList");function _e(r){return{status:200,body:d(I(r,r.params.name))}}a(_e,"handleGet");async function be(r){return te(p(r,r.params.name).profileId,r.body)}a(be,"handleDelete");const Ue=[{method:"GET",pattern:"/v1/apps/self/env",handler:a(r=>({status:200,body:{names:K(m(r))}}),"handler")},{method:"PUT",pattern:"/v1/apps/self/env/:var",handler:a(r=>{const e=T(r),{value:n}=r.body??{};if(typeof n!="string"||!n)throw l("a non-empty env value is required",{field:"value"});return{status:200,body:{changed:W(m(r),e,n)}}},"handler")},{method:"DELETE",pattern:"/v1/apps/self/env/:var",handler:a(r=>({status:200,body:{changed:H(m(r),T(r))}}),"handler")},{method:"PUT",pattern:"/v1/profiles/:name",handler:ue},{method:"POST",pattern:"/v1/profiles/:name/pause",ownerOnly:!0,handler:ve},{method:"POST",pattern:"/v1/profiles/:name/resume",ownerOnly:!0,handler:he},{method:"PATCH",pattern:"/v1/profiles/:name/metadata",handler:ce},{method:"POST",pattern:"/v1/profiles",handler:ae},{method:"PATCH",pattern:"/v1/profiles/:name",handler:le},{method:"GET",pattern:"/v1/profiles/:name/env",handler:fe},{method:"PUT",pattern:"/v1/profiles/:name/env/:var",handler:pe},{method:"DELETE",pattern:"/v1/profiles/:name/env/:var",handler:me},{method:"DELETE",pattern:"/v1/profiles/:name",handler:be},{method:"GET",pattern:"/v1/profiles",handler:ye},{method:"GET",pattern:"/v1/profiles/:name",handler:_e}];export{de as addProjectWithDefaultLimit,Ue as profileRoutes,se as renameProfileAndHandle,I as requireUsableProfile};
1
+ var N=Object.defineProperty;var o=(t,e)=>N(t,"name",{value:e,configurable:!0});import{assertLaunchKind as c}from"../../../core/runtime/launch-target.js";import{listNodesByProfile as v,shiftProfileNodeDeadlines as q}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as O}from"../../../core/canvas/executions.js";import{shiftAutoBackgroundBashDeadlines as L}from"../../../core/bash-jobs.js";import{contextDir as $}from"../../../core/canvas/node-agent-paths.js";import{boundFleet as S}from"../../../core/runtime/fleet.js";import{recordedPidLiveness as V}from"../../../core/canvas/pid.js";import{withCanvasWrite as b}from"../../../core/canvas/db.js";import{reposForCwd as F}from"../../../core/graph/repo-sync/repos.js";import{renameProfileObject as M}from"../../../core/graph/objects.js";import{usage as l}from"../../../core/errors.js";import{ApiError as f}from"../../../api/errors.js";import{scopeAllowed as P}from"../../../core/scopes.js";import{validateEnvVarName as R}from"../../../core/env-name.js";import{listProfileEnvNames as C,removeProfileEnvVar as G,setProfileEnvVar as U}from"../../../core/profiles/env-store.js";import{isDeploymentName as B,listAppEnvNames as K,removeAppEnvVar as H,setAppEnvVar as W}from"../../../core/profiles/app-env-store.js";import{addProfileProject as z,assertDeliveryLimits as J,setProfileDeliveryLimit as E,assertProfileProjects as h,createProfile as g,ensureRootProfile as Q,listProfiles as u,loadProfileManifest as y,pauseProfile as X,removeProfileProject as Y,renameProfile as Z,resumeProfile as x,setProfileDefaultKind as ee,updateProfileMetadata as te}from"../../../core/profiles/manifest.js";import{requestProfileDeletion as ne}from"../../profile-delete.js";import{brokerSignalBus as re}from"../../broker-signals/bus.js";import{toProfileDTO as d}from"../map.js";import{actsAsPerson as ae,appOf as w,resolvedScopes as ie}from"../router.js";const j="root";function m(t){return w(t.principal)??"app:terminal"}o(m,"callerApp");function A(t,e,r=null){if(u().some(n=>n.manifest.name===e&&n.profileId!==r&&(n.manifest.grantee??"app:terminal")===t))throw new f(400,"invalid_request",`${t} already has a profile named ${e}`)}o(A,"assertNameFree");async function p(t,e){const r=await I(t,e),n=r.manifest.grantee??"app:terminal";if(t.principal.class!=="person"&&n!==w(t.principal))throw new f(403,"permission_error",`profile ${r.profileId} belongs to ${n}; only that app changes it`);return r}o(p,"requireOwnProfile");async function oe(t){const e=t.body??{};if(typeof e.name!="string"||e.name.trim()==="")throw l("a profile name is required",{field:"name"});e.projects!==void 0&&h(e.projects);const r=m(t),n=e.name.trim();A(r,n),e.default_kind!==void 0&&await c(e.default_kind,process.cwd(),null);const a=g(n,e.projects??[],{defaultKind:e.default_kind,metadata:e.metadata,grantee:r});return{status:201,body:d(a)}}o(oe,"handleCreate");async function se(t,e){const r=e.trim();if(r==="")throw l("profile name must not be empty");return await b(async n=>(await M(n,t,r),Z(t,r)))}o(se,"renameProfileAndHandle");async function de(t,e,r){const n=await b(async a=>(await F(a,r)).map(i=>i.name));z(t,r);for(const a of n)e[a]===void 0&&e[`repo:${a}`]===void 0&&E(t,a,"preview")}o(de,"addProjectWithDefaultLimit");async function le(t){const{profileId:e,manifest:r}=await p(t,t.params.name),n=t.body??{};return n.name!==void 0&&A(r.grantee??"app:terminal",n.name.trim(),e),n.default_kind!==void 0&&await c(n.default_kind,process.cwd(),e),n.add_project!==void 0&&h([n.add_project]),n.set_delivery_limit!==void 0&&J({[n.set_delivery_limit.owner]:n.set_delivery_limit.level}),n.name!==void 0&&await se(e,n.name),n.default_kind!==void 0&&ee(e,n.default_kind),n.add_project!==void 0&&await de(e,r.delivery_limits??{},n.add_project.path),n.set_delivery_limit!==void 0&&E(e,n.set_delivery_limit.owner,n.set_delivery_limit.level),n.remove_project!==void 0&&Y(e,n.remove_project),{status:200,body:d(y(e))}}o(le,"handleUpdate");async function fe(t){const{profileId:e}=await p(t,t.params.name);return{status:200,body:{profile_id:e,names:C(e)}}}o(fe,"handleEnvList");function _(t){const e=t.params.var,r=R(e);if(!r.isValid)throw l(`invalid env var name: ${r.errors.join("; ")}`,{field:"name",received:e});return e}o(_,"requireEnvVarName");function T(t){const e=_(t);if(B(e)&&!ae(t.principal))throw new f(403,"permission_error",`${e} is deployment-wide; only a person changes it`);return e}o(T,"requireSelfEnvVarName");async function pe(t){const{profileId:e}=await p(t,t.params.name),r=_(t),{value:n}=t.body??{};if(typeof n!="string"||n==="")throw l("a non-empty env value is required",{field:"value"});return{status:200,body:{profile_id:e,changed:U(e,r,n)}}}o(pe,"handleEnvSet");async function me(t){const{profileId:e}=await p(t,t.params.name),r=_(t);return{status:200,body:{profile_id:e,changed:G(e,r)}}}o(me,"handleEnvRemove");async function ue(t){const e=t.params.name,r=t.body??{};r.projects!==void 0&&h(r.projects);const n=m(t);if(e===j&&n==="app:terminal")return{status:200,body:d(Q())};if(e===j)throw new f(403,"permission_error","root belongs to the terminal app");const a=u().find(s=>s.manifest.name===e&&(s.manifest.grantee??"app:terminal")===n);if(a!==void 0)return{status:200,body:d(a)};r.default_kind!==void 0&&await c(r.default_kind,process.cwd(),null);const i=g(e,r.projects??[],{defaultKind:r.default_kind,metadata:r.metadata,grantee:n});return{status:200,body:d(i)}}o(ue,"handleEnsure");async function ce(t){const e=await p(t,t.params.name),r=t.body??{};if(typeof r!="object"||r===null||Array.isArray(r))throw l("profile metadata body must be an object",{field:"body"});const n=r,a=n.unset===void 0?[]:n.unset;if(!Array.isArray(a)||a.some(k=>typeof k!="string"))throw l("profile metadata `unset` must be an array of strings",{field:"unset"});const i=n.set===void 0?{}:n.set,s=te(e.profileId,i,a);return{status:200,body:d(s)}}o(ce,"handleSetMetadata");async function ve(t){const e=y(t.params.name),r=X(e.profileId),n=(await v(e.profileId)).filter(i=>i.status==="active"||i.status==="idle");if(n.length===0)return{status:200,body:{profile_id:e.profileId,paused_at:r.manifest.paused_at}};const a=S();for(const i of n){const s=a.get(i.node_id);if(s!==void 0){a.interruptForProfilePause(i.node_id,s.pid);continue}i.pi_pid!=null&&V(i.pi_pid,i.pi_pid_identity)==="alive"&&a.interruptForProfilePause(i.node_id,i.pi_pid)}return{status:200,body:{profile_id:e.profileId,paused_at:r.manifest.paused_at}}}o(ve,"handlePause");async function he(t){const e=y(t.params.name),r=x(e.profileId);for(const n of await v(e.profileId))(n.status==="active"||n.status==="idle"||await O(n.node_id)!==null)&&re.markMail(n.node_id);if(r.pausedAt!==null){const n=Date.parse(r.pausedAt);if(!Number.isNaN(n)){const a=Math.max(0,Date.now()-n);await q(e.profileId,a);for(const i of await v(e.profileId))i.status!=="dead"&&L(await $(i.node_id),a)}}return{status:200,body:{profile_id:e.profileId,paused_at:r.manifest.paused_at}}}o(he,"handleResume");async function D(t){const e=t.principal;if(e.class==="person")return u();const r=await ie(e);return u().filter(({profileId:n,manifest:a})=>{const i=a.grantee??"app:terminal";if(i===w(e))return!0;const s=`crtr:memory:rw:${i}:profile:${n}`;return P(r,s)&&(e.class!=="broker"||P(e.scopes,s))})}o(D,"visibleProfiles");async function I(t,e){const r=await D(t),n=r.find(({profileId:i})=>i===e),a=n?[n]:r.filter(({manifest:i})=>i.name===e);if(a.length===0)throw new f(404,"not_found","profile not found");if(a.length>1)throw new f(400,"ambiguous","profile name matches multiple visible profiles; use an exact id");return a[0]}o(I,"requireUsableProfile");async function ye(t){return{status:200,body:(await D(t)).map(d)}}o(ye,"handleList");async function we(t){return{status:200,body:d(await I(t,t.params.name))}}o(we,"handleGet");async function _e(t){return ne((await p(t,t.params.name)).profileId,t.body)}o(_e,"handleDelete");const Ue=[{method:"GET",pattern:"/v1/apps/self/env",handler:o(t=>({status:200,body:{names:K(m(t))}}),"handler")},{method:"PUT",pattern:"/v1/apps/self/env/:var",handler:o(t=>{const e=T(t),{value:r}=t.body??{};if(typeof r!="string"||!r)throw l("a non-empty env value is required",{field:"value"});return{status:200,body:{changed:W(m(t),e,r)}}},"handler")},{method:"DELETE",pattern:"/v1/apps/self/env/:var",handler:o(t=>({status:200,body:{changed:H(m(t),T(t))}}),"handler")},{method:"PUT",pattern:"/v1/profiles/:name",handler:ue},{method:"POST",pattern:"/v1/profiles/:name/pause",ownerOnly:!0,handler:ve},{method:"POST",pattern:"/v1/profiles/:name/resume",ownerOnly:!0,handler:he},{method:"PATCH",pattern:"/v1/profiles/:name/metadata",handler:ce},{method:"POST",pattern:"/v1/profiles",handler:oe},{method:"PATCH",pattern:"/v1/profiles/:name",handler:le},{method:"GET",pattern:"/v1/profiles/:name/env",handler:fe},{method:"PUT",pattern:"/v1/profiles/:name/env/:var",handler:pe},{method:"DELETE",pattern:"/v1/profiles/:name/env/:var",handler:me},{method:"DELETE",pattern:"/v1/profiles/:name",handler:_e},{method:"GET",pattern:"/v1/profiles",handler:ye},{method:"GET",pattern:"/v1/profiles/:name",handler:we}];export{de as addProjectWithDefaultLimit,Ue as profileRoutes,se as renameProfileAndHandle,I as requireUsableProfile};
@@ -25,7 +25,7 @@ export interface ProviderCaller {
25
25
  machine: string;
26
26
  };
27
27
  }
28
- export declare function callerFromRequest(principal: RequestPrincipal): ProviderCaller;
28
+ export declare function callerFromRequest(principal: RequestPrincipal): Promise<ProviderCaller>;
29
29
  export declare function callerFromApp(principal: AppPrincipal): ProviderCaller;
30
30
  /** Does the caller hold `<provider>:<group>`? Both the resolved set and a
31
31
  * broker's node list must cover it. */
@@ -1 +1 @@
1
- var R=Object.defineProperty;var i=(e,r)=>R(e,"name",{value:r,configurable:!0});import{randomUUID as I}from"node:crypto";import{readConfig as $}from"../../../core/config.js";import{activeGrantForApp as O,grantFor as q,localGrants as b}from"../../../core/grants/mirror.js";import{getNode as x}from"../../../core/canvas/canvas.js";import{scopeAllowed as G}from"../../../core/scopes.js";import{ProviderError as u,providerErrorBody as N,scopeMissing as T}from"../../../core/providers/errors.js";import{callProvider as F,providerTools as C}from"../../../core/providers/call.js";import{providerIdsFromGrants as j,providerInstallState as k}from"../../../core/providers/bundles.js";import{providerRootClaims as D,resolveProviderRef as M}from"../../../core/providers/roots.js";import{listInstalledPlugins as U}from"../../../core/resolver.js";import{listAudit as z,writeProviderAudit as L}from"../../../core/providers/audit.js";import{emitEvent as _}from"../../../core/events/emit.js";import{resolvedScopes as g}from"../router.js";const be=new Set(["provider.tools","provider.call","audit.list"]);function V(e){if(e.class==="forwarded"){if(e.actor.kind==="person")return{class:"person",sub:null,grantee:null,client_id:null,resolved:null,nodeScopes:null,run_id:null,node_id:null,origin:{node:null,run:null,machine:e.via}};const r=q(e.actor.app,e.sub);if(!r)throw new u("grant_revoked",`app ${e.actor.app} has no active grant`);return{class:"app",sub:e.sub,grantee:e.actor.app,client_id:null,resolved:r.resolved,nodeScopes:e.actor.node_scopes,run_id:null,node_id:null,origin:{node:e.actor.node,run:e.actor.place?.run??null,machine:e.via}}}if(e.class==="machine")throw new u("permission_error","this operation is not available to the caller");if(e.class==="person")return{class:"person",sub:null,grantee:null,client_id:null,resolved:null,nodeScopes:null,run_id:null,node_id:null};if(e.class==="app"){const r=O(e.app);if(!r)throw new u("grant_revoked",`app ${e.app} has no active grant`);return{class:"app",sub:r.sub,grantee:e.app,client_id:null,resolved:r.resolved,nodeScopes:e.scopes,run_id:null,node_id:null}}return e.class==="cron"?{class:"app",sub:e.sub,grantee:e.app,client_id:null,resolved:g(e),nodeScopes:e.scopes,run_id:e.origin_run,node_id:null}:{class:"broker",sub:e.sub,grantee:e.app,client_id:e.client_id,resolved:g(e),nodeScopes:e.scopes,run_id:e.run??x(e.node)?.run_id??null,node_id:e.node}}i(V,"callerFromRequest");function _e(e){return{class:"app",sub:e.sub,grantee:e.grantee,client_id:e.client_id,resolved:e.resolved,nodeScopes:null,run_id:null,node_id:null}}i(_e,"callerFromApp");const Z=/^([A-Za-z0-9_-]{1,64}):([A-Za-z0-9_-]{1,64})$/;function B(e){const r=Z.exec(e);return r!==null&&r[1]!=="crtr"}i(B,"isProviderScope");const w=new WeakMap;function W(e){let r=w.get(e);return r===void 0&&(r=new Set(e),w.set(e,r)),r}i(W,"heldSet");function y(e,r){return e===null?!0:B(r)?W(e).has(r):G(e,r)}i(y,"holds");function S(e,r){return e.class==="person"?!0:y(e.resolved??[],r)&&y(e.nodeScopes,r)}i(S,"callerAllows");function ge(e,r,t){const o=`${r}:${t}`;if(!S(e,o))throw T(o)}i(ge,"requireGroup");function J(){return!!$("user").runtime?.issuer}i(J,"providerOperationsEnabled");const X=/^[A-Za-z0-9_-]{1,64}$/;function m(e,r){return new u("invalid_request",e,{param:r})}i(m,"invalid");function A(e){if(typeof e!="string"||!X.test(e)||e==="crtr")throw m("provider must be a provider id","provider");return e}i(A,"parseProvider");function H(e){if(!e||typeof e!="object"||Array.isArray(e))throw new u("invalid_request","a JSON object is required");const r=e,t=A(r.provider),o=r.tool;if(typeof o!="string"||!o.trim())throw m("tool must be a non-empty string","tool");const d=r.arguments??{};if(!d||typeof d!="object"||Array.isArray(d))throw m("arguments must be an object","arguments");const a=r.version;if(a!==void 0&&(typeof a!="number"||!Number.isInteger(a)||a<1))throw m("version must be an integer >= 1","version");const n=r.approval;if(n!==void 0&&(typeof n!="string"||!n))throw m("approval must be a question id","approval");const l=r.machine;if(l!==void 0&&(typeof l!="string"||!l.trim()))throw m("machine must be a machine id","machine");return{provider:t,tool:o.trim(),arguments:d,...a===void 0?{}:{version:a},...n===void 0?{}:{approval:n},...l===void 0?{}:{machine:l.trim()}}}i(H,"parseCallInput");function K(e,r=new URLSearchParams){const t=i((n,l,v)=>{const f=r.get(n);if(f===null)return l;if(!/^\d+$/.test(f)||Number(f)>v||Number(f)<1)throw m(`invalid ${n}`,n);return Number(f)},"numeric"),o=r.has("after")?t("after",0,Number.MAX_SAFE_INTEGER):void 0,d=t("limit",100,1e3),a=Object.fromEntries(["operation","outcome","run_id","since","until"].filter(n=>r.has(n)).map(n=>[n,r.get(n)]));return{status:200,body:z(e.class==="person"?null:e.grantee,{after:o,limit:d,...a})}}i(K,"auditList");async function Q(e,r,t){let o=r;const d=performance.now(),a=U("user"),{skipped:n}=D(a),l=new Set(a.filter(s=>s.enabled&&s.manifest.provider?.id===s.name&&!n.has(s.name)).map(s=>s.name)),v=j(b()).filter(s=>!n.has(s)),f=[...new Set([...l,...v])].sort();if(o!==void 0){const s=M(o);if(s===null)throw new u("not_found",`provider "${o}" is not available`);o=s}if(o!==void 0&&!f.includes(o))throw new u("not_found",`provider "${o}" is not available`);const E=o===void 0?f:[o],P=e.class==="person"?b().flatMap(s=>s.status==="active"?s.resolved_scopes.map(({scope:c})=>c):[]):e.resolved??[],p=await Promise.all(E.map(async s=>{if(l.has(s))return C(e,s);if(!P.some(h=>h.startsWith(`${s}:`)&&S(e,h)))return null;const c=k(s);return{provider:s,display_name:s,status:c.status,...c.error?{error:c.error}:{},groups:[],commands:[]}})).then(s=>s.filter(c=>c!==null));if(_({level:"debug",event:"api.provider.tools",duration_ms:performance.now()-d,fields:{caller:e.class,provider:o??null,providers:p.length}}),o!==void 0){if(p.length===0)throw new u("not_found",`provider "${o}" is not available`);return{status:200,body:p[0]}}return{status:200,body:{providers:p}}}i(Q,"providerTools");async function Y(e,r,t){return F(e,r,t)}i(Y,"providerCall");async function ee(e,r,t,o){if(!J())throw new u("not_found","provider operations need a directory-connected runtime");if(e==="audit.list")return K(r,t.query);if(e==="provider.tools")return Q(r,t.params.provider===void 0?void 0:A(t.params.provider),o);if(e==="provider.call"){let d;try{d=H(t.body)}catch(a){const n=t.body&&typeof t.body=="object"&&!Array.isArray(t.body)?t.body:{};throw L({request_id:o.requestId,caller:r,provider:typeof n.provider=="string"?n.provider:"",tool:typeof n.tool=="string"?n.tool:"",outcome:`refused:${a instanceof u?a.code:"invalid_request"}`}),a}return Y(r,d,o)}throw new u("not_found","unknown operation")}i(ee,"handleProviderOperation");function re(e){const r=new AbortController,t=i(()=>{e.writableFinished||r.abort()},"abort");return e.on("close",t),{signal:r.signal,release:i(()=>e.off("close",t),"release")}}i(re,"abortOnClose");function oe(e,r,t,o){const d=N(e,r,t,o??void 0);return d.status>=500&&!(e instanceof u)&&_({event:"api.provider.failed",level:"error",error:e instanceof Error?e:new Error(String(e)),fields:{request_id:r}}),d}i(oe,"providerFailure");const we=[{method:"GET",pattern:"/v1/audit",name:"audit.list"},{method:"GET",pattern:"/v1/providers/tools",name:"provider.tools"},{method:"GET",pattern:"/v1/providers/:provider/tools",name:"provider.tools"},{method:"POST",pattern:"/v1/provider/call",name:"provider.call"}].map(({method:e,pattern:r,name:t})=>({method:e,pattern:r,handler:i(async o=>{const d=I(),{signal:a,release:n}=re(o.res);let l=null;try{return l=V(o.principal),{...await ee(t,l,{params:o.params,body:o.body,query:new URL(o.req.url??"/","http://runtime.local").searchParams},{requestId:d,signal:a}),headers:{"Request-Id":d}}}catch(v){return oe(v,d,!1,l?.run_id)}finally{n()}},"handler")}));export{be as PROVIDER_OPERATIONS,re as abortOnClose,S as callerAllows,_e as callerFromApp,V as callerFromRequest,ee as handleProviderOperation,H as parseCallInput,A as parseProvider,oe as providerFailure,J as providerOperationsEnabled,we as providerRoutes,ge as requireGroup};
1
+ var R=Object.defineProperty;var i=(e,r)=>R(e,"name",{value:r,configurable:!0});import{randomUUID as I}from"node:crypto";import{readConfig as $}from"../../../core/config.js";import{activeGrantForApp as O,grantFor as q,localGrants as w}from"../../../core/grants/mirror.js";import{getNode as x}from"../../../core/canvas/canvas.js";import{scopeAllowed as G}from"../../../core/scopes.js";import{ProviderError as u,providerErrorBody as N,scopeMissing as T}from"../../../core/providers/errors.js";import{callProvider as F,providerTools as C}from"../../../core/providers/call.js";import{providerIdsFromGrants as j,providerInstallState as k}from"../../../core/providers/bundles.js";import{providerRootClaims as D,resolveProviderRef as M}from"../../../core/providers/roots.js";import{listInstalledPlugins as U}from"../../../core/resolver.js";import{listAudit as z,writeProviderAudit as L}from"../../../core/providers/audit.js";import{emitEvent as b}from"../../../core/events/emit.js";import{resolvedScopes as _}from"../router.js";const we=new Set(["provider.tools","provider.call","audit.list"]);async function V(e){if(e.class==="forwarded"){if(e.actor.kind==="person")return{class:"person",sub:null,grantee:null,client_id:null,resolved:null,nodeScopes:null,run_id:null,node_id:null,origin:{node:null,run:null,machine:e.via}};const r=await q(e.actor.app,e.sub);if(!r)throw new u("grant_revoked",`app ${e.actor.app} has no active grant`);return{class:"app",sub:e.sub,grantee:e.actor.app,client_id:null,resolved:r.resolved,nodeScopes:e.actor.node_scopes,run_id:null,node_id:null,origin:{node:e.actor.node,run:e.actor.place?.run??null,machine:e.via}}}if(e.class==="machine")throw new u("permission_error","this operation is not available to the caller");if(e.class==="person")return{class:"person",sub:null,grantee:null,client_id:null,resolved:null,nodeScopes:null,run_id:null,node_id:null};if(e.class==="app"){const r=await O(e.app);if(!r)throw new u("grant_revoked",`app ${e.app} has no active grant`);return{class:"app",sub:r.sub,grantee:e.app,client_id:null,resolved:r.resolved,nodeScopes:e.scopes,run_id:null,node_id:null}}return e.class==="cron"?{class:"app",sub:e.sub,grantee:e.app,client_id:null,resolved:await _(e),nodeScopes:e.scopes,run_id:e.origin_run,node_id:null}:{class:"broker",sub:e.sub,grantee:e.app,client_id:e.client_id,resolved:await _(e),nodeScopes:e.scopes,run_id:e.run??(await x(e.node))?.run_id??null,node_id:e.node}}i(V,"callerFromRequest");function be(e){return{class:"app",sub:e.sub,grantee:e.grantee,client_id:e.client_id,resolved:e.resolved,nodeScopes:null,run_id:null,node_id:null}}i(be,"callerFromApp");const Z=/^([A-Za-z0-9_-]{1,64}):([A-Za-z0-9_-]{1,64})$/;function B(e){const r=Z.exec(e);return r!==null&&r[1]!=="crtr"}i(B,"isProviderScope");const g=new WeakMap;function W(e){let r=g.get(e);return r===void 0&&(r=new Set(e),g.set(e,r)),r}i(W,"heldSet");function y(e,r){return e===null?!0:B(r)?W(e).has(r):G(e,r)}i(y,"holds");function S(e,r){return e.class==="person"?!0:y(e.resolved??[],r)&&y(e.nodeScopes,r)}i(S,"callerAllows");function _e(e,r,t){const o=`${r}:${t}`;if(!S(e,o))throw T(o)}i(_e,"requireGroup");function J(){return!!$("user").runtime?.issuer}i(J,"providerOperationsEnabled");const X=/^[A-Za-z0-9_-]{1,64}$/;function m(e,r){return new u("invalid_request",e,{param:r})}i(m,"invalid");function A(e){if(typeof e!="string"||!X.test(e)||e==="crtr")throw m("provider must be a provider id","provider");return e}i(A,"parseProvider");function H(e){if(!e||typeof e!="object"||Array.isArray(e))throw new u("invalid_request","a JSON object is required");const r=e,t=A(r.provider),o=r.tool;if(typeof o!="string"||!o.trim())throw m("tool must be a non-empty string","tool");const a=r.arguments??{};if(!a||typeof a!="object"||Array.isArray(a))throw m("arguments must be an object","arguments");const d=r.version;if(d!==void 0&&(typeof d!="number"||!Number.isInteger(d)||d<1))throw m("version must be an integer >= 1","version");const n=r.approval;if(n!==void 0&&(typeof n!="string"||!n))throw m("approval must be a question id","approval");const l=r.machine;if(l!==void 0&&(typeof l!="string"||!l.trim()))throw m("machine must be a machine id","machine");return{provider:t,tool:o.trim(),arguments:a,...d===void 0?{}:{version:d},...n===void 0?{}:{approval:n},...l===void 0?{}:{machine:l.trim()}}}i(H,"parseCallInput");async function K(e,r=new URLSearchParams){const t=i((n,l,v)=>{const f=r.get(n);if(f===null)return l;if(!/^\d+$/.test(f)||Number(f)>v||Number(f)<1)throw m(`invalid ${n}`,n);return Number(f)},"numeric"),o=r.has("after")?t("after",0,Number.MAX_SAFE_INTEGER):void 0,a=t("limit",100,1e3),d=Object.fromEntries(["operation","outcome","run_id","since","until"].filter(n=>r.has(n)).map(n=>[n,r.get(n)]));return{status:200,body:await z(e.class==="person"?null:e.grantee,{after:o,limit:a,...d})}}i(K,"auditList");async function Q(e,r,t){let o=r;const a=performance.now(),d=U("user"),{skipped:n}=D(d),l=new Set(d.filter(s=>s.enabled&&s.manifest.provider?.id===s.name&&!n.has(s.name)).map(s=>s.name)),v=j(await w()).filter(s=>!n.has(s)),f=[...new Set([...l,...v])].sort();if(o!==void 0){const s=M(o);if(s===null)throw new u("not_found",`provider "${o}" is not available`);o=s}if(o!==void 0&&!f.includes(o))throw new u("not_found",`provider "${o}" is not available`);const E=o===void 0?f:[o],P=e.class==="person"?(await w()).flatMap(s=>s.status==="active"?s.resolved_scopes.map(({scope:c})=>c):[]):e.resolved??[],p=await Promise.all(E.map(async s=>{if(l.has(s))return C(e,s);if(!P.some(h=>h.startsWith(`${s}:`)&&S(e,h)))return null;const c=k(s);return{provider:s,display_name:s,status:c.status,...c.error?{error:c.error}:{},groups:[],commands:[]}})).then(s=>s.filter(c=>c!==null));if(b({level:"debug",event:"api.provider.tools",duration_ms:performance.now()-a,fields:{caller:e.class,provider:o??null,providers:p.length}}),o!==void 0){if(p.length===0)throw new u("not_found",`provider "${o}" is not available`);return{status:200,body:p[0]}}return{status:200,body:{providers:p}}}i(Q,"providerTools");async function Y(e,r,t){return F(e,r,t)}i(Y,"providerCall");async function ee(e,r,t,o){if(!J())throw new u("not_found","provider operations need a directory-connected runtime");if(e==="audit.list")return await K(r,t.query);if(e==="provider.tools")return Q(r,t.params.provider===void 0?void 0:A(t.params.provider),o);if(e==="provider.call"){let a;try{a=H(t.body)}catch(d){const n=t.body&&typeof t.body=="object"&&!Array.isArray(t.body)?t.body:{};throw await L({request_id:o.requestId,caller:r,provider:typeof n.provider=="string"?n.provider:"",tool:typeof n.tool=="string"?n.tool:"",outcome:`refused:${d instanceof u?d.code:"invalid_request"}`}),d}return Y(r,a,o)}throw new u("not_found","unknown operation")}i(ee,"handleProviderOperation");function re(e){const r=new AbortController,t=i(()=>{e.writableFinished||r.abort()},"abort");return e.on("close",t),{signal:r.signal,release:i(()=>e.off("close",t),"release")}}i(re,"abortOnClose");function oe(e,r,t,o){const a=N(e,r,t,o??void 0);return a.status>=500&&!(e instanceof u)&&b({event:"api.provider.failed",level:"error",error:e instanceof Error?e:new Error(String(e)),fields:{request_id:r}}),a}i(oe,"providerFailure");const ge=[{method:"GET",pattern:"/v1/audit",name:"audit.list"},{method:"GET",pattern:"/v1/providers/tools",name:"provider.tools"},{method:"GET",pattern:"/v1/providers/:provider/tools",name:"provider.tools"},{method:"POST",pattern:"/v1/provider/call",name:"provider.call"}].map(({method:e,pattern:r,name:t})=>({method:e,pattern:r,handler:i(async o=>{const a=I(),{signal:d,release:n}=re(o.res);let l=null;try{return l=await V(o.principal),{...await ee(t,l,{params:o.params,body:o.body,query:new URL(o.req.url??"/","http://runtime.local").searchParams},{requestId:a,signal:d}),headers:{"Request-Id":a}}}catch(v){return oe(v,a,!1,l?.run_id)}finally{n()}},"handler")}));export{we as PROVIDER_OPERATIONS,re as abortOnClose,S as callerAllows,be as callerFromApp,V as callerFromRequest,ee as handleProviderOperation,H as parseCallInput,A as parseProvider,oe as providerFailure,J as providerOperationsEnabled,ge as providerRoutes,_e as requireGroup};
@@ -1 +1 @@
1
- var b=Object.defineProperty;var i=(e,t)=>b(e,"name",{value:t,configurable:!0});import{validatePageTicketResponses as v}from"../../../core/human/tickets.js";import{getRequest as l}from"../../../core/human/requests.js";import{RunError as u}from"../../../core/runs/operations.js";import{getQuestion as R,questionObject as m,questionResult as A,questionStatus as w}from"../../../core/runs/questions.js";import{answerPageTicket as O,cancelHumanTicket as S}from"../../human/finish.js";import{requireRun as T}from"../router.js";const H=new Set(["question.get","question.answer","question.cancel"]),d=i(()=>new u(404,"not_found","question not found"),"missing");function q(e,t,n){const r=R(t);if(r===null)throw d();if(r.run===null){if(r.approval?.grantee!==e.grantee||r.approval.sub!==e.sub)throw d()}else try{T(e,r.run.run_id,n)}catch(s){throw s instanceof u&&s.code==="not_found"?d():s}return r}i(q,"reachable");function f(e){const t=l(e);return new u(409,"run_settled",`question ${e} is already ${w(t)}`,void 0,{state:w(t),result:A(t)})}i(f,"settled");function j(e){return/slot(?: id)? "([^"]+)"/.exec(e)?.[1]??"responses"}i(j,"slotParam");async function U(e,t,n,r){if(e==="question.get"){const{request:o,run:c,approval:_}=q(t,n,!1);return{status:200,body:m(o,c,_)}}const{request:s,run:g,approval:h}=q(t,n,!0);if(s.state==="settled")throw f(n);if(e==="question.cancel"){if((await S(s.request_id,{reason:"dismissed from the app",actor:t.grantee,disposition:"dismissed"})).outcome==="already_settled")throw f(n);return{status:200,body:m(l(n),g,h)}}const a=r&&typeof r=="object"&&!Array.isArray(r)?r.responses:void 0;if(!a||typeof a!="object"||Array.isArray(a))throw new u(400,"invalid_request","responses must be an object keyed by slot id","responses");try{v(s.request_dir,a)}catch(o){const c=o instanceof Error?o.message:String(o);throw new u(400,"invalid_request",c,j(c))}const p=await O(s.request_id,a,{actor:t.grantee});if(p.outcome==="already_settled")throw f(n);const y=p.result;return{status:200,body:{question_id:s.request_id,status:"answered",answer:y.responses}}}i(U,"handleQuestionOperation");export{H as QUESTION_OPERATIONS,U as handleQuestionOperation};
1
+ var b=Object.defineProperty;var o=(e,t)=>b(e,"name",{value:t,configurable:!0});import{validatePageTicketResponses as v}from"../../../core/human/tickets.js";import{getRequest as p}from"../../../core/human/requests.js";import{RunError as u}from"../../../core/runs/operations.js";import{getQuestion as R,questionObject as l,questionResult as A,questionStatus as m}from"../../../core/runs/questions.js";import{answerPageTicket as O,cancelHumanTicket as S}from"../../human/finish.js";import{requireRun as T}from"../router.js";const H=new Set(["question.get","question.answer","question.cancel"]),w=o(()=>new u(404,"not_found","question not found"),"missing");async function q(e,t,n){const s=await R(t);if(s===null)throw w();if(s.run===null){if(s.approval?.grantee!==e.grantee||s.approval.sub!==e.sub)throw w()}else try{await T(e,s.run.run_id,n)}catch(r){throw r instanceof u&&r.code==="not_found"?w():r}return s}o(q,"reachable");async function d(e){const t=await p(e);return new u(409,"run_settled",`question ${e} is already ${m(t)}`,void 0,{state:m(t),result:A(t)})}o(d,"settled");function j(e){return/slot(?: id)? "([^"]+)"/.exec(e)?.[1]??"responses"}o(j,"slotParam");async function U(e,t,n,s){if(e==="question.get"){const{request:a,run:c,approval:_}=await q(t,n,!1);return{status:200,body:await l(a,c,_)}}const{request:r,run:y,approval:g}=await q(t,n,!0);if(r.state==="settled")throw await d(n);if(e==="question.cancel"){if((await S(r.request_id,{reason:"dismissed from the app",actor:t.grantee,disposition:"dismissed"})).outcome==="already_settled")throw await d(n);return{status:200,body:await l(await p(n),y,g)}}const i=s&&typeof s=="object"&&!Array.isArray(s)?s.responses:void 0;if(!i||typeof i!="object"||Array.isArray(i))throw new u(400,"invalid_request","responses must be an object keyed by slot id","responses");try{await v(r.request_dir,i)}catch(a){const c=a instanceof Error?a.message:String(a);throw new u(400,"invalid_request",c,j(c))}const f=await O(r.request_id,i,{actor:t.grantee});if(f.outcome==="already_settled")throw await d(n);const h=f.result;return{status:200,body:{question_id:r.request_id,status:"answered",answer:h.responses}}}o(U,"handleQuestionOperation");export{H as QUESTION_OPERATIONS,U as handleQuestionOperation};
@@ -2,5 +2,5 @@ import type { ReportDTO } from '../../../api/index.js';
2
2
  import type { RouteTable } from '../router.js';
3
3
  /** One node's report documents, newest first, read as the person (records nothing). This stays
4
4
  * in the daemon so collection projections can include report activity without client-side N+1s. */
5
- export declare function reportsForNode(id: string): ReportDTO[];
5
+ export declare function reportsForNode(id: string): Promise<ReportDTO[]>;
6
6
  export declare const reportRoutes: RouteTable;
@@ -1,18 +1,18 @@
1
- var B=Object.defineProperty;var d=(t,e)=>B(t,"name",{value:e,configurable:!0});import{existsSync as M,rmSync as j}from"node:fs";import{getNode as a}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as J}from"../../../core/canvas/executions.js";import{markStopSignal as z}from"../../../core/runtime/stop-signals.js";import{emitEvent as L}from"../../../core/events/emit.js";import{push as W,FinalizationError as S,StructuredRequestFinalizationError as H}from"../../../core/feed/feed.js";import{branchIsPushedAtCurrentTip as X,hasOpenManagedWorktree as G,missingWorktreeRecoveryHint as K}from"../../../core/worktree.js";import{autoDropCleanManagedWorktreeAsync as U}from"../../../core/worktree-mutation-async.js";import{openDb as V,withCanvasWrite as Y}from"../../../core/canvas/db.js";import{get as Q}from"../../../core/graph/bodies.js";import{heads as Z}from"../../../core/graph/documents.js";import{listObjects as ee,nodeObject as te}from"../../../core/graph/objects.js";import{readerFor as re}from"../../../core/graph/reader.js";import{notFound as ne,usage as f}from"../../../core/errors.js";import{InputError as u}from"../../../core/io.js";import{toReportResultDTO as ie}from"../map.js";import{clearSchemaReprompts as oe,outputDeclinedPath as se,stageStructuredResult as de,structuredRequestResultPath as ae,validateStructuredResult as ue}from"../../../core/runtime/structured-output.js";import{getPendingStructuredRequestForNode as _,getStructuredRequest as R,settleStructuredRequestIn as le}from"../../../core/canvas/structured-requests.js";import{ApiError as p}from"../../../api/errors.js";import{applySettlementEffects as $}from"../../structured-requests/effects.js";import{nodeEventStreams as x}from"./node-events.js";import{emitRunEvent as E}from"../../../core/runs/events.js";function g(t){const e=a(t);if(e===null)throw ne(`unknown node: ${t}`,{received:t});return e}d(g,"requireNode");function ce(t){if(typeof t!="object"||t===null)throw f("a push report requires a JSON body { tier, body }");const e=t.tier,i=t.delivery_tier,r=t.body;if(e!=="update"&&e!=="urgent"&&e!=="final")throw f(`invalid report tier: ${String(e)} (expected update|urgent|final)`);if(i!==void 0&&i!=="deferred"&&i!=="normal"&&i!=="urgent")throw f(`invalid delivery_tier: ${String(i)} (expected deferred|normal|urgent)`);if(e!=="update"&&i!==void 0)throw f("delivery_tier is only valid for update reports");if(typeof r!="string"||r.trim()==="")throw f("a push report requires a non-empty body");return{tier:e,...i===void 0?{}:{delivery_tier:i},body:r}}d(ce,"parsePushBody");async function fe(t){const e=t.params.id;g(e);const i=ce(t.body);if(i.tier==="final"&&_(e)!==null)throw new u({error:"structured_result_pending",message:"This node owes a structured result \u2014 a plain `push final` would finish it without recording one.",next:'Submit the result with the `submit_result` tool instead (or `crtr push result`); it validates against the pending schema, records it, and pushes the final report for you. If the schema cannot be honestly satisfied, call `submit_result` with `decline` (or `crtr push result --decline "<reason>" --code <token>`) to record the decline and finish the node.'});const r=i.tier==="final"?a(e)?.status:void 0,n=i.tier==="final"?await O(e):void 0,o=await b(e,i);i.tier==="final"&&A(e);const s=i.tier==="final"&&r!==void 0?{from:r,to:a(e)?.status??"done"}:void 0,m=ie(o,s,n),l=q(e).find(c=>c.id===o.reportId);if(l!==void 0){x.report(e,l);const c=a(e)?.run_id;c&&E(c,e,"node.report.pushed",{body:l.body,kind:l.tier==="final"?"final":"update"})}return{status:200,body:m}}d(fe,"handlePush");async function O(t){if(!G(a(t)))return;const e=await U(t);if(e!==null)return e.worktree_path;if(!await X(a(t).managed_worktree))throw new u({error:"open_managed_worktree",message:"This node still owns an open managed worktree that is neither clean and locally landed nor clean with its exact tip on origin \u2014 `push final` cannot finish.",next:(()=>{const i=a(t)?.managed_worktree;return i!=null&&i.state==="open"&&!M(i.path)?K(i):"Make the recorded worktree clean, including untracked files: commit work to retain and remove or ignore only disposable generated files. With its recorded branch checked out and no rebase in progress, push its current tip to a branch on origin, then rerun `crtr push final`; or run `crtr node worktree close` to land the clean worktree into its recorded local base."})()})}d(O,"guardFinalWorktree");const I=2e3;function me(t,e){const i=JSON.stringify(e,null,2),r=i.length>I?`${i.slice(0,I)}
2
- \u2026 (truncated \u2014 the full result is at the result path above)`:i;return`Structured output submitted.
1
+ var B=Object.defineProperty;var s=(t,e)=>B(t,"name",{value:e,configurable:!0});import{existsSync as M,rmSync as j}from"node:fs";import{getNode as d}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as J}from"../../../core/canvas/executions.js";import{markStopSignal as z}from"../../../core/runtime/stop-signals.js";import{emitEvent as L}from"../../../core/events/emit.js";import{push as W,FinalizationError as S,StructuredRequestFinalizationError as H}from"../../../core/feed/feed.js";import{branchIsPushedAtCurrentTip as X,hasOpenManagedWorktree as G,missingWorktreeRecoveryHint as K}from"../../../core/worktree.js";import{autoDropCleanManagedWorktreeAsync as U}from"../../../core/worktree-mutation-async.js";import{withCanvasWrite as V,openDb as Y}from"../../../core/canvas/db.js";import{get as Q}from"../../../core/graph/bodies.js";import{heads as Z}from"../../../core/graph/documents.js";import{listObjects as ee,nodeObject as te}from"../../../core/graph/objects.js";import{readerFor as re}from"../../../core/graph/reader.js";import{notFound as ne,usage as f}from"../../../core/errors.js";import{InputError as u}from"../../../core/io.js";import{toReportResultDTO as ie}from"../map.js";import{clearSchemaReprompts as oe,outputDeclinedPath as ae,stageStructuredResult as se,structuredRequestResultPath as de,validateStructuredResult as ue}from"../../../core/runtime/structured-output.js";import{getPendingStructuredRequestForNode as _,getStructuredRequest as R,settleStructuredRequestIn as le}from"../../../core/canvas/structured-requests.js";import{ApiError as h}from"../../../api/errors.js";import{applySettlementEffects as $}from"../../structured-requests/effects.js";import{nodeEventStreams as x}from"./node-events.js";import{emitRunEvent as E}from"../../../core/runs/events.js";import{mapAsync as ce}from"../../../core/async-array.js";async function g(t){const e=await d(t);if(e===null)throw ne(`unknown node: ${t}`,{received:t});return e}s(g,"requireNode");function fe(t){if(typeof t!="object"||t===null)throw f("a push report requires a JSON body { tier, body }");const e=t.tier,n=t.delivery_tier,r=t.body;if(e!=="update"&&e!=="urgent"&&e!=="final")throw f(`invalid report tier: ${String(e)} (expected update|urgent|final)`);if(n!==void 0&&n!=="deferred"&&n!=="normal"&&n!=="urgent")throw f(`invalid delivery_tier: ${String(n)} (expected deferred|normal|urgent)`);if(e!=="update"&&n!==void 0)throw f("delivery_tier is only valid for update reports");if(typeof r!="string"||r.trim()==="")throw f("a push report requires a non-empty body");return{tier:e,...n===void 0?{}:{delivery_tier:n},body:r}}s(fe,"parsePushBody");async function me(t){const e=t.params.id;await g(e);const n=fe(t.body);if(n.tier==="final"&&await _(e)!==null)throw new u({error:"structured_result_pending",message:"This node owes a structured result \u2014 a plain `push final` would finish it without recording one.",next:'Submit the result with the `submit_result` tool instead (or `crtr push result`); it validates against the pending schema, records it, and pushes the final report for you. If the schema cannot be honestly satisfied, call `submit_result` with `decline` (or `crtr push result --decline "<reason>" --code <token>`) to record the decline and finish the node.'});const r=n.tier==="final"?(await d(e))?.status:void 0,i=n.tier==="final"?await O(e):void 0,o=await b(e,n);n.tier==="final"&&await A(e);const a=n.tier==="final"&&r!==void 0?{from:r,to:(await d(e))?.status??"done"}:void 0,m=ie(o,a,i),l=(await q(e)).find(c=>c.id===o.reportId);if(l!==void 0){x.report(e,l);const c=(await d(e))?.run_id;c&&await E(c,e,"node.report.pushed",{body:l.body,kind:l.tier==="final"?"final":"update"})}return{status:200,body:m}}s(me,"handlePush");async function O(t){if(!G(await d(t)))return;const e=await U(t);if(e!==null)return e.worktree_path;if(!await X((await d(t)).managed_worktree))throw new u({error:"open_managed_worktree",message:"This node still owns an open managed worktree that is neither clean and locally landed nor clean with its exact tip on origin \u2014 `push final` cannot finish.",next:await(async()=>{const n=(await d(t))?.managed_worktree;return n!=null&&n.state==="open"&&!M(n.path)?K(n):"Make the recorded worktree clean, including untracked files: commit work to retain and remove or ignore only disposable generated files. With its recorded branch checked out and no rebase in progress, push its current tip to a branch on origin, then rerun `crtr push final`; or run `crtr node worktree close` to land the clean worktree into its recorded local base."})()})}s(O,"guardFinalWorktree");const I=2e3;function pe(t,e){const n=JSON.stringify(e,null,2),r=n.length>I?`${n.slice(0,I)}
2
+ \u2026 (truncated \u2014 the full result is at the result path above)`:n;return`Structured output submitted.
3
3
 
4
4
  Result path: ${t}
5
5
 
6
6
  \`\`\`json
7
7
  ${r}
8
8
  \`\`\`
9
- `}d(me,"submitReportBody");function he(t,e){return`Structured result declined.
9
+ `}s(pe,"submitReportBody");function he(t,e){return`Structured result declined.
10
10
 
11
11
  Reason: ${e.reason}
12
12
  Code: ${e.code}
13
13
  Retryable: ${e.retryable?"yes":"no"}
14
14
 
15
15
  Declined marker: ${t}
16
- `}d(he,"declineReportBody");const N=1024,T=64;function pe(t,e){if(typeof t!="object"||t===null)throw f("a result submission requires a JSON body { value } or { decline, code, retryable }");const i=t.request_id;if(typeof i!="string"||i.trim()===""){const o=_(e);throw new u({error:"request_id_required",message:`a structured result requires request_id${o===null?"":` (pending request: ${o.request_id})`}`,next:"Pass `--request <request-id>` exactly as named in the structured-output instruction."})}const r=Object.hasOwn(t,"value"),n=Object.hasOwn(t,"decline");if(r&&n)throw f("a result submission carries either { value } or { decline, code, retryable }, not both");if(n){const{decline:o,code:s,retryable:m}=t;if(typeof o!="string"||o.trim()==="")throw new u({error:"missing_decline_reason",message:"A decline needs a reason.",next:'Rerun with `--decline "<one sentence on why the schema cannot be honestly satisfied>" --code <token>`.'});if(o.length>N)throw new u({error:"decline_reason_too_long",message:`A decline reason is at most ${N} characters (got ${o.length}).`,next:"Keep the reason to one plain sentence; put any detail in an artifact and name its path."});if(typeof s!="string"||s.trim()===""||/\s/.test(s.trim())||s.trim().length>T)throw new u({error:"invalid_decline_code",message:`A decline needs a code: one whitespace-free token of at most ${T} characters naming the decline class.`,next:"Rerun with `--code <token>` \u2014 the token your requester documented for this case."});if(typeof m!="boolean")throw f("a decline carries `retryable` as a boolean");return{requestId:i.trim(),declined:{reason:o.trim(),code:s.trim(),retryable:m}}}if(!r)throw f("a result submission requires a JSON body { value } or { decline, code, retryable }");return{requestId:i.trim(),value:t.value}}d(pe,"parseSubmitBody");const we=1024*1024;async function ye(t){const e=t.params.id,i=g(e);_(e)!==null&&oe(e);const r=pe(t.body,e),n=R(r.requestId);if(n===null||n.node_id!==e)throw new p(404,"structured_request_not_found","the named structured request does not belong to this node");if(n.state!=="pending")throw new p(409,n.state==="expired"?"structured_request_expired":"structured_request_settled",`structured request ${n.request_id} is already ${n.state}`);let o;if("value"in r){if(Buffer.byteLength(JSON.stringify(r.value)??"")>we)throw new u({error:"result_too_large",message:"the submitted result is over 1 MiB serialized; nothing was recorded.",next:"Submit a smaller result \u2014 write bulky content to a file and put its path in the result."});try{o=await ue(n.schema,r.value)}catch(c){throw new u({error:"result_schema_mismatch",message:`the submitted result does not match the requested schema: ${c.message}`,next:'Fix the listed fields and submit again; if the schema cannot be honestly satisfied, decline it (`submit_result` with `decline`, or `crtr push result --decline "<reason>" --code <token>`).'})}}const s="declined"in r?se(e,i.grantee):ae(e,n.request_id,n.submission,i.grantee),m="declined"in r?he(s,r.declined):me(s,o),l="value"in r?de(e,n.request_id,n.submission,o,i.grantee):void 0;try{if(n.submission==="oneoff"){const h=Y(D=>le(D,n.request_id,"declined"in r?{intended:"declined",declined:r.declined}:{intended:"completed",result:o}));if(!h.changed||h.row===null||h.row.state!=="completed"&&h.row.state!=="declined")throw new p(409,h.row?.state==="expired"?"structured_request_expired":"structured_request_settled",`structured request ${n.request_id} is already ${h.row?.state??"settled"}`);await $(h.row,l);const y=await b(e,{tier:"update",body:m},void 0,{requestMessageId:n.request_message_id});return P(e,y.reportId),{status:200,body:{mode:n.submission,result_path:s,report:y.report,notified:[...y.deliveredTo],..."declined"in r?{declined:r.declined}:{}}}}const c=a(e)?.status,v=await O(e),F="declined"in r?{kind:"failure",reason:"declined",detailJson:JSON.stringify({schema:"crtr.node-outcome-detail/v1",message:r.declined.reason,declined:r.declined}),structured:{requestId:n.request_id,declined:r.declined,skipEffects:!0}}:{structured:{requestId:n.request_id,value:o,skipEffects:!0}},w=await b(e,{tier:"final",body:m},F);A(e);const C=R(n.request_id);await $(C,l),P(e,w.reportId);const k=c===void 0?void 0:{from:c,to:a(e)?.status??"done"};return{status:200,body:{mode:n.submission,result_path:s,report:w.report,notified:[...w.deliveredTo],..."declined"in r?{declined:r.declined}:{},...k===void 0?{}:{transitioned:k},...v===void 0?{}:{worktree_auto_dropped:!0,worktree_auto_dropped_path:v}}}}finally{l!==void 0&&j(l.tmpPath,{force:!0})}}d(ye,"handleSubmitResult");function P(t,e){const i=q(t).find(n=>n.id===e);if(i===void 0)return;x.report(t,i);const r=a(t)?.run_id;r&&E(r,t,"node.report.pushed",{body:i.body,kind:i.tier==="final"?"final":"update"})}d(P,"emitReportEvents");function A(t){try{const e=J(t);e!==null&&z(t,"pushedFinal",e.executionId)}catch(e){try{L({event:"daemon.node.final-marker.failed",level:"error",node_id:t,error:e})||process.stderr.write(`final marker failed for ${t}: ${String(e)}
16
+ `}s(he,"declineReportBody");const N=1024,T=64;async function we(t,e){if(typeof t!="object"||t===null)throw f("a result submission requires a JSON body { value } or { decline, code, retryable }");const n=t.request_id;if(typeof n!="string"||n.trim()===""){const o=await _(e);throw new u({error:"request_id_required",message:`a structured result requires request_id${o===null?"":` (pending request: ${o.request_id})`}`,next:"Pass `--request <request-id>` exactly as named in the structured-output instruction."})}const r=Object.hasOwn(t,"value"),i=Object.hasOwn(t,"decline");if(r&&i)throw f("a result submission carries either { value } or { decline, code, retryable }, not both");if(i){const{decline:o,code:a,retryable:m}=t;if(typeof o!="string"||o.trim()==="")throw new u({error:"missing_decline_reason",message:"A decline needs a reason.",next:'Rerun with `--decline "<one sentence on why the schema cannot be honestly satisfied>" --code <token>`.'});if(o.length>N)throw new u({error:"decline_reason_too_long",message:`A decline reason is at most ${N} characters (got ${o.length}).`,next:"Keep the reason to one plain sentence; put any detail in an artifact and name its path."});if(typeof a!="string"||a.trim()===""||/\s/.test(a.trim())||a.trim().length>T)throw new u({error:"invalid_decline_code",message:`A decline needs a code: one whitespace-free token of at most ${T} characters naming the decline class.`,next:"Rerun with `--code <token>` \u2014 the token your requester documented for this case."});if(typeof m!="boolean")throw f("a decline carries `retryable` as a boolean");return{requestId:n.trim(),declined:{reason:o.trim(),code:a.trim(),retryable:m}}}if(!r)throw f("a result submission requires a JSON body { value } or { decline, code, retryable }");return{requestId:n.trim(),value:t.value}}s(we,"parseSubmitBody");const ye=1024*1024;async function _e(t){const e=t.params.id,n=await g(e);await _(e)!==null&&oe(e);const r=await we(t.body,e),i=await R(r.requestId);if(i===null||i.node_id!==e)throw new h(404,"structured_request_not_found","the named structured request does not belong to this node");if(i.state!=="pending")throw new h(409,i.state==="expired"?"structured_request_expired":"structured_request_settled",`structured request ${i.request_id} is already ${i.state}`);let o;if("value"in r){if(Buffer.byteLength(JSON.stringify(r.value)??"")>ye)throw new u({error:"result_too_large",message:"the submitted result is over 1 MiB serialized; nothing was recorded.",next:"Submit a smaller result \u2014 write bulky content to a file and put its path in the result."});try{o=await ue(i.schema,r.value)}catch(c){throw new u({error:"result_schema_mismatch",message:`the submitted result does not match the requested schema: ${c.message}`,next:'Fix the listed fields and submit again; if the schema cannot be honestly satisfied, decline it (`submit_result` with `decline`, or `crtr push result --decline "<reason>" --code <token>`).'})}}const a="declined"in r?ae(e,n.grantee):de(e,i.request_id,i.submission,n.grantee),m="declined"in r?he(a,r.declined):pe(a,o),l="value"in r?se(e,i.request_id,i.submission,o,n.grantee):void 0;try{if(i.submission==="oneoff"){const p=await V(async D=>await le(D,i.request_id,"declined"in r?{intended:"declined",declined:r.declined}:{intended:"completed",result:o}));if(!p.changed||p.row===null||p.row.state!=="completed"&&p.row.state!=="declined")throw new h(409,p.row?.state==="expired"?"structured_request_expired":"structured_request_settled",`structured request ${i.request_id} is already ${p.row?.state??"settled"}`);await $(p.row,l);const y=await b(e,{tier:"update",body:m},void 0,{requestMessageId:i.request_message_id});return await P(e,y.reportId),{status:200,body:{mode:i.submission,result_path:a,report:y.report,notified:[...y.deliveredTo],..."declined"in r?{declined:r.declined}:{}}}}const c=(await d(e))?.status,v=await O(e),F="declined"in r?{kind:"failure",reason:"declined",detailJson:JSON.stringify({schema:"crtr.node-outcome-detail/v1",message:r.declined.reason,declined:r.declined}),structured:{requestId:i.request_id,declined:r.declined,skipEffects:!0}}:{structured:{requestId:i.request_id,value:o,skipEffects:!0}},w=await b(e,{tier:"final",body:m},F);await A(e);const C=await R(i.request_id);await $(C,l),await P(e,w.reportId);const k=c===void 0?void 0:{from:c,to:(await d(e))?.status??"done"};return{status:200,body:{mode:i.submission,result_path:a,report:w.report,notified:[...w.deliveredTo],..."declined"in r?{declined:r.declined}:{},...k===void 0?{}:{transitioned:k},...v===void 0?{}:{worktree_auto_dropped:!0,worktree_auto_dropped_path:v}}}}finally{l!==void 0&&j(l.tmpPath,{force:!0})}}s(_e,"handleSubmitResult");async function P(t,e){const n=(await q(t)).find(i=>i.id===e);if(n===void 0)return;x.report(t,n);const r=(await d(t))?.run_id;r&&await E(r,t,"node.report.pushed",{body:n.body,kind:n.tier==="final"?"final":"update"})}s(P,"emitReportEvents");async function A(t){try{const e=await J(t);e!==null&&z(t,"pushedFinal",e.executionId)}catch(e){try{L({event:"daemon.node.final-marker.failed",level:"error",node_id:t,error:e})||process.stderr.write(`final marker failed for ${t}: ${String(e)}
17
17
  `)}catch{process.stderr.write(`final marker failed for ${t}: ${String(e)}
18
- `)}}}d(A,"markCommittedFinal");async function b(t,e,i,r){try{return await W(t,{kind:e.tier,body:e.body,...e.delivery_tier===void 0?{}:{deliveryTier:e.delivery_tier},...i===void 0?{}:{outcome:i},...r===void 0?{}:{result:r}})}catch(n){throw n instanceof H?new p(409,n.message,n.message==="structured_request_expired"?"the named structured request expired before this submission committed":"the named structured request is already settled"):n instanceof S&&n.code==="already_finalized"?new u({error:"already_finalized",message:"This node already submitted its canonical final result.",next:"Push an update with the new information, then stop."}):n instanceof S&&n.code==="finalization_forbidden"?new u({error:"finalization_forbidden",message:"A canceled or dead node cannot submit a canonical final result.",next:"Do not push final from this node."}):n}}d(b,"pushOrRethrow");function q(t){const e=V();return ee(e,re(e,{class:"person"},()=>[]),{type:"document",kind:"report",owner:te(e,t)}).map(r=>{const n=r.name.match(/-(update|urgent|final)$/)?.[1]??"update",o=Z(e,r)[0];return{name:r.name,id:r.id,tier:n,body:o===void 0?"":Q(o.body_hash).trim(),created:r.created_at}}).sort((r,n)=>r.created<n.created?1:r.created>n.created?-1:n.name.localeCompare(r.name))}d(q,"reportsForNode");function _e(t){const e=t.params.id;g(e);const i=t.query.get("tier"),r=t.query.get("limit"),n=r!==null?Number(r):void 0;let o=q(e);return i!==null&&(o=o.filter(s=>s.tier===i)),n!==void 0&&Number.isFinite(n)&&n>=0&&(o=o.slice(0,n)),{status:200,body:o}}d(_e,"handleList");const ze=[{method:"POST",pattern:"/v1/nodes/:id/reports",ownerOnly:!0,handler:fe},{method:"GET",pattern:"/v1/nodes/:id/reports",handler:_e},{method:"POST",pattern:"/v1/nodes/:id/result",handler:ye}];export{ze as reportRoutes,q as reportsForNode};
18
+ `)}}}s(A,"markCommittedFinal");async function b(t,e,n,r){try{return await W(t,{kind:e.tier,body:e.body,...e.delivery_tier===void 0?{}:{deliveryTier:e.delivery_tier},...n===void 0?{}:{outcome:n},...r===void 0?{}:{result:r}})}catch(i){throw i instanceof H?new h(409,i.message,i.message==="structured_request_expired"?"the named structured request expired before this submission committed":"the named structured request is already settled"):i instanceof S&&i.code==="already_finalized"?new u({error:"already_finalized",message:"This node already submitted its canonical final result.",next:"Push an update with the new information, then stop."}):i instanceof S&&i.code==="finalization_forbidden"?new u({error:"finalization_forbidden",message:"A canceled or dead node cannot submit a canonical final result.",next:"Do not push final from this node."}):i}}s(b,"pushOrRethrow");async function q(t){const e=await Y(),n=await ee(e,await re(e,{class:"person"},async()=>[]),{type:"document",kind:"report",owner:await te(e,t)});return(await ce(n,async r=>{const i=r.name.match(/-(update|urgent|final)$/)?.[1]??"update",o=(await Z(e,r))[0];return{name:r.name,id:r.id,tier:i,body:o===void 0?"":Q(o.body_hash).trim(),created:r.created_at}})).sort((r,i)=>r.created<i.created?1:r.created>i.created?-1:i.name.localeCompare(r.name))}s(q,"reportsForNode");async function ge(t){const e=t.params.id;await g(e);const n=t.query.get("tier"),r=t.query.get("limit"),i=r!==null?Number(r):void 0;let o=await q(e);return n!==null&&(o=o.filter(a=>a.tier===n)),i!==void 0&&Number.isFinite(i)&&i>=0&&(o=o.slice(0,i)),{status:200,body:o}}s(ge,"handleList");const We=[{method:"POST",pattern:"/v1/nodes/:id/reports",ownerOnly:!0,handler:me},{method:"GET",pattern:"/v1/nodes/:id/reports",handler:ge},{method:"POST",pattern:"/v1/nodes/:id/result",handler:_e}];export{We as reportRoutes,q as reportsForNode};
@@ -1 +1 @@
1
- var z=Object.defineProperty;var d=(n,t)=>z(n,"name",{value:t,configurable:!0});import{randomUUID as q}from"node:crypto";import{getNode as T}from"../../../core/canvas/canvas.js";import{isSafeNodeId as S}from"../../../core/canvas/paths.js";import{createComment as J,deleteComment as X,editComment as Y,getComment as A,listCommentEvents as Z,listComments as $,listReviewEvents as ee,reopenComment as ne,resolveComment as te}from"../../../core/review/comments.js";import{withCanvasWrite as k}from"../../../core/canvas/db.js";import{captureAnchorText as ie,requireCurrentDocumentLocked as oe}from"../../../core/review/document.js";import{forkReviewComment as re}from"../../../core/review/fork.js";import{applyRangeBatch as de}from"../../../core/review/remap.js";import{getReviewByCompanion as se,requireVisibleReview as f}from"../../../core/review/store.js";import{ReviewOperationError as v}from"../../../core/review/types.js";import{notifyComment as ce}from"../../review/comment-notify.js";import{toReviewCommentDTO as p,toReviewCommentEventDTO as x}from"../map.js";import{invalidRequest as ue,isRecord as I,objectBody as R,requireParam as D,requiredString as P}from"./validate.js";const j=/^[a-f0-9]{32}$/,L=/^[a-f0-9]{64}$/,ae=new Set(["open","resolved","deleted","all"]),me=new Set(["wake","quiet"]);function m(n){ue("review comment request",n)}d(m,"invalidRequest");function le(n,t,e){const i=n[t];if(i!==void 0){if(typeof i!="string"||!L.test(i)){e.push({field:t,problem:"must be a lowercase SHA-256 hex digest",received:i});return}return i}}d(le,"optionalSha256");function M(n,t,e){const i=n[t];if(typeof i!="string"||!L.test(i)){e.push({field:t,problem:"must be a lowercase SHA-256 hex digest",...i===void 0?{}:{received:i}});return}return i}d(M,"requiredSha256");function B(n,t){const e=n.deliver;if(e!==void 0){if(typeof e!="string"||!me.has(e)){t.push({field:"deliver",problem:"must be wake or quiet",received:e});return}return e}}d(B,"optionalDeliver");function fe(n,t){const e=n.if_revision;if(e!==void 0){if(!Number.isSafeInteger(e)||e<0){t.push({field:"if_revision",problem:"must be a non-negative safe integer",received:e});return}return e}}d(fe,"optionalRevision");function F(n,t){const e=n.actor_node_id;return e==null?{kind:"human",node_id:null}:typeof e!="string"||!S(e)?(t.push({field:"actor_node_id",problem:"must be a safe node id or null",received:e}),null):{kind:"node",node_id:e}}d(F,"actorFrom");function G(n,t,e){T(n)===null&&e.push({field:t,problem:"must name an existing node",received:n})}d(G,"requireKnownNode");function N(n,t){n.node_id!==null&&G(n.node_id,"actor_node_id",t)}d(N,"requireKnownActor");function H(n,t,e){if(!I(n)){e.push({field:t,problem:"must be an anchor object",received:n});return}const i=["line","end_line","col_start","col_end","quote"];for(const r of Object.keys(n))i.includes(r)||e.push({field:`${t}.${r}`,problem:"is not allowed",received:n[r]});const o=n.line,s=n.end_line;typeof o!="number"&&e.push({field:`${t}.line`,problem:"must be a number",...o===void 0?{}:{received:o}}),typeof s!="number"&&e.push({field:`${t}.end_line`,problem:"must be a number",...s===void 0?{}:{received:s}});for(const r of["col_start","col_end"]){const c=n[r];c!==void 0&&typeof c!="number"&&e.push({field:`${t}.${r}`,problem:"must be a number",received:c})}if(n.quote!==void 0&&typeof n.quote!="string"&&e.push({field:`${t}.quote`,problem:"must be a string",received:n.quote}),!(typeof o!="number"||typeof s!="number"))return{line:o,end_line:s,...typeof n.col_start=="number"?{col_start:n.col_start}:{},...typeof n.col_end=="number"?{col_end:n.col_end}:{},...typeof n.quote=="string"?{quote:n.quote}:{}}}d(H,"anchorFrom");function w(n,t){return D(n,"review_id","must be a safe review id",S,t)}d(w,"requireReviewId");function C(n,t){return D(n,"comment_id","must be a 32-character lowercase hexadecimal id",e=>j.test(e),t)}d(C,"requireCommentId");function b(n){const t=f(n);if(t.state!=="open")throw new v("review_terminal","review already has a terminal outcome",{state:t.state,requested:"comment",review:t});return t}d(b,"requireOpenReview");function U(n){const t=n===null?void 0:T(n)?.review_binding?.review_id,e=n===null?null:se(n)??(t===void 0?null:f(t));if(e===null||e.state!=="open")throw new v("review_required","an open review is required when no review id is supplied",{actor_node_id:n});return e}d(U,"requireCompanionReview");function he(n){return{comment:p(n),events:Z(n.comment_id).map(x)}}d(he,"toDetail");function _e(n,t){return{attempted:!0,target_node_id:n.companion_node_id,status:"failed",woke:!1,error:t instanceof Error?t.message:String(t)}}d(_e,"deliveryFailure");async function V(n){if(!n.changed)return{comment:p(n.comment),changed:!1};let t;try{t=await ce({review:n.review,comment:n.comment,verb:n.verb,actor_node_id:n.actor.node_id,deliver:n.deliver,operation_id:n.operationId})}catch(e){t=_e(n.review,e)}return{comment:p(n.comment),changed:!0,delivery:t}}d(V,"mutationResult");function ve(n,t){const e=[],i=R(n.body,["text","anchor","doc_hash","actor_node_id","deliver"],e),o=t==="review"?(()=>{const a=w(n,e);return a===void 0?void 0:{kind:"review",review_id:a}})():{kind:"self"},s=P(i,"text",e),r=H(i.anchor,"anchor",e),c=le(i,"doc_hash",e),u=F(i,e),h=B(i,e);return u!==null&&N(u,e),(e.length>0||o===void 0||s===void 0||r===void 0||u===null)&&m(e),{selector:o,text:s,anchor:r,...c===void 0?{}:{doc_hash:c},actor:u,...h===void 0?{}:{deliver:h}}}d(ve,"parseCreate");function pe(n,t){const e=[],i=R(n.body,t?["text","actor_node_id","deliver","if_revision"]:["actor_node_id","deliver","if_revision"],e),o=C(n,e),s=t?P(i,"text",e):void 0,r=F(i,e),c=B(i,e),u=fe(i,e);return r!==null&&N(r,e),(e.length>0||o===void 0||r===null||t&&s===void 0)&&m(e),{comment_id:o,...s===void 0?{}:{text:s},actor:r,...c===void 0?{}:{deliver:c},...u===void 0?{}:{if_revision:u}}}d(pe,"parseAction");function we(n){const t=[],e=R(n.body,["from_doc_hash","to_doc_hash","entries"],t),i=w(n,t),o=M(e,"from_doc_hash",t),s=M(e,"to_doc_hash",t),r=e.entries,c=[];return Array.isArray(r)?r.forEach((u,h)=>{const a=`entries[${h}]`;if(!I(u)){t.push({field:a,problem:"must be an object",received:u});return}for(const g of Object.keys(u))["comment_id","anchor","detached"].includes(g)||t.push({field:`${a}.${g}`,problem:"is not allowed",received:u[g]});const l=u.comment_id;if(typeof l!="string"||!j.test(l)){t.push({field:`${a}.comment_id`,problem:"must be a 32-character lowercase hexadecimal id",received:l});return}const W=u.anchor!==void 0,_=u.detached;_!==void 0&&_!==!0&&t.push({field:`${a}.detached`,problem:"must be true when present",received:_});const E=_===!0;if(W===E){t.push({field:a,problem:"must provide exactly one of anchor or detached: true"});return}if(E){c.push({comment_id:l,detached:!0});return}const O=H(u.anchor,`${a}.anchor`,t);O!==void 0&&c.push({comment_id:l,anchor:O})}):t.push({field:"entries",problem:"must be an array",received:r}),(t.length>0||i===void 0||o===void 0||s===void 0||!Array.isArray(r))&&m(t),{review_id:i,request:{from_doc_hash:o,to_doc_hash:s,entries:c}}}d(we,"parseRangeBatch");function be(n,t,e){for(const[r,c]of n.query)r!=="status"&&(r!=="actor_node_id"||t!=="self")&&e.push({field:r,problem:"is not allowed",received:c});const i=n.query.getAll("status");(i.length>1||i.length===1&&!ae.has(i[0]))&&e.push({field:"status",problem:"must be open, resolved, deleted, or all",received:i.length>1?i:i[0]});const o=n.query.getAll("actor_node_id");let s=null;if(o.length>1)e.push({field:"actor_node_id",problem:"must appear at most once",received:o});else if(o.length===1){const r=o[0];S(r)?(s=r,G(r,"actor_node_id",e)):e.push({field:"actor_node_id",problem:"must be a safe node id",received:r})}return{...i.length===0?{}:{status:i[0]},actor_node_id:s}}d(be,"parseListQuery");function ye(n,t){const e={};for(const[i,o]of n.query)i!=="since_seq"&&i!=="limit"&&t.push({field:i,problem:"is not allowed",received:o});for(const i of["since_seq","limit"]){const o=n.query.getAll(i);if(o.length>1){t.push({field:i,problem:"must appear at most once",received:o});continue}if(o.length===0)continue;const s=o[0],r=Number(s);if(!Number.isSafeInteger(r)||r<0||String(r)!==s){t.push({field:i,problem:"must be a non-negative safe integer",received:s});continue}e[i]=r}return e.limit!==void 0&&e.limit<1&&t.push({field:"limit",problem:"must be at least 1",received:e.limit}),e}d(ye,"parseEventQuery");async function Q(n,t){const e=ve(n,t),i=q(),o=k(s=>{const r=e.selector.kind==="review"?b(e.selector.review_id):b(U(e.actor.node_id).review_id),c=oe(s,r.review_id,e.doc_hash??r.anchor_base_sha256),u=J({review_id:r.review_id,text:e.text,anchor:e.anchor,line_text:ie(c.lines,e.anchor),doc_hash:c.sha256,actor:e.actor,operation_id:i});return{review:r,mutation:u}});return{status:200,body:await V({review:o.review,...o.mutation,verb:"create",actor:e.actor,deliver:e.deliver,operationId:i})}}d(Q,"handleCreate");function K(n,t){const e=[],i=t==="review"?(()=>{const c=w(n,e);return c===void 0?void 0:{kind:"review",review_id:c}})():{kind:"self"},o=be(n,t,e);(e.length>0||i===void 0)&&m(e);const s=i.kind==="review"?f(i.review_id):U(o.actor_node_id);return{status:200,body:{review_id:s.review_id,comments:$(s.review_id,o).map(p)}}}d(K,"handleList");function ge(n){const t=[],e=w(n,t),i=ye(n,t);(t.length>0||e===void 0)&&m(t);const o=f(e),s=ee(o.review_id,i);return{status:200,body:{review_id:o.review_id,events:s.events.map(x),next_since_seq:s.events.length===0?null:s.next_since_seq}}}d(ge,"handleEvents");function qe(n){const{review_id:t,request:e}=we(n),i=q(),o=k(()=>{const r=b(t),c=$(r.review_id).length,u=de({review_id:r.review_id,...e,actor:{kind:"human",node_id:null},operation_id:i});return{review:r,nondeleted:c,applied:u}});return{status:200,body:{review_id:o.review.review_id,anchor_base_sha256:o.applied.anchor_base_sha256,updated:o.applied.updated,detached:o.applied.detached,unchanged:o.nondeleted-o.applied.updated}}}d(qe,"handleRanges");function Se(n){const t=[],e=C(n,t);(t.length>0||e===void 0)&&m(t);const i=A(e);if(i===null)throw new v("unknown_comment","comment was not found",{received:e});return f(i.review_id),{status:200,body:he(i)}}d(Se,"handleDetail");async function y(n,t){const e=pe(n,t==="edit"),i=q(),o=k(()=>{const s=A(e.comment_id);if(s===null)throw new v("unknown_comment","comment was not found",{received:e.comment_id});const r=b(s.review_id),c=t==="edit"?Y(e.comment_id,{text:e.text,actor:e.actor,operation_id:i,if_revision:e.if_revision}):t==="resolve"?te(e.comment_id,{actor:e.actor,operation_id:i,if_revision:e.if_revision}):t==="reopen"?ne(e.comment_id,{actor:e.actor,operation_id:i,if_revision:e.if_revision}):X(e.comment_id,{actor:e.actor,operation_id:i,if_revision:e.if_revision});return{review:r,mutation:c}});return{status:200,body:await V({review:o.review,...o.mutation,verb:t,actor:e.actor,deliver:e.deliver,operationId:i})}}d(y,"handleAction");async function ke(n){const t=[],e=C(n,t);(t.length>0||e===void 0)&&m(t);const i=await re(e);return{status:200,body:{comment_id:e,node_id:i.node_id,cwd:i.cwd}}}d(ke,"handleFork");const Be=[{method:"POST",pattern:"/v1/human/reviews/self/comments",handler:d(n=>Q(n,"self"),"handler")},{method:"GET",pattern:"/v1/human/reviews/self/comments",handler:d(n=>K(n,"self"),"handler")},{method:"POST",pattern:"/v1/human/reviews/:review_id/comments",handler:d(n=>Q(n,"review"),"handler")},{method:"GET",pattern:"/v1/human/reviews/:review_id/comments",handler:d(n=>K(n,"review"),"handler")},{method:"GET",pattern:"/v1/human/reviews/:review_id/comment-events",handler:ge},{method:"POST",pattern:"/v1/human/reviews/:review_id/comment-ranges",handler:qe},{method:"GET",pattern:"/v1/human/comments/:comment_id",handler:Se},{method:"POST",pattern:"/v1/human/comments/:comment_id/edit",handler:d(n=>y(n,"edit"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/resolve",handler:d(n=>y(n,"resolve"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/reopen",handler:d(n=>y(n,"reopen"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/delete",handler:d(n=>y(n,"delete"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/fork",handler:ke}];export{Be as reviewCommentRoutes};
1
+ var z=Object.defineProperty;var d=(n,t)=>z(n,"name",{value:t,configurable:!0});import{randomUUID as q}from"node:crypto";import{getNode as T}from"../../../core/canvas/canvas.js";import{isSafeNodeId as S}from"../../../core/canvas/paths.js";import{createComment as J,deleteComment as X,editComment as Y,getComment as A,listCommentEvents as Z,listComments as $,listReviewEvents as ee,reopenComment as ne,resolveComment as te}from"../../../core/review/comments.js";import{withCanvasWrite as k}from"../../../core/canvas/db.js";import{captureAnchorText as ie,requireCurrentDocumentLocked as oe}from"../../../core/review/document.js";import{forkReviewComment as re}from"../../../core/review/fork.js";import{applyRangeBatch as de}from"../../../core/review/remap.js";import{getReviewByCompanion as ae,requireVisibleReview as f}from"../../../core/review/store.js";import{ReviewOperationError as v}from"../../../core/review/types.js";import{notifyComment as se}from"../../review/comment-notify.js";import{toReviewCommentDTO as p,toReviewCommentEventDTO as x}from"../map.js";import{invalidRequest as ce,isRecord as I,objectBody as R,requireParam as D,requiredString as P}from"./validate.js";const j=/^[a-f0-9]{32}$/,L=/^[a-f0-9]{64}$/,ue=new Set(["open","resolved","deleted","all"]),me=new Set(["wake","quiet"]);function m(n){ce("review comment request",n)}d(m,"invalidRequest");function le(n,t,e){const i=n[t];if(i!==void 0){if(typeof i!="string"||!L.test(i)){e.push({field:t,problem:"must be a lowercase SHA-256 hex digest",received:i});return}return i}}d(le,"optionalSha256");function M(n,t,e){const i=n[t];if(typeof i!="string"||!L.test(i)){e.push({field:t,problem:"must be a lowercase SHA-256 hex digest",...i===void 0?{}:{received:i}});return}return i}d(M,"requiredSha256");function B(n,t){const e=n.deliver;if(e!==void 0){if(typeof e!="string"||!me.has(e)){t.push({field:"deliver",problem:"must be wake or quiet",received:e});return}return e}}d(B,"optionalDeliver");function fe(n,t){const e=n.if_revision;if(e!==void 0){if(!Number.isSafeInteger(e)||e<0){t.push({field:"if_revision",problem:"must be a non-negative safe integer",received:e});return}return e}}d(fe,"optionalRevision");function F(n,t){const e=n.actor_node_id;return e==null?{kind:"human",node_id:null}:typeof e!="string"||!S(e)?(t.push({field:"actor_node_id",problem:"must be a safe node id or null",received:e}),null):{kind:"node",node_id:e}}d(F,"actorFrom");async function G(n,t,e){await T(n)===null&&e.push({field:t,problem:"must name an existing node",received:n})}d(G,"requireKnownNode");async function N(n,t){n.node_id!==null&&await G(n.node_id,"actor_node_id",t)}d(N,"requireKnownActor");function H(n,t,e){if(!I(n)){e.push({field:t,problem:"must be an anchor object",received:n});return}const i=["line","end_line","col_start","col_end","quote"];for(const r of Object.keys(n))i.includes(r)||e.push({field:`${t}.${r}`,problem:"is not allowed",received:n[r]});const o=n.line,a=n.end_line;typeof o!="number"&&e.push({field:`${t}.line`,problem:"must be a number",...o===void 0?{}:{received:o}}),typeof a!="number"&&e.push({field:`${t}.end_line`,problem:"must be a number",...a===void 0?{}:{received:a}});for(const r of["col_start","col_end"]){const s=n[r];s!==void 0&&typeof s!="number"&&e.push({field:`${t}.${r}`,problem:"must be a number",received:s})}if(n.quote!==void 0&&typeof n.quote!="string"&&e.push({field:`${t}.quote`,problem:"must be a string",received:n.quote}),!(typeof o!="number"||typeof a!="number"))return{line:o,end_line:a,...typeof n.col_start=="number"?{col_start:n.col_start}:{},...typeof n.col_end=="number"?{col_end:n.col_end}:{},...typeof n.quote=="string"?{quote:n.quote}:{}}}d(H,"anchorFrom");function w(n,t){return D(n,"review_id","must be a safe review id",S,t)}d(w,"requireReviewId");function C(n,t){return D(n,"comment_id","must be a 32-character lowercase hexadecimal id",e=>j.test(e),t)}d(C,"requireCommentId");async function b(n){const t=await f(n);if(t.state!=="open")throw new v("review_terminal","review already has a terminal outcome",{state:t.state,requested:"comment",review:t});return t}d(b,"requireOpenReview");async function U(n){const t=n===null?void 0:(await T(n))?.review_binding?.review_id,e=n===null?null:await ae(n)??(t===void 0?null:await f(t));if(e===null||e.state!=="open")throw new v("review_required","an open review is required when no review id is supplied",{actor_node_id:n});return e}d(U,"requireCompanionReview");async function he(n){return{comment:p(n),events:(await Z(n.comment_id)).map(x)}}d(he,"toDetail");function _e(n,t){return{attempted:!0,target_node_id:n.companion_node_id,status:"failed",woke:!1,error:t instanceof Error?t.message:String(t)}}d(_e,"deliveryFailure");async function V(n){if(!n.changed)return{comment:p(n.comment),changed:!1};let t;try{t=await se({review:n.review,comment:n.comment,verb:n.verb,actor_node_id:n.actor.node_id,deliver:n.deliver,operation_id:n.operationId})}catch(e){t=_e(n.review,e)}return{comment:p(n.comment),changed:!0,delivery:t}}d(V,"mutationResult");async function ve(n,t){const e=[],i=R(n.body,["text","anchor","doc_hash","actor_node_id","deliver"],e),o=t==="review"?(()=>{const u=w(n,e);return u===void 0?void 0:{kind:"review",review_id:u}})():{kind:"self"},a=P(i,"text",e),r=H(i.anchor,"anchor",e),s=le(i,"doc_hash",e),c=F(i,e),h=B(i,e);return c!==null&&await N(c,e),(e.length>0||o===void 0||a===void 0||r===void 0||c===null)&&m(e),{selector:o,text:a,anchor:r,...s===void 0?{}:{doc_hash:s},actor:c,...h===void 0?{}:{deliver:h}}}d(ve,"parseCreate");async function pe(n,t){const e=[],i=R(n.body,t?["text","actor_node_id","deliver","if_revision"]:["actor_node_id","deliver","if_revision"],e),o=C(n,e),a=t?P(i,"text",e):void 0,r=F(i,e),s=B(i,e),c=fe(i,e);return r!==null&&await N(r,e),(e.length>0||o===void 0||r===null||t&&a===void 0)&&m(e),{comment_id:o,...a===void 0?{}:{text:a},actor:r,...s===void 0?{}:{deliver:s},...c===void 0?{}:{if_revision:c}}}d(pe,"parseAction");function we(n){const t=[],e=R(n.body,["from_doc_hash","to_doc_hash","entries"],t),i=w(n,t),o=M(e,"from_doc_hash",t),a=M(e,"to_doc_hash",t),r=e.entries,s=[];return Array.isArray(r)?r.forEach((c,h)=>{const u=`entries[${h}]`;if(!I(c)){t.push({field:u,problem:"must be an object",received:c});return}for(const g of Object.keys(c))["comment_id","anchor","detached"].includes(g)||t.push({field:`${u}.${g}`,problem:"is not allowed",received:c[g]});const l=c.comment_id;if(typeof l!="string"||!j.test(l)){t.push({field:`${u}.comment_id`,problem:"must be a 32-character lowercase hexadecimal id",received:l});return}const W=c.anchor!==void 0,_=c.detached;_!==void 0&&_!==!0&&t.push({field:`${u}.detached`,problem:"must be true when present",received:_});const E=_===!0;if(W===E){t.push({field:u,problem:"must provide exactly one of anchor or detached: true"});return}if(E){s.push({comment_id:l,detached:!0});return}const O=H(c.anchor,`${u}.anchor`,t);O!==void 0&&s.push({comment_id:l,anchor:O})}):t.push({field:"entries",problem:"must be an array",received:r}),(t.length>0||i===void 0||o===void 0||a===void 0||!Array.isArray(r))&&m(t),{review_id:i,request:{from_doc_hash:o,to_doc_hash:a,entries:s}}}d(we,"parseRangeBatch");async function be(n,t,e){for(const[r,s]of n.query)r!=="status"&&(r!=="actor_node_id"||t!=="self")&&e.push({field:r,problem:"is not allowed",received:s});const i=n.query.getAll("status");(i.length>1||i.length===1&&!ue.has(i[0]))&&e.push({field:"status",problem:"must be open, resolved, deleted, or all",received:i.length>1?i:i[0]});const o=n.query.getAll("actor_node_id");let a=null;if(o.length>1)e.push({field:"actor_node_id",problem:"must appear at most once",received:o});else if(o.length===1){const r=o[0];S(r)?(a=r,await G(r,"actor_node_id",e)):e.push({field:"actor_node_id",problem:"must be a safe node id",received:r})}return{...i.length===0?{}:{status:i[0]},actor_node_id:a}}d(be,"parseListQuery");function ye(n,t){const e={};for(const[i,o]of n.query)i!=="since_seq"&&i!=="limit"&&t.push({field:i,problem:"is not allowed",received:o});for(const i of["since_seq","limit"]){const o=n.query.getAll(i);if(o.length>1){t.push({field:i,problem:"must appear at most once",received:o});continue}if(o.length===0)continue;const a=o[0],r=Number(a);if(!Number.isSafeInteger(r)||r<0||String(r)!==a){t.push({field:i,problem:"must be a non-negative safe integer",received:a});continue}e[i]=r}return e.limit!==void 0&&e.limit<1&&t.push({field:"limit",problem:"must be at least 1",received:e.limit}),e}d(ye,"parseEventQuery");async function Q(n,t){const e=await ve(n,t),i=q(),o=await k(async a=>{const r=e.selector.kind==="review"?await b(e.selector.review_id):await b((await U(e.actor.node_id)).review_id),s=await oe(a,r.review_id,e.doc_hash??r.anchor_base_sha256),c=await J({review_id:r.review_id,text:e.text,anchor:e.anchor,line_text:ie(s.lines,e.anchor),doc_hash:s.sha256,actor:e.actor,operation_id:i});return{review:r,mutation:c}});return{status:200,body:await V({review:o.review,...o.mutation,verb:"create",actor:e.actor,deliver:e.deliver,operationId:i})}}d(Q,"handleCreate");async function K(n,t){const e=[],i=t==="review"?(()=>{const s=w(n,e);return s===void 0?void 0:{kind:"review",review_id:s}})():{kind:"self"},o=await be(n,t,e);(e.length>0||i===void 0)&&m(e);const a=i.kind==="review"?await f(i.review_id):await U(o.actor_node_id);return{status:200,body:{review_id:a.review_id,comments:(await $(a.review_id,o)).map(p)}}}d(K,"handleList");async function ge(n){const t=[],e=w(n,t),i=ye(n,t);(t.length>0||e===void 0)&&m(t);const o=await f(e),a=await ee(o.review_id,i);return{status:200,body:{review_id:o.review_id,events:a.events.map(x),next_since_seq:a.events.length===0?null:a.next_since_seq}}}d(ge,"handleEvents");async function qe(n){const{review_id:t,request:e}=we(n),i=q(),o=await k(async()=>{const r=await b(t),s=(await $(r.review_id)).length,c=await de({review_id:r.review_id,...e,actor:{kind:"human",node_id:null},operation_id:i});return{review:r,nondeleted:s,applied:c}});return{status:200,body:{review_id:o.review.review_id,anchor_base_sha256:o.applied.anchor_base_sha256,updated:o.applied.updated,detached:o.applied.detached,unchanged:o.nondeleted-o.applied.updated}}}d(qe,"handleRanges");async function Se(n){const t=[],e=C(n,t);(t.length>0||e===void 0)&&m(t);const i=await A(e);if(i===null)throw new v("unknown_comment","comment was not found",{received:e});return await f(i.review_id),{status:200,body:await he(i)}}d(Se,"handleDetail");async function y(n,t){const e=await pe(n,t==="edit"),i=q(),o=await k(async()=>{const a=await A(e.comment_id);if(a===null)throw new v("unknown_comment","comment was not found",{received:e.comment_id});const r=await b(a.review_id),s=t==="edit"?await Y(e.comment_id,{text:e.text,actor:e.actor,operation_id:i,if_revision:e.if_revision}):t==="resolve"?await te(e.comment_id,{actor:e.actor,operation_id:i,if_revision:e.if_revision}):t==="reopen"?await ne(e.comment_id,{actor:e.actor,operation_id:i,if_revision:e.if_revision}):await X(e.comment_id,{actor:e.actor,operation_id:i,if_revision:e.if_revision});return{review:r,mutation:s}});return{status:200,body:await V({review:o.review,...o.mutation,verb:t,actor:e.actor,deliver:e.deliver,operationId:i})}}d(y,"handleAction");async function ke(n){const t=[],e=C(n,t);(t.length>0||e===void 0)&&m(t);const i=await re(e);return{status:200,body:{comment_id:e,node_id:i.node_id,cwd:i.cwd}}}d(ke,"handleFork");const Be=[{method:"POST",pattern:"/v1/human/reviews/self/comments",handler:d(n=>Q(n,"self"),"handler")},{method:"GET",pattern:"/v1/human/reviews/self/comments",handler:d(async n=>await K(n,"self"),"handler")},{method:"POST",pattern:"/v1/human/reviews/:review_id/comments",handler:d(n=>Q(n,"review"),"handler")},{method:"GET",pattern:"/v1/human/reviews/:review_id/comments",handler:d(async n=>await K(n,"review"),"handler")},{method:"GET",pattern:"/v1/human/reviews/:review_id/comment-events",handler:ge},{method:"POST",pattern:"/v1/human/reviews/:review_id/comment-ranges",handler:qe},{method:"GET",pattern:"/v1/human/comments/:comment_id",handler:Se},{method:"POST",pattern:"/v1/human/comments/:comment_id/edit",handler:d(n=>y(n,"edit"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/resolve",handler:d(n=>y(n,"resolve"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/reopen",handler:d(n=>y(n,"reopen"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/delete",handler:d(n=>y(n,"delete"),"handler")},{method:"POST",pattern:"/v1/human/comments/:comment_id/fork",handler:ke}];export{Be as reviewCommentRoutes};
@@ -1 +1 @@
1
- var k=Object.defineProperty;var s=(t,e)=>k(t,"name",{value:e,configurable:!0});import{ApiError as m}from"../../../api/index.js";import{withCanvasWrite as R}from"../../../core/canvas/db.js";import{isSafeNodeId as p}from"../../../core/canvas/paths.js";import{readDocument as q}from"../../../core/graph/documents.js";import{getByRowid as E}from"../../../core/graph/objects.js";import{checkoutsForCwd as S}from"../../../core/graph/repo-sync/repos.js";import{getNode as b}from"../../../core/canvas/canvas.js";import{assertScope as T}from"../../../core/scopes.js";import{createReview as $}from"../../../core/review/birth.js";import{readAnchorBase as C,listReviews as D,requireVisibleReview as y}from"../../../core/review/store.js";import{cancelReview as I,submitReviewApproval as A}from"../../review/finish.js";import{toFeedbackResultDTO as O,toReviewDTO as F}from"../map.js";import{readerFor as L,resolveRef as B}from"../reader.js";import{canReadNode as N}from"../router.js";import{invalidRequest as P,objectBody as w,optionalString as c,requireParam as j,requiredString as g}from"./validate.js";const G=new Set(["open","approved","canceled"]),V=["origin_kind","origin_node_id","document","file","idempotency_key","subtitle","output_path"],W=["reason","actor","disposition"];function l(t){P("review request",t)}s(l,"invalidRequest");function h(t,e){return j(t,"review_id","must be a safe review id",p,e)}s(h,"requireReviewId");function f(t){return{...F(t,t.state==="approved"?{result_path:`${t.review_dir}/result.json`}:{}),review_dir:t.review_dir}}s(f,"toReviewResponseDTO");function K(t){const e=[],i=w(t.body,V,e),o=i.origin_kind,n=o==="ticket"||o==="inline"?o:void 0;n===void 0&&e.push({field:"origin_kind",problem:"must be ticket or inline",...o===void 0?{}:{received:o}});const r=g(i,"origin_node_id",e);r!==void 0&&!p(r)&&e.push({field:"origin_node_id",problem:"must be a safe node id",received:r});const d=c(i,"document",e),a=c(i,"file",e);n==="ticket"&&(d===void 0||a!==void 0)&&e.push({field:"document",problem:"is required for ticket reviews, and file is not allowed"}),n==="inline"&&a===void 0==(d===void 0)&&e.push({field:"file",problem:"inline reviews take exactly one of file or document"});const u=g(i,"idempotency_key",e);u!==void 0&&u.length>128&&e.push({field:"idempotency_key",problem:"must be at most 128 characters",received:u});const v=c(i,"subtitle",e),_=c(i,"output_path",e);return n==="ticket"&&v===void 0&&i.subtitle===void 0&&e.push({field:"subtitle",problem:"is required for ticket reviews"}),n==="inline"&&i.subtitle!==void 0&&e.push({field:"subtitle",problem:"is only allowed for ticket reviews",received:i.subtitle}),n==="inline"&&i.output_path!==void 0&&e.push({field:"output_path",problem:"is only allowed for ticket reviews",received:i.output_path}),(e.length>0||n===void 0||r===void 0||!p(r)||u===void 0||u.length>128)&&l(e),{origin_kind:n,origin_node_id:r,...d===void 0?{}:{document:d},...a===void 0?{}:{file:a},idempotency_key:u,...v===void 0?{}:{subtitle:v},..._===void 0?{}:{output_path:_}}}s(K,"parseCreate");function M(t){const e=[],i={},o=new Set(["state","origin_node_id","file"]);for(const[n,r]of t.query.entries())o.has(n)||e.push({field:n,problem:"is not allowed",received:r});for(const n of o){const r=t.query.getAll(n);if(r.length>1){e.push({field:n,problem:"must appear at most once",received:r});continue}const d=r[0];d!==void 0&&(n==="state"?G.has(d)?i.state=d:e.push({field:n,problem:"must be open, approved, or canceled",received:d}):n==="origin_node_id"?p(d)?i.origin_node_id=d:e.push({field:n,problem:"must be a safe node id",received:d}):d===""?e.push({field:n,problem:"must be a non-empty string",received:d}):i.file=d)}return e.length>0&&l(e),i}s(M,"parseList");function x(t,e){const i=t.body===void 0?{}:w(t.body,W,e),o=c(i,"reason",e),n=c(i,"actor",e),r=c(i,"disposition",e);return r!==void 0&&r!=="canceled"&&r!=="dismissed"&&e.push({field:"disposition",problem:'must be "canceled" or "dismissed"',received:r}),{...o===void 0?{}:{reason:o},...n===void 0?{}:{actor:n},...r==="canceled"||r==="dismissed"?{disposition:r}:{}}}s(x,"parseCancel");function z(t,e){w(t.body,[],e)}s(z,"requireEmptyBody");async function H(t){const e=K(t),i=b(e.origin_node_id);i!==null&&T(i,"crtr:act");const{document:o,file:n,...r}=e,d=await $({...r,...o===void 0?{file:n??""}:{document:J(t,o)}});return{status:200,body:f(d)}}s(H,"handleCreate");function J(t,e){return R(i=>{const o=L(i,t),n=B(i,o,e);if("remote"in n)throw new m(404,"not_found",`no document named ${n.remote} on this runtime`,{next:"Check the name with `crtr canvas search`."});if("deleted"in n)throw new m(404,"not_found",`${n.deleted.name} is deleted`,{id:n.deleted.id,deleted:!0});if(n.type!=="document")throw new m(400,"invalid_request",`${e} is a ${n.type}, not a document`);const r=q(i,o,n,u=>S(i,u));if(r.needsMerge)throw new m(409,"needs_merge",`${n.name} has ${r.heads.length} heads; merge them before a review`,{id:n.id,next:`Read it with \`crtr canvas read ${n.id}\` and write the merged body with \`crtr doc edit\`.`});const d=n.owner===null?null:E(i,n.owner),a=d===null?"":d.type==="node"?d.id:d.name;return{id:n.id,name:a===""?n.name:`${a}/${n.name}`,base:r.record.heads_key,body:r.heads[0].body}})}s(J,"reviewedDocument");function Q(t){const e=M(t);return{status:200,body:{reviews:D(e).filter(o=>{if(t.principal.class==="person")return!0;const n=b(o.origin_node_id);return n!==null&&N(t.principal,n.grantee??"app:terminal",n.node_id)}).map(f)}}}s(Q,"handleList");function U(t){const e=[],i=h(t,e);return(e.length>0||i===void 0)&&l(e),{status:200,body:f(y(i))}}s(U,"handleRead");async function X(t){const e=[],i=h(t,e);z(t,e),(e.length>0||i===void 0)&&l(e);const o=await A(i);return{status:200,body:o.outcome==="awaiting_companion"?{review:f(o.record),outcome:o.outcome}:{review:f(o.record),result:O(o.result),outcome:o.outcome}}}s(X,"handleSubmit");async function Y(t){const e=[],i=h(t,e),o=x(t,e);(e.length>0||i===void 0)&&l(e);const n=await I(i,o);return{status:200,body:{review:f(n.record),outcome:n.outcome}}}s(Y,"handleCancel");function Z(t){const e=[],i=h(t,e);(e.length>0||i===void 0)&&l(e);const o=y(i),n=C(o.review_id);if(n===null)throw new Error(`review anchor base is missing: ${o.review_id}`);return{status:200,body:{review_id:o.review_id,anchor_base_sha256:n.sha256,anchor_base_text:new TextDecoder("utf-8",{fatal:!0}).decode(n.bytes),file:o.file}}}s(Z,"handleDocument");const ve=[{method:"POST",pattern:"/v1/human/reviews",scope:"crtr:act",handler:H},{method:"GET",pattern:"/v1/human/reviews",handler:Q},{method:"GET",pattern:"/v1/human/reviews/:review_id",handler:U},{method:"POST",pattern:"/v1/human/reviews/:review_id/submit",handler:X},{method:"POST",pattern:"/v1/human/reviews/:review_id/cancel",handler:Y},{method:"GET",pattern:"/v1/human/reviews/:review_id/document",handler:Z}];export{K as parseCreate,ve as reviewRoutes};
1
+ var k=Object.defineProperty;var s=(t,e)=>k(t,"name",{value:e,configurable:!0});import{ApiError as m}from"../../../api/index.js";import{withCanvasWrite as R}from"../../../core/canvas/db.js";import{isSafeNodeId as p}from"../../../core/canvas/paths.js";import{readDocument as q}from"../../../core/graph/documents.js";import{getByRowid as E}from"../../../core/graph/objects.js";import{checkoutsForCwd as S}from"../../../core/graph/repo-sync/repos.js";import{getNode as b}from"../../../core/canvas/canvas.js";import{assertScope as T}from"../../../core/scopes.js";import{createReview as $}from"../../../core/review/birth.js";import{readAnchorBase as C,listReviews as D,requireVisibleReview as y}from"../../../core/review/store.js";import{cancelReview as I,submitReviewApproval as A}from"../../review/finish.js";import{toFeedbackResultDTO as O,toReviewDTO as F}from"../map.js";import{readerFor as L,resolveRef as B}from"../reader.js";import{canReadNode as N}from"../router.js";import{invalidRequest as P,objectBody as v,optionalString as c,requireParam as j,requiredString as g}from"./validate.js";import{filterAsync as G}from"../../../core/async-array.js";const V=new Set(["open","approved","canceled"]),W=["origin_kind","origin_node_id","document","file","idempotency_key","subtitle","output_path"],K=["reason","actor","disposition"];function l(t){P("review request",t)}s(l,"invalidRequest");function w(t,e){return j(t,"review_id","must be a safe review id",p,e)}s(w,"requireReviewId");function f(t){return{...F(t,t.state==="approved"?{result_path:`${t.review_dir}/result.json`}:{}),review_dir:t.review_dir}}s(f,"toReviewResponseDTO");function M(t){const e=[],n=v(t.body,W,e),o=n.origin_kind,i=o==="ticket"||o==="inline"?o:void 0;i===void 0&&e.push({field:"origin_kind",problem:"must be ticket or inline",...o===void 0?{}:{received:o}});const r=g(n,"origin_node_id",e);r!==void 0&&!p(r)&&e.push({field:"origin_node_id",problem:"must be a safe node id",received:r});const d=c(n,"document",e),u=c(n,"file",e);i==="ticket"&&(d===void 0||u!==void 0)&&e.push({field:"document",problem:"is required for ticket reviews, and file is not allowed"}),i==="inline"&&u===void 0==(d===void 0)&&e.push({field:"file",problem:"inline reviews take exactly one of file or document"});const a=g(n,"idempotency_key",e);a!==void 0&&a.length>128&&e.push({field:"idempotency_key",problem:"must be at most 128 characters",received:a});const h=c(n,"subtitle",e),_=c(n,"output_path",e);return i==="ticket"&&h===void 0&&n.subtitle===void 0&&e.push({field:"subtitle",problem:"is required for ticket reviews"}),i==="inline"&&n.subtitle!==void 0&&e.push({field:"subtitle",problem:"is only allowed for ticket reviews",received:n.subtitle}),i==="inline"&&n.output_path!==void 0&&e.push({field:"output_path",problem:"is only allowed for ticket reviews",received:n.output_path}),(e.length>0||i===void 0||r===void 0||!p(r)||a===void 0||a.length>128)&&l(e),{origin_kind:i,origin_node_id:r,...d===void 0?{}:{document:d},...u===void 0?{}:{file:u},idempotency_key:a,...h===void 0?{}:{subtitle:h},..._===void 0?{}:{output_path:_}}}s(M,"parseCreate");function x(t){const e=[],n={},o=new Set(["state","origin_node_id","file"]);for(const[i,r]of t.query.entries())o.has(i)||e.push({field:i,problem:"is not allowed",received:r});for(const i of o){const r=t.query.getAll(i);if(r.length>1){e.push({field:i,problem:"must appear at most once",received:r});continue}const d=r[0];d!==void 0&&(i==="state"?V.has(d)?n.state=d:e.push({field:i,problem:"must be open, approved, or canceled",received:d}):i==="origin_node_id"?p(d)?n.origin_node_id=d:e.push({field:i,problem:"must be a safe node id",received:d}):d===""?e.push({field:i,problem:"must be a non-empty string",received:d}):n.file=d)}return e.length>0&&l(e),n}s(x,"parseList");function z(t,e){const n=t.body===void 0?{}:v(t.body,K,e),o=c(n,"reason",e),i=c(n,"actor",e),r=c(n,"disposition",e);return r!==void 0&&r!=="canceled"&&r!=="dismissed"&&e.push({field:"disposition",problem:'must be "canceled" or "dismissed"',received:r}),{...o===void 0?{}:{reason:o},...i===void 0?{}:{actor:i},...r==="canceled"||r==="dismissed"?{disposition:r}:{}}}s(z,"parseCancel");function H(t,e){v(t.body,[],e)}s(H,"requireEmptyBody");async function J(t){const e=M(t),n=await b(e.origin_node_id);n!==null&&T(n,"crtr:act");const{document:o,file:i,...r}=e,d=await $({...r,...o===void 0?{file:i??""}:{document:await Q(t,o)}});return{status:200,body:f(d)}}s(J,"handleCreate");async function Q(t,e){return await R(async n=>{const o=await L(n,t),i=await B(n,o,e);if("remote"in i)throw new m(404,"not_found",`no document named ${i.remote} on this runtime`,{next:"Check the name with `crtr canvas search`."});if("deleted"in i)throw new m(404,"not_found",`${i.deleted.name} is deleted`,{id:i.deleted.id,deleted:!0});if(i.type!=="document")throw new m(400,"invalid_request",`${e} is a ${i.type}, not a document`);const r=await q(n,o,i,async a=>await S(n,a));if(r.needsMerge)throw new m(409,"needs_merge",`${i.name} has ${r.heads.length} heads; merge them before a review`,{id:i.id,next:`Read it with \`crtr canvas read ${i.id}\` and write the merged body with \`crtr doc edit\`.`});const d=i.owner===null?null:await E(n,i.owner),u=d===null?"":d.type==="node"?d.id:d.name;return{id:i.id,name:u===""?i.name:`${u}/${i.name}`,base:r.record.heads_key,body:r.heads[0].body}})}s(Q,"reviewedDocument");async function U(t){const e=x(t);return{status:200,body:{reviews:(await G(await D(e),async o=>{if(t.principal.class==="person")return!0;const i=await b(o.origin_node_id);return i!==null&&await N(t.principal,i.grantee??"app:terminal",i.node_id)})).map(f)}}}s(U,"handleList");async function X(t){const e=[],n=w(t,e);return(e.length>0||n===void 0)&&l(e),{status:200,body:f(await y(n))}}s(X,"handleRead");async function Y(t){const e=[],n=w(t,e);H(t,e),(e.length>0||n===void 0)&&l(e);const o=await A(n);return{status:200,body:o.outcome==="awaiting_companion"?{review:f(o.record),outcome:o.outcome}:{review:f(o.record),result:O(o.result),outcome:o.outcome}}}s(Y,"handleSubmit");async function Z(t){const e=[],n=w(t,e),o=z(t,e);(e.length>0||n===void 0)&&l(e);const i=await I(n,o);return{status:200,body:{review:f(i.record),outcome:i.outcome}}}s(Z,"handleCancel");async function ee(t){const e=[],n=w(t,e);(e.length>0||n===void 0)&&l(e);const o=await y(n),i=await C(o.review_id);if(i===null)throw new Error(`review anchor base is missing: ${o.review_id}`);return{status:200,body:{review_id:o.review_id,anchor_base_sha256:i.sha256,anchor_base_text:new TextDecoder("utf-8",{fatal:!0}).decode(i.bytes),file:o.file}}}s(ee,"handleDocument");const _e=[{method:"POST",pattern:"/v1/human/reviews",scope:"crtr:act",handler:J},{method:"GET",pattern:"/v1/human/reviews",handler:U},{method:"GET",pattern:"/v1/human/reviews/:review_id",handler:X},{method:"POST",pattern:"/v1/human/reviews/:review_id/submit",handler:Y},{method:"POST",pattern:"/v1/human/reviews/:review_id/cancel",handler:Z},{method:"GET",pattern:"/v1/human/reviews/:review_id/document",handler:ee}];export{M as parseCreate,_e as reviewRoutes};