@north-light/cli 0.3.529 → 0.3.531

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (509) hide show
  1. package/dist/api/dto/lifecycle.d.ts +3 -1
  2. package/dist/api/dto/messages.d.ts +5 -3
  3. package/dist/builtin-memory/crouter-plugin/bundles-and-memory.md +1 -1
  4. package/dist/builtin-memory/crouter-plugin/commands.md +1 -1
  5. package/dist/clients/attach/session/connection.js +1 -1
  6. package/dist/clients/attach/session/reconnect.js +1 -1
  7. package/dist/clients/attach/viewer.js +508 -508
  8. package/dist/commands/node/message.js +1 -1
  9. package/dist/commands/sys/join.js +1 -1
  10. package/dist/core/async-array.d.ts +7 -0
  11. package/dist/core/async-array.js +1 -0
  12. package/dist/core/audit.d.ts +1 -1
  13. package/dist/core/audit.js +2 -2
  14. package/dist/core/canvas/attention.d.ts +4 -4
  15. package/dist/core/canvas/attention.js +1 -1
  16. package/dist/core/canvas/boot.d.ts +4 -4
  17. package/dist/core/canvas/boot.js +1 -1
  18. package/dist/core/canvas/canvas.d.ts +59 -59
  19. package/dist/core/canvas/canvas.js +19 -19
  20. package/dist/core/canvas/context-strip.js +2 -2
  21. package/dist/core/canvas/crons.d.ts +27 -27
  22. package/dist/core/canvas/crons.js +11 -11
  23. package/dist/core/canvas/daemon-actions.d.ts +10 -10
  24. package/dist/core/canvas/daemon-actions.js +8 -8
  25. package/dist/core/canvas/daemon-owner.d.ts +3 -3
  26. package/dist/core/canvas/daemon-owner.js +2 -2
  27. package/dist/core/canvas/db.d.ts +19 -30
  28. package/dist/core/canvas/db.js +3 -2
  29. package/dist/core/canvas/deliveries.d.ts +16 -16
  30. package/dist/core/canvas/deliveries.js +24 -24
  31. package/dist/core/canvas/executions.d.ts +8 -8
  32. package/dist/core/canvas/executions.js +1 -1
  33. package/dist/core/canvas/focuses.d.ts +8 -8
  34. package/dist/core/canvas/focuses.js +1 -1
  35. package/dist/core/canvas/history.d.ts +3 -3
  36. package/dist/core/canvas/history.js +9 -9
  37. package/dist/core/canvas/install-id.d.ts +1 -1
  38. package/dist/core/canvas/install-id.js +1 -1
  39. package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +1 -1
  40. package/dist/core/canvas/managed-worktree-sweep-candidates.js +2 -2
  41. package/dist/core/canvas/memory-reads.d.ts +6 -6
  42. package/dist/core/canvas/memory-reads.js +1 -1
  43. package/dist/core/canvas/nav-model.d.ts +13 -13
  44. package/dist/core/canvas/nav-model.js +1 -1
  45. package/dist/core/canvas/node-agent-paths.d.ts +6 -6
  46. package/dist/core/canvas/node-agent-paths.js +1 -1
  47. package/dist/core/canvas/node-tokens.d.ts +7 -7
  48. package/dist/core/canvas/node-tokens.js +3 -3
  49. package/dist/core/canvas/outcome-actions.d.ts +5 -5
  50. package/dist/core/canvas/outcome-actions.js +3 -3
  51. package/dist/core/canvas/recovery.d.ts +26 -26
  52. package/dist/core/canvas/recovery.js +2 -2
  53. package/dist/core/canvas/render-source.d.ts +1 -1
  54. package/dist/core/canvas/render-source.js +1 -1
  55. package/dist/core/canvas/sessions.d.ts +10 -10
  56. package/dist/core/canvas/sessions.js +4 -4
  57. package/dist/core/canvas/source.js +1 -1
  58. package/dist/core/canvas/structured-requests.d.ts +15 -15
  59. package/dist/core/canvas/structured-requests.js +5 -5
  60. package/dist/core/canvas/tree.d.ts +9 -9
  61. package/dist/core/canvas/tree.js +5 -5
  62. package/dist/core/canvas/waits.d.ts +13 -13
  63. package/dist/core/canvas/waits.js +6 -6
  64. package/dist/core/canvas/worktrees.d.ts +15 -15
  65. package/dist/core/canvas/worktrees.js +1 -1
  66. package/dist/core/command-hooks/lifecycle-catalog.d.ts +4 -4
  67. package/dist/core/command-hooks/lifecycle-catalog.js +1 -1
  68. package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
  69. package/dist/core/command-plugins/bundle.d.ts +1 -1
  70. package/dist/core/command-plugins/bundle.js +1 -1
  71. package/dist/core/conversation-store/file-store.d.ts +7 -7
  72. package/dist/core/conversation-store/file-store.js +9 -9
  73. package/dist/core/conversation-store/index.d.ts +16 -14
  74. package/dist/core/conversation-store/index.js +1 -1
  75. package/dist/core/conversation-store/listener.js +5 -5
  76. package/dist/core/conversation-store/patch.d.ts +3 -1
  77. package/dist/core/conversation-store/patch.js +1 -1
  78. package/dist/core/directory/join.d.ts +1 -1
  79. package/dist/core/feed/feed.js +3 -3
  80. package/dist/core/feed/inbox.d.ts +2 -2
  81. package/dist/core/feed/inbox.js +1 -1
  82. package/dist/core/feed/messages.d.ts +11 -12
  83. package/dist/core/feed/messages.js +5 -5
  84. package/dist/core/feed/reports.d.ts +4 -4
  85. package/dist/core/feed/reports.js +2 -2
  86. package/dist/core/grants/cover.d.ts +1 -1
  87. package/dist/core/grants/cover.js +1 -1
  88. package/dist/core/grants/local.d.ts +1 -1
  89. package/dist/core/grants/local.js +1 -1
  90. package/dist/core/grants/mirror.d.ts +19 -19
  91. package/dist/core/grants/mirror.js +2 -2
  92. package/dist/core/grants/on-sync.d.ts +1 -1
  93. package/dist/core/grants/on-sync.js +1 -1
  94. package/dist/core/grants/remove.js +1 -1
  95. package/dist/core/grants/sync.js +1 -1
  96. package/dist/core/graph/access.d.ts +17 -17
  97. package/dist/core/graph/access.js +3 -3
  98. package/dist/core/graph/custom.d.ts +16 -16
  99. package/dist/core/graph/custom.js +9 -9
  100. package/dist/core/graph/deletion.d.ts +3 -7
  101. package/dist/core/graph/deletion.js +4 -4
  102. package/dist/core/graph/documents.d.ts +24 -27
  103. package/dist/core/graph/documents.js +7 -7
  104. package/dist/core/graph/edges.d.ts +13 -13
  105. package/dist/core/graph/edges.js +1 -1
  106. package/dist/core/graph/events.d.ts +7 -9
  107. package/dist/core/graph/events.js +8 -8
  108. package/dist/core/graph/exposures.d.ts +6 -6
  109. package/dist/core/graph/exposures.js +4 -4
  110. package/dist/core/graph/jobs.d.ts +6 -8
  111. package/dist/core/graph/jobs.js +2 -2
  112. package/dist/core/graph/kinds/action.js +1 -1
  113. package/dist/core/graph/kinds/custom.js +2 -2
  114. package/dist/core/graph/kinds/document.d.ts +1 -0
  115. package/dist/core/graph/kinds/document.js +4 -4
  116. package/dist/core/graph/kinds/dto.d.ts +2 -2
  117. package/dist/core/graph/kinds/dto.js +1 -1
  118. package/dist/core/graph/kinds/job.js +2 -2
  119. package/dist/core/graph/kinds/kind.d.ts +6 -8
  120. package/dist/core/graph/kinds/kind.js +1 -1
  121. package/dist/core/graph/kinds/node.js +5 -5
  122. package/dist/core/graph/kinds/owner.js +2 -2
  123. package/dist/core/graph/kinds/registry.d.ts +6 -9
  124. package/dist/core/graph/kinds/registry.js +1 -1
  125. package/dist/core/graph/names.d.ts +6 -6
  126. package/dist/core/graph/names.js +3 -3
  127. package/dist/core/graph/object-waits.d.ts +4 -7
  128. package/dist/core/graph/object-waits.js +1 -1
  129. package/dist/core/graph/objects.d.ts +14 -14
  130. package/dist/core/graph/objects.js +9 -9
  131. package/dist/core/graph/package-docs.d.ts +2 -7
  132. package/dist/core/graph/package-docs.js +5 -5
  133. package/dist/core/graph/package-kinds.d.ts +2 -5
  134. package/dist/core/graph/package-kinds.js +1 -1
  135. package/dist/core/graph/package-reconcile.d.ts +2 -5
  136. package/dist/core/graph/package-reconcile.js +1 -1
  137. package/dist/core/graph/reader.d.ts +18 -18
  138. package/dist/core/graph/reader.js +3 -3
  139. package/dist/core/graph/receivers.d.ts +4 -4
  140. package/dist/core/graph/receivers.js +5 -5
  141. package/dist/core/graph/repo-sync/exchange.d.ts +3 -7
  142. package/dist/core/graph/repo-sync/exchange.js +2 -2
  143. package/dist/core/graph/repo-sync/repos.d.ts +7 -5
  144. package/dist/core/graph/repo-sync/repos.js +3 -3
  145. package/dist/core/graph/repo-sync/sync.d.ts +3 -6
  146. package/dist/core/graph/repo-sync/sync.js +2 -2
  147. package/dist/core/graph/rules.d.ts +5 -5
  148. package/dist/core/graph/rules.js +3 -3
  149. package/dist/core/graph/spaces/app.js +1 -1
  150. package/dist/core/graph/spaces/index.d.ts +4 -5
  151. package/dist/core/graph/spaces/index.js +1 -1
  152. package/dist/core/graph/spaces/own-memory.d.ts +4 -4
  153. package/dist/core/graph/spaces/own-memory.js +1 -1
  154. package/dist/core/graph/spaces/person.js +3 -3
  155. package/dist/core/graph/spaces/repo.d.ts +1 -1
  156. package/dist/core/graph/spaces/repo.js +1 -1
  157. package/dist/core/graph/watches.d.ts +15 -15
  158. package/dist/core/graph/watches.js +10 -10
  159. package/dist/core/human/feedback-companion.d.ts +2 -2
  160. package/dist/core/human/feedback-companion.js +1 -1
  161. package/dist/core/human/feedback.d.ts +3 -3
  162. package/dist/core/human/feedback.js +1 -1
  163. package/dist/core/human/requests.d.ts +34 -33
  164. package/dist/core/human/requests.js +20 -20
  165. package/dist/core/human/scan.d.ts +2 -2
  166. package/dist/core/human/scan.js +1 -1
  167. package/dist/core/human/tickets.d.ts +9 -9
  168. package/dist/core/human/tickets.js +1 -1
  169. package/dist/core/llm/app-rungs.d.ts +1 -1
  170. package/dist/core/llm/app-rungs.js +1 -1
  171. package/dist/core/llm/run.js +1 -1
  172. package/dist/core/peer/directory.d.ts +1 -1
  173. package/dist/core/peer/directory.js +1 -1
  174. package/dist/core/peer/envelope.d.ts +3 -3
  175. package/dist/core/peer/envelope.js +1 -1
  176. package/dist/core/peer/home.d.ts +7 -7
  177. package/dist/core/peer/home.js +2 -2
  178. package/dist/core/peer/ingest.d.ts +6 -6
  179. package/dist/core/peer/ingest.js +1 -1
  180. package/dist/core/peer/outbox-store.d.ts +14 -14
  181. package/dist/core/peer/outbox-store.js +5 -5
  182. package/dist/core/peer/receiver.d.ts +2 -2
  183. package/dist/core/peer/receiver.js +1 -1
  184. package/dist/core/peer/stubs.d.ts +10 -10
  185. package/dist/core/peer/stubs.js +1 -1
  186. package/dist/core/providers/approval.d.ts +2 -2
  187. package/dist/core/providers/approval.js +2 -2
  188. package/dist/core/providers/audit.d.ts +3 -3
  189. package/dist/core/providers/audit.js +2 -2
  190. package/dist/core/providers/bundles.js +2 -2
  191. package/dist/core/providers/call.d.ts +2 -2
  192. package/dist/core/providers/call.js +1 -1
  193. package/dist/core/providers/files.d.ts +1 -1
  194. package/dist/core/providers/files.js +1 -1
  195. package/dist/core/providers/mint.js +1 -1
  196. package/dist/core/providers/receipts.d.ts +1 -1
  197. package/dist/core/providers/receipts.js +2 -2
  198. package/dist/core/review/birth.js +1 -1
  199. package/dist/core/review/comments.d.ts +19 -19
  200. package/dist/core/review/comments.js +5 -5
  201. package/dist/core/review/companion.d.ts +1 -1
  202. package/dist/core/review/companion.js +1 -1
  203. package/dist/core/review/document.d.ts +3 -3
  204. package/dist/core/review/document.js +2 -2
  205. package/dist/core/review/fork.js +2 -2
  206. package/dist/core/review/realize.js +1 -1
  207. package/dist/core/review/remap.d.ts +2 -2
  208. package/dist/core/review/remap.js +4 -4
  209. package/dist/core/review/stage.d.ts +1 -1
  210. package/dist/core/review/stage.js +1 -1
  211. package/dist/core/review/store.d.ts +21 -21
  212. package/dist/core/review/store.js +1 -1
  213. package/dist/core/runs/activity.d.ts +1 -1
  214. package/dist/core/runs/activity.js +5 -5
  215. package/dist/core/runs/confinement.d.ts +7 -7
  216. package/dist/core/runs/confinement.js +2 -2
  217. package/dist/core/runs/events.d.ts +12 -12
  218. package/dist/core/runs/events.js +4 -4
  219. package/dist/core/runs/operations.d.ts +11 -11
  220. package/dist/core/runs/operations.js +5 -5
  221. package/dist/core/runs/questions.d.ts +10 -10
  222. package/dist/core/runs/questions.js +3 -3
  223. package/dist/core/runtime/auth-reload.js +1 -1
  224. package/dist/core/runtime/bearings.d.ts +5 -5
  225. package/dist/core/runtime/bearings.js +6 -6
  226. package/dist/core/runtime/broker-inventory.js +1 -1
  227. package/dist/core/runtime/broker-request.js +1 -1
  228. package/dist/core/runtime/broker.js +1 -1
  229. package/dist/core/runtime/close.d.ts +3 -3
  230. package/dist/core/runtime/close.js +1 -1
  231. package/dist/core/runtime/deliver-live.js +1 -1
  232. package/dist/core/runtime/fleet.d.ts +2 -2
  233. package/dist/core/runtime/host.d.ts +3 -3
  234. package/dist/core/runtime/host.js +3 -3
  235. package/dist/core/runtime/kickoff.d.ts +12 -12
  236. package/dist/core/runtime/kickoff.js +17 -17
  237. package/dist/core/runtime/launch-target.d.ts +1 -1
  238. package/dist/core/runtime/launch-target.js +1 -1
  239. package/dist/core/runtime/ledger.d.ts +3 -3
  240. package/dist/core/runtime/ledger.js +3 -3
  241. package/dist/core/runtime/lifecycle.d.ts +1 -1
  242. package/dist/core/runtime/lifecycle.js +2 -2
  243. package/dist/core/runtime/memory-admission.js +1 -1
  244. package/dist/core/runtime/model-swap.d.ts +2 -2
  245. package/dist/core/runtime/model-swap.js +1 -1
  246. package/dist/core/runtime/node-read.d.ts +1 -1
  247. package/dist/core/runtime/node-read.js +2 -2
  248. package/dist/core/runtime/nodes.d.ts +6 -6
  249. package/dist/core/runtime/nodes.js +1 -1
  250. package/dist/core/runtime/outcome-document.d.ts +1 -1
  251. package/dist/core/runtime/outcome-document.js +1 -1
  252. package/dist/core/runtime/persona.d.ts +3 -3
  253. package/dist/core/runtime/persona.js +2 -2
  254. package/dist/core/runtime/placement.d.ts +11 -11
  255. package/dist/core/runtime/placement.js +1 -1
  256. package/dist/core/runtime/promote.d.ts +3 -3
  257. package/dist/core/runtime/promote.js +1 -1
  258. package/dist/core/runtime/recycle.js +1 -1
  259. package/dist/core/runtime/reopen.d.ts +21 -10
  260. package/dist/core/runtime/reopen.js +1 -1
  261. package/dist/core/runtime/reset.d.ts +4 -4
  262. package/dist/core/runtime/reset.js +1 -1
  263. package/dist/core/runtime/revive-all.d.ts +2 -2
  264. package/dist/core/runtime/revive-all.js +1 -1
  265. package/dist/core/runtime/revive.d.ts +4 -4
  266. package/dist/core/runtime/revive.js +2 -2
  267. package/dist/core/runtime/roadmap.d.ts +6 -6
  268. package/dist/core/runtime/roadmap.js +5 -5
  269. package/dist/core/runtime/session-branch.d.ts +1 -1
  270. package/dist/core/runtime/session-branch.js +1 -1
  271. package/dist/core/runtime/session-list-cache.js +1 -1
  272. package/dist/core/runtime/situational-live.js +1 -1
  273. package/dist/core/runtime/spawn.d.ts +2 -2
  274. package/dist/core/runtime/spawn.js +2 -2
  275. package/dist/core/runtime/stop-guard.d.ts +2 -2
  276. package/dist/core/runtime/stop-guard.js +3 -3
  277. package/dist/core/runtime/warm-pool.d.ts +2 -2
  278. package/dist/core/runtime/warm-pool.js +1 -1
  279. package/dist/core/spaces/mounts.d.ts +2 -2
  280. package/dist/core/spaces/mounts.js +1 -1
  281. package/dist/core/spaces/permissions.d.ts +1 -1
  282. package/dist/core/spaces/permissions.js +1 -1
  283. package/dist/core/spaces/process.d.ts +1 -1
  284. package/dist/core/spaces/process.js +1 -1
  285. package/dist/core/spaces/space.js +1 -1
  286. package/dist/core/spaces/stop.d.ts +3 -3
  287. package/dist/core/spaces/stop.js +2 -2
  288. package/dist/core/spaces/users.d.ts +6 -6
  289. package/dist/core/spaces/users.js +1 -1
  290. package/dist/core/storage/attachments.d.ts +2 -2
  291. package/dist/core/storage/attachments.js +1 -1
  292. package/dist/core/storage/shares.d.ts +2 -2
  293. package/dist/core/storage/shares.js +1 -1
  294. package/dist/core/storage/tables.d.ts +21 -21
  295. package/dist/core/storage/tables.js +3 -3
  296. package/dist/core/substrate/delivery/corpus.d.ts +5 -8
  297. package/dist/core/substrate/delivery/corpus.js +3 -3
  298. package/dist/core/substrate/delivery/deliver.d.ts +10 -15
  299. package/dist/core/substrate/delivery/deliver.js +3 -3
  300. package/dist/core/substrate/delivery/plan.d.ts +2 -12
  301. package/dist/core/substrate/delivery/plan.js +3 -3
  302. package/dist/core/substrate/delivery/render-boot.d.ts +4 -4
  303. package/dist/core/substrate/delivery/render-boot.js +18 -18
  304. package/dist/core/substrate/delivery/render-event.d.ts +7 -14
  305. package/dist/core/substrate/delivery/render-event.js +4 -4
  306. package/dist/core/substrate/subject.d.ts +2 -2
  307. package/dist/core/substrate/subject.js +1 -1
  308. package/dist/core/usage/ledger.d.ts +6 -6
  309. package/dist/core/usage/ledger.js +4 -4
  310. package/dist/core/worktree-close.js +4 -4
  311. package/dist/core/worktree-mutation-async.js +7 -7
  312. package/dist/core/worktree-quarantine.js +1 -1
  313. package/dist/core/worktree-sweep.d.ts +1 -1
  314. package/dist/core/worktree-sweep.js +6 -6
  315. package/dist/core/worktree.d.ts +5 -5
  316. package/dist/core/worktree.js +13 -13
  317. package/dist/daemon/analytics/compute.d.ts +2 -2
  318. package/dist/daemon/analytics/compute.js +1 -1
  319. package/dist/daemon/api/app-listener.d.ts +4 -4
  320. package/dist/daemon/api/app-listener.js +13 -13
  321. package/dist/daemon/api/bridge.js +5 -5
  322. package/dist/daemon/api/document-listener.js +6 -6
  323. package/dist/daemon/api/handlers/analytics.js +1 -1
  324. package/dist/daemon/api/handlers/attach.js +1 -1
  325. package/dist/daemon/api/handlers/bash-jobs.js +1 -1
  326. package/dist/daemon/api/handlers/bash.js +1 -1
  327. package/dist/daemon/api/handlers/broker-ops.d.ts +1 -1
  328. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  329. package/dist/daemon/api/handlers/broker-recovery.d.ts +1 -1
  330. package/dist/daemon/api/handlers/broker-recovery.js +1 -1
  331. package/dist/daemon/api/handlers/broker-signals.d.ts +2 -2
  332. package/dist/daemon/api/handlers/broker-signals.js +2 -2
  333. package/dist/daemon/api/handlers/canvas.d.ts +1 -1
  334. package/dist/daemon/api/handlers/canvas.js +4 -4
  335. package/dist/daemon/api/handlers/chat-inventory.js +1 -1
  336. package/dist/daemon/api/handlers/crons.js +1 -1
  337. package/dist/daemon/api/handlers/custom-objects.d.ts +4 -4
  338. package/dist/daemon/api/handlers/custom-objects.js +3 -3
  339. package/dist/daemon/api/handlers/delivery-retry.js +1 -1
  340. package/dist/daemon/api/handlers/delivery.js +1 -1
  341. package/dist/daemon/api/handlers/docs.d.ts +4 -4
  342. package/dist/daemon/api/handlers/docs.js +1 -1
  343. package/dist/daemon/api/handlers/feedback-comments.js +3 -3
  344. package/dist/daemon/api/handlers/files.js +1 -1
  345. package/dist/daemon/api/handlers/focus.js +1 -1
  346. package/dist/daemon/api/handlers/health.js +3 -3
  347. package/dist/daemon/api/handlers/hook-exec.js +1 -1
  348. package/dist/daemon/api/handlers/human-requests.js +1 -1
  349. package/dist/daemon/api/handlers/inbox-page.d.ts +1 -1
  350. package/dist/daemon/api/handlers/inbox-page.js +1 -1
  351. package/dist/daemon/api/handlers/inbox.d.ts +1 -1
  352. package/dist/daemon/api/handlers/inbox.js +1 -1
  353. package/dist/daemon/api/handlers/llm.d.ts +1 -1
  354. package/dist/daemon/api/handlers/llm.js +3 -3
  355. package/dist/daemon/api/handlers/memory-reads.js +1 -1
  356. package/dist/daemon/api/handlers/memory.d.ts +5 -5
  357. package/dist/daemon/api/handlers/memory.js +5 -5
  358. package/dist/daemon/api/handlers/messages.js +2 -2
  359. package/dist/daemon/api/handlers/node-events.d.ts +2 -2
  360. package/dist/daemon/api/handlers/node-events.js +3 -3
  361. package/dist/daemon/api/handlers/node-outcomes.js +1 -1
  362. package/dist/daemon/api/handlers/node-records.js +2 -2
  363. package/dist/daemon/api/handlers/nodes.d.ts +1 -1
  364. package/dist/daemon/api/handlers/nodes.js +1 -1
  365. package/dist/daemon/api/handlers/objects.js +3 -3
  366. package/dist/daemon/api/handlers/package-docs.js +1 -1
  367. package/dist/daemon/api/handlers/plugin-app-token.d.ts +1 -1
  368. package/dist/daemon/api/handlers/plugin-app-token.js +1 -1
  369. package/dist/daemon/api/handlers/profiles.d.ts +3 -3
  370. package/dist/daemon/api/handlers/profiles.js +1 -1
  371. package/dist/daemon/api/handlers/providers.d.ts +1 -1
  372. package/dist/daemon/api/handlers/providers.js +1 -1
  373. package/dist/daemon/api/handlers/questions.js +1 -1
  374. package/dist/daemon/api/handlers/reports.d.ts +1 -1
  375. package/dist/daemon/api/handlers/reports.js +5 -5
  376. package/dist/daemon/api/handlers/review-comments.js +1 -1
  377. package/dist/daemon/api/handlers/reviews.js +1 -1
  378. package/dist/daemon/api/handlers/runs.js +1 -1
  379. package/dist/daemon/api/handlers/structured-requests.js +1 -1
  380. package/dist/daemon/api/handlers/subscriptions.js +1 -1
  381. package/dist/daemon/api/handlers/transfer.js +1 -1
  382. package/dist/daemon/api/map.d.ts +3 -3
  383. package/dist/daemon/api/map.js +1 -1
  384. package/dist/daemon/api/principal.d.ts +1 -1
  385. package/dist/daemon/api/principal.js +1 -1
  386. package/dist/daemon/api/reader.d.ts +5 -5
  387. package/dist/daemon/api/reader.js +1 -1
  388. package/dist/daemon/api/router.d.ts +5 -5
  389. package/dist/daemon/api/router.js +1 -1
  390. package/dist/daemon/api/server.js +1 -1
  391. package/dist/daemon/broker-signals/bus.d.ts +1 -1
  392. package/dist/daemon/broker-signals/bus.js +1 -1
  393. package/dist/daemon/companion-retire.js +1 -1
  394. package/dist/daemon/cron/armed-context.d.ts +2 -2
  395. package/dist/daemon/cron/armed-context.js +1 -1
  396. package/dist/daemon/cron/authority.d.ts +2 -2
  397. package/dist/daemon/cron/authority.js +1 -1
  398. package/dist/daemon/cron/disposition.js +1 -1
  399. package/dist/daemon/cron/ended.d.ts +1 -1
  400. package/dist/daemon/cron/ended.js +2 -2
  401. package/dist/daemon/cron/escalation.js +3 -3
  402. package/dist/daemon/cron/folders.d.ts +1 -1
  403. package/dist/daemon/cron/folders.js +1 -1
  404. package/dist/daemon/cron/held.d.ts +1 -1
  405. package/dist/daemon/cron/held.js +1 -1
  406. package/dist/daemon/cron/lease-recovery.d.ts +1 -1
  407. package/dist/daemon/cron/lease-recovery.js +1 -1
  408. package/dist/daemon/cron/passes.d.ts +2 -2
  409. package/dist/daemon/cron/passes.js +1 -1
  410. package/dist/daemon/cron/run-socket.d.ts +1 -1
  411. package/dist/daemon/cron/run-socket.js +1 -1
  412. package/dist/daemon/cron/settle.js +1 -1
  413. package/dist/daemon/cron/sinks.d.ts +1 -1
  414. package/dist/daemon/cron/sinks.js +2 -2
  415. package/dist/daemon/cron-run.d.ts +12 -3
  416. package/dist/daemon/cron-run.js +2 -2
  417. package/dist/daemon/crtrd.js +6 -6
  418. package/dist/daemon/delivery/run-delivery.js +1 -1
  419. package/dist/daemon/due-sources.d.ts +3 -3
  420. package/dist/daemon/due-sources.js +1 -1
  421. package/dist/daemon/due.d.ts +3 -3
  422. package/dist/daemon/due.js +7 -7
  423. package/dist/daemon/fleet.d.ts +2 -2
  424. package/dist/daemon/fleet.js +11 -11
  425. package/dist/daemon/human/finish.js +3 -3
  426. package/dist/daemon/human/settle.d.ts +1 -1
  427. package/dist/daemon/human/settle.js +1 -1
  428. package/dist/daemon/human/sweep.js +1 -1
  429. package/dist/daemon/joined-owner.d.ts +3 -3
  430. package/dist/daemon/joined-owner.js +1 -1
  431. package/dist/daemon/messaging/node-message.js +1 -1
  432. package/dist/daemon/park-activity.d.ts +2 -2
  433. package/dist/daemon/park-activity.js +1 -1
  434. package/dist/daemon/peer/authority.js +1 -1
  435. package/dist/daemon/peer/forward.d.ts +6 -6
  436. package/dist/daemon/peer/forward.js +1 -1
  437. package/dist/daemon/peer/handlers.js +1 -1
  438. package/dist/daemon/peer/ingress.d.ts +4 -4
  439. package/dist/daemon/peer/ingress.js +1 -1
  440. package/dist/daemon/peer/outbox.d.ts +2 -2
  441. package/dist/daemon/peer/outbox.js +1 -1
  442. package/dist/daemon/peer/relay-service.js +1 -1
  443. package/dist/daemon/plugin-objects/read-leaf.d.ts +2 -2
  444. package/dist/daemon/plugin-objects/read-leaf.js +2 -2
  445. package/dist/daemon/profile-delete.js +1 -1
  446. package/dist/daemon/readiness.d.ts +2 -2
  447. package/dist/daemon/readiness.js +1 -1
  448. package/dist/daemon/reconcilers/action-lane.d.ts +1 -1
  449. package/dist/daemon/reconcilers/action-lane.js +1 -1
  450. package/dist/daemon/reconcilers/bash-deadline.js +2 -2
  451. package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
  452. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  453. package/dist/daemon/reconcilers/controller-death.d.ts +1 -1
  454. package/dist/daemon/reconcilers/controller-death.js +1 -1
  455. package/dist/daemon/reconcilers/cron-lane.d.ts +1 -1
  456. package/dist/daemon/reconcilers/cron-lane.js +1 -1
  457. package/dist/daemon/reconcilers/delivery-lane.d.ts +1 -1
  458. package/dist/daemon/reconcilers/delivery-lane.js +2 -2
  459. package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +3 -3
  460. package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
  461. package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +2 -2
  462. package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
  463. package/dist/daemon/reconcilers/live-obligation.d.ts +6 -6
  464. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  465. package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
  466. package/dist/daemon/reconcilers/node-deadline.d.ts +1 -1
  467. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  468. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  469. package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.d.ts +3 -3
  470. package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.js +1 -1
  471. package/dist/daemon/reconcilers/node-lifecycle/terminating.js +1 -1
  472. package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
  473. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.d.ts +1 -1
  474. package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
  475. package/dist/daemon/reconcilers/pending-review-submit.d.ts +1 -1
  476. package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
  477. package/dist/daemon/reconcilers/storage-due-work.js +1 -1
  478. package/dist/daemon/reconcilers/storage-maintenance.d.ts +1 -1
  479. package/dist/daemon/reconcilers/storage-maintenance.js +2 -2
  480. package/dist/daemon/reconcilers/structured-request-lane.d.ts +1 -1
  481. package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
  482. package/dist/daemon/review/comment-notify.js +2 -2
  483. package/dist/daemon/review/companion.d.ts +3 -3
  484. package/dist/daemon/review/companion.js +1 -1
  485. package/dist/daemon/review/finish.js +1 -1
  486. package/dist/daemon/review/sweep.js +1 -1
  487. package/dist/daemon/run-notices.d.ts +4 -4
  488. package/dist/daemon/run-notices.js +1 -1
  489. package/dist/daemon/runs/append-section.d.ts +2 -2
  490. package/dist/daemon/runs/append-section.js +2 -2
  491. package/dist/daemon/runs/observer.d.ts +2 -2
  492. package/dist/daemon/runs/observer.js +2 -2
  493. package/dist/daemon/structured-requests/boot.d.ts +1 -1
  494. package/dist/daemon/structured-requests/boot.js +1 -1
  495. package/dist/daemon/structured-requests/effects.js +1 -1
  496. package/dist/daemon/structured-requests/sidecar.d.ts +1 -1
  497. package/dist/daemon/structured-requests/sidecar.js +1 -1
  498. package/dist/launcher/run.js +1 -1
  499. package/dist/migrations/004-canvas-documents/apply.d.ts +3 -3
  500. package/dist/migrations/004-canvas-documents/apply.js +1 -1
  501. package/dist/migrations/004-canvas-documents/index.d.ts +2 -2
  502. package/dist/migrations/004-canvas-documents/index.js +2 -2
  503. package/dist/migrations/activation.js +2 -2
  504. package/docs/plugin/bundles-and-memory.md +1 -1
  505. package/docs/plugin/commands.md +1 -1
  506. package/docs/public-api.md +11 -0
  507. package/package.json +4 -3
  508. package/packages/crouter-identity/package.json +1 -1
  509. package/runtime.lock.json +12 -12
@@ -1,3 +1,3 @@
1
- var C=Object.defineProperty;var p=(o,e)=>C(o,"name",{value:e,configurable:!0});import{prepared as f}from"../sqlite-statements.js";import{coveredByAny as m,isSandboxedNode as L}from"../../shared/env.js";import{existsSync as A}from"node:fs";import{CrtrError as b}from"../errors.js";import{getStoredProfile as $}from"../scoped-state/profiles.js";import{userScopeRoot as M}from"../scope.js";import{parseScope as O}from"@north-light/identity";import{activeGrant as v,grantFor as N}from"../grants/mirror.js";import{prepared as F}from"../canvas/db.js";import{ApiError as T}from"../../api/errors.js";import{readConfig as W}from"../config.js";import{pluginAppToken as D}from"../secrets.js";import{SCOPE_VOCABULARY as E}from"../scopes.js";import{loadExactProfileManifest as B}from"../profiles/manifest.js";import{ensureOwner as S,getByRowid as P,nodeObject as I}from"./objects.js";function x(o,e,t,s){const r=e===null?[]:s.projectPaths(e),n=t(o),c=new Set(n.map(a=>a.repo.rowid)),l=[];for(const a of r){if(!A(a))continue;let u;try{u=t(a)}catch(i){if(i instanceof b&&i.code==="git-lookup-failed")continue;throw i}for(const i of u)c.has(i.repo.rowid)||(c.add(i.repo.rowid),l.push(i))}return{repos:n.map(a=>a.repo),checkouts:n,projectRepos:l.map(a=>a.repo),projectCheckouts:l}}p(x,"viewRepos");function ae(o,e,t){if(e.class==="anonymous")throw new Error("a publish token cannot read as a principal");if(e.class==="person")return{class:"person",person:g(o)};if(e.class==="app")return{class:"app",app:j(o,e.app),scopes:e.scopes};if(e.class==="machine")throw new Error("a machine token cannot read as a principal");if(e.class==="forwarded"){if(e.actor.kind==="person")return{class:"person",person:g(o)};const l=N(e.actor.app,e.sub);if(!l)throw new T(403,"app_not_granted",`${e.actor.app} holds no active grant for ${e.sub} on this machine`);const a=e.actor.node_scopes;return{class:"app",app:j(o,e.actor.app),place:e.actor.place,launched:a,scopes:a===null?l.resolved:a.filter(u=>m(l.resolved,u))}}if(e.class==="cron"){const l=e.grant?v(e.grant)?.resolved??[]:E,a=e.scopes;return{class:"app",app:j(o,e.app),scopes:a===null?l:a.filter(u=>m(l,u)),launched:a,place:{run:e.origin_run??"",isolated:e.isolated}}}const s=w(o),r=I(o,e.node),n=r.owner===null?null:s.object(r.owner);if(!n)throw new Error(`node ${e.node} has no owner`);const c=f(o,"SELECT cwd, profile_id FROM nodes WHERE node_id = ?").get(e.node);return{class:"node",node:r,app:n,scopes:H(e.app,e.sub,e.grant,e.scopes,s),launched:e.scopes,cwd:c.cwd,...x(c.cwd,c.profile_id,t,s),profile:c.profile_id===null?null:s.profile(c.profile_id,n)}}p(ae,"readerFor");function J(o,e,t,s=w(o),r=!1){const n=F(o,"SELECT o.* FROM objects o WHERE o.id = ? AND o.type = 'node'").get(e),c=F(o,`SELECT (SELECT external_id FROM identities WHERE object = ?) AS grantee,
2
- sub, grant_id, scopes_json, cwd, profile_id FROM nodes WHERE node_id = ?`).get(n?.owner??null,e);if(!n||!c)throw new Error(`no node ${e}`);const{grantee:l,sub:a,grant_id:u,scopes_json:i,cwd:d,profile_id:h}=c,_=n.owner===null?null:s.object(n.owner);if(!_)throw new Error(`node ${e} has no owner`);const R=i===null?null:JSON.parse(i);return{class:"node",node:n,app:_,scopes:H(l,a??"",u,R,s,r),launched:R,cwd:d,...x(d,h,t,s),profile:h===null?null:s.profile(h,_)}}p(J,"readerForNode");function pe(o,e,t=()=>[],s=w(o)){const r=f(o,"SELECT envelope_json FROM peer_stubs WHERE object = ?").get(e.rowid);if(r!==void 0)return y(o,e,r.envelope_json===null?null:JSON.parse(r.envelope_json),s);if(e.type==="node")return J(o,e.id,t,s,!0);const n=e.owner===null?null:s.object(e.owner);if(!n)throw new Error(`watcher ${e.id} has no owner`);const l=(n.type==="app"?n:n.type==="profile"&&n.owner!==null?s.object(n.owner):null)??f(o,"SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object WHERE i.external_id = 'app:terminal' AND i.scheme = 'app'").get()??f(o,"SELECT * FROM objects WHERE type = 'person' AND name = 'user' AND home_machine IS NULL").get();if(!l)throw new Error("no terminal app or person object");const a=f(o,"SELECT external_id FROM identities WHERE object = ? AND scheme = 'app'").get(l.rowid)?.external_id??"app:terminal",u=f(o,"SELECT resolved_scopes_json FROM grants WHERE grantee = ? AND status = 'active'").all(a),i=n.type==="person"?null:u.length===0?a==="app:terminal"&&!s.terminalHasIssuer()?E:s.pluginScopes(a):u.length===1?JSON.parse(u[0].resolved_scopes_json).filter(d=>d.mode==="always").map(d=>O(d.scope)):null;return{class:"object",object:e,node:e,owner:n,app:l,scopes:i,repos:n.type==="repo"?[n]:[]}}p(pe,"readerForObject");function le(o,e,t){const s=f(o,"SELECT external_id FROM identities WHERE object = ? AND scheme = 'app'").get(e.rowid)?.external_id;if(s===void 0)return null;const r=f(o,"SELECT resolved_scopes_json FROM grants WHERE grantee = ? AND status = 'active'").all(s);return r.length===0?s==="app:terminal"&&!t.terminalHasIssuer()?E:t.pluginScopes(s):r.length>1?null:JSON.parse(r[0].resolved_scopes_json).filter(n=>n.mode==="always").map(n=>O(n.scope))}p(le,"appScopesNow");function y(o,e,t,s){const r=g(o);if(t!==null&&t.app===null)return{class:"object",object:e,node:e,owner:r,app:r,scopes:null,repos:[]};const n=t?.app==null?null:j(o,t.app),c=t?.app==null?null:s.grantFor(t.app,t.sub),l=t===null||c===null?null:t.node_scopes===null?c.resolved:t.node_scopes.filter(u=>m(c.resolved,u)),a=n??(e.owner===null?r:s.object(e.owner)??r);return{class:"object",object:e,node:e,owner:a,app:a,scopes:l,launched:t?.node_scopes??null,repos:[],...t?.place==null?{}:{place:t.place}}}p(y,"readerForStub");function w(o){return{grantById:v,grantFor:N,terminalHasIssuer:p(()=>!!W("user").runtime?.issuer,"terminalHasIssuer"),pluginScopes:p(e=>D(e.replace(/^app:/,""))?.scopes??null,"pluginScopes"),object:p(e=>P(o,e),"object"),profile:p((e,t)=>U(o,e,t),"profile"),projectPaths:p(e=>L()?[]:$(M(),e)?.manifest.projects.map(t=>t.path)??[],"projectPaths")}}p(w,"liveLookups");function ce(o){const e=w(o),t=new Map,s=p((r,n)=>(t.has(r)||t.set(r,n()),t.get(r)),"memo");return{grantById:p(r=>s(`g\0${r}`,()=>e.grantById(r)),"grantById"),grantFor:p((r,n)=>s(`a\0${r}\0${n}`,()=>e.grantFor(r,n)),"grantFor"),terminalHasIssuer:p(()=>s("issuer",()=>e.terminalHasIssuer()),"terminalHasIssuer"),pluginScopes:p(r=>s(`t\0${r}`,()=>e.pluginScopes(r)),"pluginScopes"),object:p(r=>s(`o\0${r}`,()=>e.object(r)),"object"),profile:p((r,n)=>s(`p\0${r}\0${n.rowid}`,()=>e.profile(r,n)),"profile"),projectPaths:p(r=>s(`j\0${r}`,()=>e.projectPaths(r)),"projectPaths")}}p(ce,"publishLookups");function H(o,e,t,s,r,n=!1){const c=t?r.grantById(t):r.grantFor(o,e),l=c&&c.grantee===o?c.resolved:o==="app:terminal"&&!r.terminalHasIssuer()?E:null;if(l===null){if(n)return null;throw new Error(`the grant of ${o} is not active`)}return s===null?l:s.filter(a=>m(l,a))}p(H,"nodeScopes");function g(o){return S(o,"person","local-user","user:local","user")}p(g,"personObject");function j(o,e){return e==="user:local"?g(o):S(o,"app","app",e,e.replace(/^app:/,""))}p(j,"appObject");function U(o,e,t){return f(o,`SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object
3
- WHERE i.scheme = 'profile' AND i.external_id = ?`).get(e)??S(o,"profile","profile",e,B(e).manifest.name,t)}p(U,"profileObject");export{le as appScopesNow,w as liveLookups,U as profileObject,ce as publishLookups,ae as readerFor,J as readerForNode,pe as readerForObject,x as viewRepos};
1
+ var F=Object.defineProperty;var p=(o,e)=>F(o,"name",{value:e,configurable:!0});import{coveredByAny as f,isSandboxedNode as x}from"../../shared/env.js";import{existsSync as H}from"node:fs";import{CrtrError as C}from"../errors.js";import{getStoredProfile as L}from"../scoped-state/profiles.js";import{userScopeRoot as A}from"../scope.js";import{parseScope as R}from"@north-light/identity";import{activeGrant as O,grantFor as v}from"../grants/mirror.js";import{ApiError as b}from"../../api/errors.js";import{readConfig as $}from"../config.js";import{pluginAppToken as M}from"../secrets.js";import{SCOPE_VOCABULARY as d}from"../scopes.js";import{loadExactProfileManifest as T}from"../profiles/manifest.js";import{ensureOwner as _,getByRowid as W,nodeObject as D}from"./objects.js";async function y(o,e,t,a){const r=e===null?[]:a.projectPaths(e),n=await t(o),l=new Set(n.map(s=>s.repo.rowid)),c=[];for(const s of r){if(!H(s))continue;let i;try{i=await t(s)}catch(u){if(u instanceof C&&u.code==="git-lookup-failed")continue;throw u}for(const u of i)l.has(u.repo.rowid)||(l.add(u.repo.rowid),c.push(u))}return{repos:n.map(s=>s.repo),checkouts:n,projectRepos:c.map(s=>s.repo),projectCheckouts:c}}p(y,"viewRepos");async function re(o,e,t){if(e.class==="anonymous")throw new Error("a publish token cannot read as a principal");if(e.class==="person")return{class:"person",person:await E(o)};if(e.class==="app")return{class:"app",app:await g(o,e.app),scopes:e.scopes};if(e.class==="machine")throw new Error("a machine token cannot read as a principal");if(e.class==="forwarded"){if(e.actor.kind==="person")return{class:"person",person:await E(o)};const c=await v(e.actor.app,e.sub);if(!c)throw new b(403,"app_not_granted",`${e.actor.app} holds no active grant for ${e.sub} on this machine`);const s=e.actor.node_scopes;return{class:"app",app:await g(o,e.actor.app),place:e.actor.place,launched:s,scopes:s===null?c.resolved:s.filter(i=>f(c.resolved,i))}}if(e.class==="cron"){const c=e.grant?(await O(e.grant))?.resolved??[]:d,s=e.scopes;return{class:"app",app:await g(o,e.app),scopes:s===null?c:s.filter(i=>f(c,i)),launched:s,place:{run:e.origin_run??"",isolated:e.isolated}}}const a=m(o),r=await D(o,e.node),n=r.owner===null?null:await a.object(r.owner);if(!n)throw new Error(`node ${e.node} has no owner`);const l=await o.prepare("SELECT cwd, profile_id FROM nodes WHERE node_id = ?").get(e.node);return{class:"node",node:r,app:n,scopes:await N(e.app,e.sub,e.grant,e.scopes,a),launched:e.scopes,cwd:l.cwd,...await y(l.cwd,l.profile_id,t,a),profile:l.profile_id===null?null:await a.profile(l.profile_id,n)}}p(re,"readerFor");async function B(o,e,t,a=m(o),r=!1){const n=await o.prepare("SELECT o.* FROM objects o WHERE o.id = ? AND o.type = 'node'").get(e),l=await o.prepare(`SELECT (SELECT external_id FROM identities WHERE object = ?) AS grantee,
2
+ sub, grant_id, scopes_json, cwd, profile_id FROM nodes WHERE node_id = ?`).get(n?.owner??null,e);if(!n||!l)throw new Error(`no node ${e}`);const{grantee:c,sub:s,grant_id:i,scopes_json:u,cwd:w,profile_id:j}=l,h=n.owner===null?null:await a.object(n.owner);if(!h)throw new Error(`node ${e} has no owner`);const S=u===null?null:JSON.parse(u);return{class:"node",node:n,app:h,scopes:await N(c,s??"",i,S,a,r),launched:S,cwd:w,...await y(w,j,t,a),profile:j===null?null:await a.profile(j,h)}}p(B,"readerForNode");async function ne(o,e,t=async()=>[],a=m(o)){const r=await o.prepare("SELECT envelope_json FROM peer_stubs WHERE object = ?").get(e.rowid);if(r!==void 0)return await P(o,e,r.envelope_json===null?null:JSON.parse(r.envelope_json),a);if(e.type==="node")return await B(o,e.id,t,a,!0);const n=e.owner===null?null:await a.object(e.owner);if(!n)throw new Error(`watcher ${e.id} has no owner`);const c=(n.type==="app"?n:n.type==="profile"&&n.owner!==null?await a.object(n.owner):null)??await o.prepare("SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object WHERE i.external_id = 'app:terminal' AND i.scheme = 'app'").get()??await o.prepare("SELECT * FROM objects WHERE type = 'person' AND name = 'user' AND home_machine IS NULL").get();if(!c)throw new Error("no terminal app or person object");const s=(await o.prepare("SELECT external_id FROM identities WHERE object = ? AND scheme = 'app'").get(c.rowid))?.external_id??"app:terminal",i=await o.prepare("SELECT resolved_scopes_json FROM grants WHERE grantee = ? AND status = 'active'").all(s),u=n.type==="person"?null:i.length===0?s==="app:terminal"&&!a.terminalHasIssuer()?d:a.pluginScopes(s):i.length===1?JSON.parse(i[0].resolved_scopes_json).filter(w=>w.mode==="always").map(w=>R(w.scope)):null;return{class:"object",object:e,node:e,owner:n,app:c,scopes:u,repos:n.type==="repo"?[n]:[]}}p(ne,"readerForObject");async function te(o,e,t){const a=(await o.prepare("SELECT external_id FROM identities WHERE object = ? AND scheme = 'app'").get(e.rowid))?.external_id;if(a===void 0)return null;const r=await o.prepare("SELECT resolved_scopes_json FROM grants WHERE grantee = ? AND status = 'active'").all(a);return r.length===0?a==="app:terminal"&&!t.terminalHasIssuer()?d:t.pluginScopes(a):r.length>1?null:JSON.parse(r[0].resolved_scopes_json).filter(n=>n.mode==="always").map(n=>R(n.scope))}p(te,"appScopesNow");async function P(o,e,t,a){const r=await E(o);if(t!==null&&t.app===null)return{class:"object",object:e,node:e,owner:r,app:r,scopes:null,repos:[]};const n=t?.app==null?null:await g(o,t.app),l=t?.app==null?null:await a.grantFor(t.app,t.sub),c=t===null||l===null?null:t.node_scopes===null?l.resolved:t.node_scopes.filter(i=>f(l.resolved,i)),s=n??(e.owner===null?r:await a.object(e.owner)??r);return{class:"object",object:e,node:e,owner:s,app:s,scopes:c,launched:t?.node_scopes??null,repos:[],...t?.place==null?{}:{place:t.place}}}p(P,"readerForStub");function m(o){return{grantById:O,grantFor:v,terminalHasIssuer:p(()=>!!$("user").runtime?.issuer,"terminalHasIssuer"),pluginScopes:p(e=>M(e.replace(/^app:/,""))?.scopes??null,"pluginScopes"),object:p(async e=>await W(o,e),"object"),profile:p(async(e,t)=>await I(o,e,t),"profile"),projectPaths:p(e=>x()?[]:L(A(),e)?.manifest.projects.map(t=>t.path)??[],"projectPaths")}}p(m,"liveLookups");function ae(o){const e=m(o),t=new Map,a=p((r,n)=>(t.has(r)||t.set(r,n()),t.get(r)),"memo");return{grantById:p(r=>a(`g\0${r}`,()=>e.grantById(r)),"grantById"),grantFor:p((r,n)=>a(`a\0${r}\0${n}`,()=>e.grantFor(r,n)),"grantFor"),terminalHasIssuer:p(()=>a("issuer",()=>e.terminalHasIssuer()),"terminalHasIssuer"),pluginScopes:p(r=>a(`t\0${r}`,()=>e.pluginScopes(r)),"pluginScopes"),object:p(async r=>await a(`o\0${r}`,async()=>await e.object(r)),"object"),profile:p(async(r,n)=>await a(`p\0${r}\0${n.rowid}`,async()=>await e.profile(r,n)),"profile"),projectPaths:p(r=>a(`j\0${r}`,()=>e.projectPaths(r)),"projectPaths")}}p(ae,"publishLookups");async function N(o,e,t,a,r,n=!1){const l=t?await r.grantById(t):await r.grantFor(o,e),c=l&&l.grantee===o?l.resolved:o==="app:terminal"&&!r.terminalHasIssuer()?d:null;if(c===null){if(n)return null;throw new Error(`the grant of ${o} is not active`)}return a===null?c:a.filter(s=>f(c,s))}p(N,"nodeScopes");async function E(o){return await _(o,"person","local-user","user:local","user")}p(E,"personObject");async function g(o,e){return e==="user:local"?await E(o):await _(o,"app","app",e,e.replace(/^app:/,""))}p(g,"appObject");async function I(o,e,t){return await o.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object
3
+ WHERE i.scheme = 'profile' AND i.external_id = ?`).get(e)??await _(o,"profile","profile",e,T(e).manifest.name,t)}p(I,"profileObject");export{te as appScopesNow,m as liveLookups,I as profileObject,ae as publishLookups,re as readerFor,B as readerForNode,ne as readerForObject,y as viewRepos};
@@ -1,5 +1,5 @@
1
- import type { DatabaseSync } from 'node:sqlite';
2
1
  import type { ObjectRow, Level, ListenDelivery } from './types.js';
2
+ import type { CanvasDb } from '../canvas/db.js';
3
3
  export interface ReceiverDestination {
4
4
  id: string;
5
5
  reception: 1 | 2;
@@ -16,13 +16,13 @@ export interface ReceivedMessage {
16
16
  }
17
17
  export interface Receiver {
18
18
  bodyOwner(destinations: readonly ReceiverDestination[]): string | null;
19
- enqueue(db: DatabaseSync, message: ReceivedMessage, destinations: readonly ReceiverDestination[]): void;
19
+ enqueue(db: CanvasDb, message: ReceivedMessage, destinations: readonly ReceiverDestination[]): Promise<void>;
20
20
  }
21
21
  export type ReceiverName = 'inbox' | 'argv' | 'url' | 'queue' | 'peer';
22
22
  /** The receiver is per instance, not per kind. An action's historical argv JSON is unchanged. */
23
- export declare function receiverForObject(db: DatabaseSync, object: ObjectRow): ReceiverName | undefined;
23
+ export declare function receiverForObject(db: CanvasDb, object: ObjectRow): Promise<ReceiverName | undefined>;
24
24
  export declare const BACKLOG_CAP = 1000;
25
- export declare function onQueueSignal(objectId: string, cb: () => void): () => void;
25
+ export declare function onQueueSignal(objectId: string, cb: () => void): Promise<() => void>;
26
26
  export declare function signalQueue(id: string): void;
27
27
  export declare const argvReceiver: Receiver;
28
28
  export declare const RECEIVERS: Readonly<Record<ReceiverName, Receiver>>;
@@ -1,7 +1,7 @@
1
- var f=Object.defineProperty;var i=(e,t)=>f(e,"name",{value:t,configurable:!0});import{prepared as o}from"../sqlite-statements.js";import{randomBytes as p}from"node:crypto";import{nodeInbox as g}from"./kinds/node.js";import{peerReceiver as _}from"../peer/receiver.js";function N(e,t){const r=o(e,"SELECT receiver_json FROM custom_objects WHERE object = ?").get(t.rowid);if(!r?.receiver_json)return;const n=JSON.parse(r.receiver_json);if(n==="queue")return"queue";if(n&&typeof n=="object"&&!Array.isArray(n)){if("url"in n)return"url";if("argv"in n)return"argv"}}i(N,"receiverForObject");const E=1e3,a=new Map;function w(e,t){const r=a.get(e)??new Set;return r.add(t),a.set(e,r),()=>{r.delete(t),r.size===0&&a.delete(e)}}i(w,"onQueueSignal");function m(e){setImmediate(()=>{for(const t of a.get(e)??[])t()})}i(m,"signalQueue");function R(e,t){const r=o(e,`SELECT COUNT(*) AS n FROM deliveries WHERE destination_id = ?
2
- AND state = 'pending' AND canceled_at IS NULL`).get(t).n;if(r<=E)return;const n=o(e,`SELECT delivery_id, message_id FROM deliveries
1
+ var p=Object.defineProperty;var i=(e,r)=>p(e,"name",{value:r,configurable:!0});import{randomBytes as l}from"node:crypto";import{nodeInbox as f}from"./kinds/node.js";import{peerReceiver as g}from"../peer/receiver.js";async function T(e,r){const t=await e.prepare("SELECT receiver_json FROM custom_objects WHERE object = ?").get(r.rowid);if(!t?.receiver_json)return;const n=JSON.parse(t.receiver_json);if(n==="queue")return"queue";if(n&&typeof n=="object"&&!Array.isArray(n)){if("url"in n)return"url";if("argv"in n)return"argv"}}i(T,"receiverForObject");const u=1e3,s=new Map;async function y(e,r){const t=s.get(e)??new Set;return t.add(r),s.set(e,t),()=>{t.delete(r),t.size===0&&s.delete(e)}}i(y,"onQueueSignal");function _(e){setImmediate(()=>{for(const r of s.get(e)??[])r()})}i(_,"signalQueue");async function R(e,r){const t=(await e.prepare(`SELECT COUNT(*) AS n FROM deliveries WHERE destination_id = ?
2
+ AND state = 'pending' AND canceled_at IS NULL`).get(r)).n;if(t<=u)return;const n=await e.prepare(`SELECT delivery_id, message_id FROM deliveries
3
3
  WHERE destination_id = ? AND state = 'pending' AND canceled_at IS NULL
4
- ORDER BY created_at, rowid LIMIT ?`).all(t,r-E);for(const s of n)o(e,"DELETE FROM deliveries WHERE delivery_id = ?").run(s.delivery_id),o(e,"DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(s.message_id,s.message_id);n.length&&o(e,`UPDATE custom_objects SET dropped = dropped + ? WHERE object =
5
- (SELECT rowid FROM objects WHERE id = ?)`).run(n.length,t)}i(R,"cap");function c(e,t){return{bodyOwner:i(()=>null,"bodyOwner"),enqueue(r,n,s){const d=Date.now(),l=o(r,`INSERT INTO deliveries
4
+ ORDER BY created_at, rowid LIMIT ?`).all(r,t-u);for(const a of n)await e.prepare("DELETE FROM deliveries WHERE delivery_id = ?").run(a.delivery_id),await e.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(a.message_id,a.message_id);n.length&&await e.prepare(`UPDATE custom_objects SET dropped = dropped + ? WHERE object =
5
+ (SELECT rowid FROM objects WHERE id = ?)`).run(n.length,r)}i(R,"cap");function c(e,r){return{bodyOwner:i(()=>null,"bodyOwner"),async enqueue(t,n,a){const o=Date.now(),E=t.prepare(`INSERT INTO deliveries
6
6
  (delivery_id, message_id, destination_id, urgency, wake, state, next_attempt_at, created_at, updated_at)
7
- VALUES (?, ?, ?, 'normal', 0, 'pending', ?, ?, ?)`);for(const u of s)l.run(p(16).toString("hex"),n.messageId,u.id,e?d:null,d,d),R(r,u.id),t&&m(u.id)}}}i(c,"pushReceiver");const v=c(!0,!1),x={inbox:g,argv:v,url:c(!0,!1),queue:c(!1,!0),peer:_};export{E as BACKLOG_CAP,x as RECEIVERS,v as argvReceiver,w as onQueueSignal,N as receiverForObject,m as signalQueue};
7
+ VALUES (?, ?, ?, 'normal', 0, 'pending', ?, ?, ?)`);for(const d of a)await E.run(l(16).toString("hex"),n.messageId,d.id,e?o:null,o,o),await R(t,d.id),r&&_(d.id)}}}i(c,"pushReceiver");const m=c(!0,!1),L={inbox:f,argv:m,url:c(!0,!1),queue:c(!1,!0),peer:g};export{u as BACKLOG_CAP,L as RECEIVERS,m as argvReceiver,y as onQueueSignal,T as receiverForObject,_ as signalQueue};
@@ -1,10 +1,6 @@
1
- /** The canvas side of repo sync: export a repo space's public documents to `refs/crtr/docs`
2
- * tree files, and import a changed tree back into canvas.db. Export only reads; import only
3
- * adds revisions (never drops one) and publishes `created`, `edited` and `deleted` with a
4
- * null actor, since the act happened on another runtime. */
5
- import type { DatabaseSync } from 'node:sqlite';
6
1
  import type { ReposFn } from '../reader.js';
7
2
  import type { ObjectRow } from '../types.js';
3
+ import { type CanvasDb } from '../../canvas/db.js';
8
4
  /**
9
5
  * The tree (path → file text) of every public document the repo space owns, deleted ones
10
6
  * included. A revision already in `previous` is copied verbatim, so a remote author and the
@@ -12,7 +8,7 @@ import type { ObjectRow } from '../types.js';
12
8
  * a head carries the document's current `links-to` edges. `carry` names paths of `previous` that
13
9
  * are copied through untouched (files whose import was refused and is still pending).
14
10
  */
15
- export declare function exportRepo(db: DatabaseSync, repo: ObjectRow, previous: Map<string, string> | null, imported?: Map<string, string> | null): Map<string, string>;
11
+ export declare function exportRepo(db: CanvasDb, repo: ObjectRow, previous: Map<string, string> | null, imported?: Map<string, string> | null): Promise<Map<string, string>>;
16
12
  /** Paths of `tree` whose text differs from the baseline last imported: files that arrived but
17
13
  * have not landed in canvas.db. */
18
14
  export declare function pendingPaths(tree: Map<string, string> | null, imported: Map<string, string> | null): string[];
@@ -35,6 +31,6 @@ export interface ImportResult {
35
31
  * publishes once: `created`, `edited` (with `heads` and `needs_merge`) or `deleted`. A
36
32
  * document that fails is rolled back alone and reported in `refused`.
37
33
  */
38
- export declare function importTree(db: DatabaseSync, repo: ObjectRow, before: Map<string, string>, after: Map<string, string>, reposFn?: ReposFn): ImportResult;
34
+ export declare function importTree(db: CanvasDb, repo: ObjectRow, before: Map<string, string>, after: Map<string, string>, reposFn?: ReposFn): Promise<ImportResult>;
39
35
  /** Whether any link target in a serialized ref file is one of `arrived`. */
40
36
  export declare function namesArrived(text: string, arrived: ReadonlySet<string>): boolean;
@@ -1,2 +1,2 @@
1
- var H=Object.defineProperty;var p=(t,i)=>H(t,"name",{value:i,configurable:!0});import{prepared as g}from"../../sqlite-statements.js";import{get as W,put as P}from"../bodies.js";import{setLinks as J,setUnresolved as U}from"../edges.js";import{collectUnlinked as Y,deleteDocument as M,documentRecord as C,heads as D,importDocument as z,insertImportedRevisions as K,moveDocument as V,restoreDocument as G,setDocumentRecord as q}from"../documents.js";import{CrtrError as F}from"../../errors.js";import{publish as T}from"../events.js";import{getById as x,getByRowid as N,setObjectKind as Q}from"../objects.js";import{rulesOf as X}from"../rules.js";import{SPACES as Z}from"../spaces/index.js";import{docPath as b,mergeDoc as ee,parseDoc as y,serializeDoc as $}from"./ref-format.js";function L(t){const i=Z[t.type];if(t.owner!==null||!i||i.sync!=="repo-ref")throw new Error(`${t.type} ${t.id} is not a space that syncs through a repo ref`)}p(L,"assertRepoRefSpace");function te(t){const i=new Map;for(const[o,n]of t??[]){const _=y(o,n);_.ok&&i.set(_.doc.id,_.doc)}return i}p(te,"parseMap");function Oe(t,i,o,n=null){L(i);const _=te(o),m=g(t,"SELECT * FROM objects WHERE type = 'document' AND owner = ? AND privacy = 'public' ORDER BY rowid").all(i.rowid),l=g(t,"SELECT rowid, rev_id, number, body_hash, author, rationale, created_at FROM revisions WHERE document = ? ORDER BY number, rev_id"),v=g(t,"SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rowid = rp.parent WHERE rp.child = ?"),r=g(t,`SELECT e.written_as, o.id FROM edges e JOIN objects o ON o.rowid = e.dst
2
- WHERE e.type = 'links-to' AND e.src = ? ORDER BY e.written_as, o.id`),a=new Map;for(const e of m){const d=C(t,e),c=new Map((_.get(e.id)?.revisions??[]).map(s=>[s.rev_id,s])),h=new Set(D(t,e).map(s=>s.rev_id)),w=r.all(e.rowid).map(s=>({written_as:s.written_as??"",dst:s.id})),R=l.all(e.rowid).map(s=>c.get(s.rev_id)??{rev_id:s.rev_id,number:s.number,parents:v.all(s.rowid).map(O=>O.rev_id),body:W(s.body_hash),body_hash:s.body_hash,author:s.author===null?null:N(t,s.author)?.id??null,rationale:s.rationale,created_at:s.created_at,links:h.has(s.rev_id)?w:[]});if(R.length===0)continue;const E=X(t,e).map(s=>({position:s.position,on:s.on,match:s.match??null,match_frontmatter:s.matchFrontmatter??null,if:s.if??null,deliver:s.deliver})),A={id:e.id,name:e.name,kind:e.kind??"document",privacy:"public",preview:e.preview,summary:d.summary,why_it_exists:d.why_it_exists,unlisted:d.unlisted,lint_ignore:d.lint_ignore,extensions:d.extensions,created_at:e.created_at,deleted_at:e.deleted_at,rules:E,revisions:R};a.set(b(e.id),$(A))}for(const e of ne(o,n)){const d=o.get(e),c=a.get(e);if(c===void 0){a.set(e,d);continue}const h=y(e,d),w=y(e,c);if(!h.ok){a.set(e,d);continue}if(!w.ok)continue;const R=n?.has(e)?y(e,n.get(e)):null,E=ee(R?.ok?R.doc:null,w.doc,h.doc);E&&a.set(e,$(E))}return a}p(Oe,"exportRepo");function ne(t,i){return[...t??[]].filter(([o,n])=>i?.get(o)!==n).map(([o])=>o)}p(ne,"pendingPaths");function ie(t){return[...t].sort((i,o)=>i.position-o.position).map(i=>({on:i.on,deliver:i.deliver,...i.match!==null&&i.match!==void 0?{match:i.match}:{},...i.match_frontmatter!==null&&i.match_frontmatter!==void 0?{matchFrontmatter:i.match_frontmatter}:{},...i.if!==null&&i.if!==void 0?{if:i.if}:{}}))}p(ie,"toRuleSpecs");const oe=p((t,i)=>JSON.stringify(t??null)===JSON.stringify(i??null),"same");function j(t,i){const o={},n=p(_=>!t||!oe(t[_],i[_]),"differs");return n("preview")&&(o.preview=i.preview),n("summary")&&(o.summary=i.summary),n("why_it_exists")&&(o.whyItExists=i.why_it_exists),n("unlisted")&&(o.unlisted=i.unlisted),n("lint_ignore")&&(o.lintIgnore=i.lint_ignore),n("extensions")&&(o.extensions=i.extensions),n("rules")&&(o.rules=ie(i.rules)),o}p(j,"changedFields");let re=0;function B(t,i){const o=`repo_sync_import_${++re}`;t.exec(`SAVEPOINT ${o}`);try{const n=i();return t.exec(`RELEASE ${o}`),n}catch(n){throw t.exec(`ROLLBACK TO ${o}`),t.exec(`RELEASE ${o}`),n}}p(B,"atomic");function Se(t,i,o,n,_){L(i);const m={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]},l=[];for(const[r,a]of n){if(o.get(r)===a)continue;const e=y(r,a);if(!e.ok){m.refused.push({path:r,reason:e.reason});continue}const d=o.has(r)?y(r,o.get(r)):null;l.push({path:r,prior:d?.ok?d.doc:null,doc:e.doc})}for(const[r,a]of o){if(n.has(r))continue;const e=y(r,a);e.ok&&l.push({path:r,prior:e.doc,doc:null,priorId:e.doc.id})}for(const r of l)for(const a of r.doc?.revisions??[])P(a.body);const v=[];return B(t,()=>{let r=l;for(;;){const a=[];for(const e of r){const d={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]};try{const c=[];B(t,()=>ue(t,i,e.prior,e.doc,e.priorId??e.doc.id,d,_,c)),v.push(...c),m.created+=d.created,m.revisions+=d.revisions,m.deleted+=d.deleted,m.needsMerge.push(...d.needsMerge)}catch(c){le(c)?a.push({w:e,error:c}):m.refused.push({path:e.path,reason:c.message})}}if(a.length===0)break;if(a.length===r.length){for(const e of a)m.refused.push({path:e.w.path,reason:e.error.message});break}r=a.map(e=>e.w)}se(t,n,new Set(v),new Set(l.map(a=>a.path)))}),m}p(Se,"importTree");function se(t,i,o,n){if(o.size===0)return;const _=g(t,"INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('links-to', ?, ?, ?, ?)"),m=new Date().toISOString();for(const[l,v]of i){if(!n.has(l)&&!de(v,o))continue;const r=y(l,v);if(!r.ok||r.doc.deleted_at)continue;const a=x(t,r.doc.id);if(!a||a.type!=="document"||a.deleted_at)continue;const e=D(t,a)[0],d=r.doc.revisions.find(c=>c.rev_id===e?.rev_id)?.links??[];for(const c of d){const h=x(t,c.dst);h&&h.rowid!==a.rowid&&_.run(a.rowid,h.rowid,c.written_as,m)}}}p(se,"completeLinks");const ae=/"dst":\s*"((?:[^"\\]|\\.)*)"/g;function de(t,i){for(const o of t.matchAll(ae))if(i.has(ce(o[1])))return!0;return!1}p(de,"namesArrived");function ce(t){if(!t.includes("\\"))return t;try{return JSON.parse(`"${t}"`)}catch{return t}}p(ce,"decodeJsonString");function le(t){return t instanceof F&&t.code==="conflict"&&t.details?.holder!==void 0}p(le,"isNameConflict");function ue(t,i,o,n,_,m,l,v){const r=x(t,_);if(r&&(r.type!=="document"||r.owner!==i.rowid))throw new Error(`id ${_} is held by ${r.type} ${r.name} outside ${i.name}`);if(!n){r&&!r.deleted_at&&(M(t,null,r,l),m.deleted++);return}const a=g(t,"SELECT count(*) AS n FROM revisions WHERE document = ?");let e,d=!1,c=!1,h=0,w=0;if(r){e=r,h=C(t,e).revision,e.created_at!==n.created_at&&(g(t,"UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.created_at,e.rowid),e=N(t,e.rowid));const u=n.kind;(o?o.kind!==u:e.kind!==u)&&Q(t,e,u),c=!!e.deleted_at&&n.deleted_at===null&&(o===null||o.deleted_at!=null);let f=j(c?null:o,n);if(n.deleted_at&&e.deleted_at){const{rules:k,...S}=f;f=S}c&&(e=G(t,e,n.name,l),v?.push(e.id)),Object.keys(f).length>0&&(e=q(t,null,e,f)),n.name!==e.name&&!e.deleted_at&&(e=V(t,null,e,{name:n.name},l))}else{const f=n.revisions.filter(k=>k.parents.length===0).sort((k,S)=>k.number-S.number||k.rev_id.localeCompare(S.rev_id))[0];if(!f)throw new Error(`${n.name}: no root revision`);e=z(t,{id:n.id,owner:i,name:n.name,kind:n.kind,preview:n.preview,privacy:"public",...j(null,n),revisions:[{rev_id:f.rev_id,body_hash:f.body_hash,author:null,rationale:f.rationale,created_at:f.created_at}]},l),e.created_at!==n.created_at&&(g(t,"UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.created_at,e.rowid),e=N(t,e.rowid)),d=!0,v?.push(e.id),w=1}const R=a.get(e.rowid).n,{headCount:E}=K(t,e,n.revisions.map(u=>({rev_id:u.rev_id,parents:u.parents,body_hash:u.body_hash,rationale:u.rationale,created_at:u.created_at})));w+=a.get(e.rowid).n-R,m.revisions+=w;const s=D(t,e)[0],O=new Map(n.revisions.map(u=>[u.rev_id,u]));if(w>0||c){const u=(O.get(s.rev_id)?.links??[]).map(f=>({written_as:f.written_as,dst:x(t,f.dst)})).filter(f=>f.dst!==null);Y(t,J(t,e,u),l),U(t,e,[])}if(E>1&&m.needsMerge.push(e.id),n.deleted_at&&!e.deleted_at){M(t,null,e,l,n.deleted_at),m.deleted++;return}if(n.deleted_at&&e.deleted_at&&e.deleted_at!==n.deleted_at&&g(t,"UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(n.deleted_at,e.rowid),d){m.created++,T(t,{event:"created",object:e,actor:null,attrs:{revision:s.number},pointer:s.rev_id},l);return}if(c){m.created++,T(t,{event:"created",object:e,actor:null,attrs:{revision:s.number},pointer:s.rev_id},l);return}if(w===0)return;const I=n.revisions.filter(u=>!o?.revisions.some(f=>f.rev_id===u.rev_id)).sort((u,f)=>f.number-u.number||f.created_at.localeCompare(u.created_at))[0]??O.get(s.rev_id);T(t,{event:"edited",object:e,actor:null,pointer:s.rev_id,attrs:{revision:s.number,from_revision:h,rationale:I?.rationale??null,author:I?.author??null,heads:E,needs_merge:E>1}},l)}p(ue,"importOne");export{Oe as exportRepo,Se as importTree,de as namesArrived,ne as pendingPaths};
1
+ var $=Object.defineProperty;var w=(t,i)=>$(t,"name",{value:i,configurable:!0});import{get as B,put as J}from"../bodies.js";import{setLinks as P,setUnresolved as U}from"../edges.js";import{collectUnlinked as Y,deleteDocument as I,documentRecord as C,heads as x,importDocument as z,insertImportedRevisions as G,moveDocument as K,restoreDocument as V,setDocumentRecord as b}from"../documents.js";import{CrtrError as q}from"../../errors.js";import{publish as D}from"../events.js";import{getById as S,getByRowid as M,setObjectKind as F}from"../objects.js";import{rulesOf as Q}from"../rules.js";import{SPACES as X}from"../spaces/index.js";import{docPath as Z,mergeDoc as ee,parseDoc as g,serializeDoc as A}from"./ref-format.js";import{withCanvasWrite as W}from"../../canvas/db.js";import{mapAsync as j}from"../../async-array.js";function H(t){const i=X[t.type];if(t.owner!==null||!i||i.sync!=="repo-ref")throw new Error(`${t.type} ${t.id} is not a space that syncs through a repo ref`)}w(H,"assertRepoRefSpace");function te(t){const i=new Map;for(const[r,n]of t??[]){const m=g(r,n);m.ok&&i.set(m.doc.id,m.doc)}return i}w(te,"parseMap");async function Oe(t,i,r,n=null){H(i);const m=te(r),p=await t.prepare("SELECT * FROM objects WHERE type = 'document' AND owner = ? AND privacy = 'public' ORDER BY rowid").all(i.rowid),l=t.prepare("SELECT rowid, rev_id, number, body_hash, author, rationale, created_at FROM revisions WHERE document = ? ORDER BY number, rev_id"),h=t.prepare("SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rowid = rp.parent WHERE rp.child = ?"),o=t.prepare(`SELECT e.written_as, o.id FROM edges e JOIN objects o ON o.rowid = e.dst
2
+ WHERE e.type = 'links-to' AND e.src = ? ORDER BY e.written_as, o.id`),s=new Map;for(const e of p){const d=await C(t,e),c=new Map((m.get(e.id)?.revisions??[]).map(a=>[a.rev_id,a])),_=new Set((await x(t,e)).map(a=>a.rev_id)),v=(await o.all(e.rowid)).map(a=>({written_as:a.written_as??"",dst:a.id})),E=await j(await l.all(e.rowid),async a=>c.get(a.rev_id)??{rev_id:a.rev_id,number:a.number,parents:(await h.all(a.rowid)).map(R=>R.rev_id),body:B(a.body_hash),body_hash:a.body_hash,author:a.author===null?null:(await M(t,a.author))?.id??null,rationale:a.rationale,created_at:a.created_at,links:_.has(a.rev_id)?v:[]});if(E.length===0)continue;const y=(await Q(t,e)).map(a=>({position:a.position,on:a.on,match:a.match??null,match_frontmatter:a.matchFrontmatter??null,if:a.if??null,deliver:a.deliver})),N={id:e.id,name:e.name,kind:e.kind??"document",privacy:"public",preview:e.preview,summary:d.summary,why_it_exists:d.why_it_exists,unlisted:d.unlisted,lint_ignore:d.lint_ignore,extensions:d.extensions,created_at:e.created_at,deleted_at:e.deleted_at,rules:y,revisions:E};s.set(Z(e.id),A(N))}for(const e of ne(r,n)){const d=r.get(e),c=s.get(e);if(c===void 0){s.set(e,d);continue}const _=g(e,d),v=g(e,c);if(!_.ok){s.set(e,d);continue}if(!v.ok)continue;const E=n?.has(e)?g(e,n.get(e)):null,y=ee(E?.ok?E.doc:null,v.doc,_.doc);y&&s.set(e,A(y))}return s}w(Oe,"exportRepo");function ne(t,i){return[...t??[]].filter(([r,n])=>i?.get(r)!==n).map(([r])=>r)}w(ne,"pendingPaths");function ie(t){return[...t].sort((i,r)=>i.position-r.position).map(i=>({on:i.on,deliver:i.deliver,...i.match!==null&&i.match!==void 0?{match:i.match}:{},...i.match_frontmatter!==null&&i.match_frontmatter!==void 0?{matchFrontmatter:i.match_frontmatter}:{},...i.if!==null&&i.if!==void 0?{if:i.if}:{}}))}w(ie,"toRuleSpecs");const re=w((t,i)=>JSON.stringify(t??null)===JSON.stringify(i??null),"same");function L(t,i){const r={},n=w(m=>!t||!re(t[m],i[m]),"differs");return n("preview")&&(r.preview=i.preview),n("summary")&&(r.summary=i.summary),n("why_it_exists")&&(r.whyItExists=i.why_it_exists),n("unlisted")&&(r.unlisted=i.unlisted),n("lint_ignore")&&(r.lintIgnore=i.lint_ignore),n("extensions")&&(r.extensions=i.extensions),n("rules")&&(r.rules=ie(i.rules)),r}w(L,"changedFields");async function Se(t,i,r,n,m){H(i);const p={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]},l=[];for(const[o,s]of n){if(r.get(o)===s)continue;const e=g(o,s);if(!e.ok){p.refused.push({path:o,reason:e.reason});continue}const d=r.has(o)?g(o,r.get(o)):null;l.push({path:o,prior:d?.ok?d.doc:null,doc:e.doc})}for(const[o,s]of r){if(n.has(o))continue;const e=g(o,s);e.ok&&l.push({path:o,prior:e.doc,doc:null,priorId:e.doc.id})}for(const o of l)for(const s of o.doc?.revisions??[])J(s.body);const h=[];return await W(async()=>{let o=l;for(;;){const s=[];for(const e of o){const d={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]};try{const c=[];await W(async()=>await le(t,i,e.prior,e.doc,e.priorId??e.doc.id,d,m,c),{savepoint:!0}),h.push(...c),p.created+=d.created,p.revisions+=d.revisions,p.deleted+=d.deleted,p.needsMerge.push(...d.needsMerge)}catch(c){ce(c)?s.push({w:e,error:c}):p.refused.push({path:e.path,reason:c.message})}}if(s.length===0)break;if(s.length===o.length){for(const e of s)p.refused.push({path:e.w.path,reason:e.error.message});break}o=s.map(e=>e.w)}await oe(t,n,new Set(h),new Set(l.map(s=>s.path)))},{savepoint:!0}),p}w(Se,"importTree");async function oe(t,i,r,n){if(r.size===0)return;const m=t.prepare("INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('links-to', ?, ?, ?, ?)"),p=new Date().toISOString();for(const[l,h]of i){if(!n.has(l)&&!se(h,r))continue;const o=g(l,h);if(!o.ok||o.doc.deleted_at)continue;const s=await S(t,o.doc.id);if(!s||s.type!=="document"||s.deleted_at)continue;const e=(await x(t,s))[0],d=o.doc.revisions.find(c=>c.rev_id===e?.rev_id)?.links??[];for(const c of d){const _=await S(t,c.dst);_&&_.rowid!==s.rowid&&await m.run(s.rowid,_.rowid,c.written_as,p)}}}w(oe,"completeLinks");const ae=/"dst":\s*"((?:[^"\\]|\\.)*)"/g;function se(t,i){for(const r of t.matchAll(ae))if(i.has(de(r[1])))return!0;return!1}w(se,"namesArrived");function de(t){if(!t.includes("\\"))return t;try{return JSON.parse(`"${t}"`)}catch{return t}}w(de,"decodeJsonString");function ce(t){return t instanceof q&&t.code==="conflict"&&t.details?.holder!==void 0}w(ce,"isNameConflict");async function le(t,i,r,n,m,p,l,h){const o=await S(t,m);if(o&&(o.type!=="document"||o.owner!==i.rowid))throw new Error(`id ${m} is held by ${o.type} ${o.name} outside ${i.name}`);if(!n){o&&!o.deleted_at&&(await I(t,null,o,l),p.deleted++);return}const s=t.prepare("SELECT count(*) AS n FROM revisions WHERE document = ?");let e,d=!1,c=!1,_=0,v=0;if(o){e=o,_=(await C(t,e)).revision,e.created_at!==n.created_at&&(await t.prepare("UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.created_at,e.rowid),e=await M(t,e.rowid));const u=n.kind;(r?r.kind!==u:e.kind!==u)&&await F(t,e,u),c=!!e.deleted_at&&n.deleted_at===null&&(r===null||r.deleted_at!=null);let f=L(c?null:r,n);if(n.deleted_at&&e.deleted_at){const{rules:k,...O}=f;f=O}c&&(e=await V(t,e,n.name,l),h?.push(e.id)),Object.keys(f).length>0&&(e=await b(t,null,e,f)),n.name!==e.name&&!e.deleted_at&&(e=await K(t,null,e,{name:n.name},l))}else{const f=n.revisions.filter(k=>k.parents.length===0).sort((k,O)=>k.number-O.number||k.rev_id.localeCompare(O.rev_id))[0];if(!f)throw new Error(`${n.name}: no root revision`);e=await z(t,{id:n.id,owner:i,name:n.name,kind:n.kind,preview:n.preview,privacy:"public",...L(null,n),revisions:[{rev_id:f.rev_id,body_hash:f.body_hash,author:null,rationale:f.rationale,created_at:f.created_at}]},l),e.created_at!==n.created_at&&(await t.prepare("UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.created_at,e.rowid),e=await M(t,e.rowid)),d=!0,h?.push(e.id),v=1}const E=(await s.get(e.rowid)).n,{headCount:y}=await G(t,e,n.revisions.map(u=>({rev_id:u.rev_id,parents:u.parents,body_hash:u.body_hash,rationale:u.rationale,created_at:u.created_at})));v+=(await s.get(e.rowid)).n-E,p.revisions+=v;const a=(await x(t,e))[0],R=new Map(n.revisions.map(u=>[u.rev_id,u]));if(v>0||c){const u=(await j(R.get(a.rev_id)?.links??[],async f=>({written_as:f.written_as,dst:await S(t,f.dst)}))).filter(f=>f.dst!==null);await Y(t,await P(t,e,u),l),await U(t,e,[])}if(y>1&&p.needsMerge.push(e.id),n.deleted_at&&!e.deleted_at){await I(t,null,e,l,n.deleted_at),p.deleted++;return}if(n.deleted_at&&e.deleted_at&&e.deleted_at!==n.deleted_at&&await t.prepare("UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(n.deleted_at,e.rowid),d){p.created++,await D(t,{event:"created",object:e,actor:null,attrs:{revision:a.number},pointer:a.rev_id},l);return}if(c){p.created++,await D(t,{event:"created",object:e,actor:null,attrs:{revision:a.number},pointer:a.rev_id},l);return}if(v===0)return;const T=n.revisions.filter(u=>!r?.revisions.some(f=>f.rev_id===u.rev_id)).sort((u,f)=>f.number-u.number||f.created_at.localeCompare(u.created_at))[0]??R.get(a.rev_id);await D(t,{event:"edited",object:e,actor:null,pointer:a.rev_id,attrs:{revision:a.number,from_revision:_,rationale:T?.rationale??null,author:T?.author??null,heads:y,needs_merge:y>1}},l)}w(le,"importOne");export{Oe as exportRepo,Se as importTree,se as namesArrived,ne as pendingPaths};
@@ -1,7 +1,6 @@
1
- /** Repo objects on the canvas: one per repo identity, handle chosen once. */
2
- import type { DatabaseSync } from 'node:sqlite';
3
1
  import type { Checkout, ObjectRow } from '../types.js';
4
2
  import { handleHint } from './identity.js';
3
+ import type { CanvasDb } from '../../canvas/db.js';
5
4
  export { handleHint };
6
5
  export interface RepoIdentity {
7
6
  scheme: 'git' | 'local-path';
@@ -10,10 +9,13 @@ export interface RepoIdentity {
10
9
  }
11
10
  /** The repo object for an identity, created on first sight. A handle already
12
11
  * held by another repo gets `-2`, `-3`, … appended. */
13
- export declare function ensureRepo(db: DatabaseSync, id: RepoIdentity, handle?: string): ObjectRow;
12
+ export declare function ensureRepo(db: CanvasDb, id: RepoIdentity, handle?: string): Promise<ObjectRow>;
14
13
  /** Repos enclosing `cwd`, nearest first: every enclosing git checkout (created
15
14
  * on first sight) and every existing local-path repo whose path is `cwd` or
16
15
  * an ancestor of it. A non-git folder is never created here. */
17
- export declare function reposForCwd(db: DatabaseSync, cwd: string): ObjectRow[];
16
+ export declare function reposForCwd(db: CanvasDb, cwd: string): Promise<ObjectRow[]>;
17
+ /** Run the git lookups for `cwd`'s checkouts now, so a later `checkoutsForCwd` inside a canvas write hits the identity
18
+ * cache instead of spawning git while every other db caller waits on the write lock. */
19
+ export declare function warmCheckoutIdentities(cwd: string): void;
18
20
  /** `reposForCwd` with the directory each repo is checked out at. */
19
- export declare function checkoutsForCwd(db: DatabaseSync, cwd: string): Checkout[];
21
+ export declare function checkoutsForCwd(db: CanvasDb, cwd: string): Promise<Checkout[]>;
@@ -1,3 +1,3 @@
1
- var h=Object.defineProperty;var s=(t,e)=>h(t,"name",{value:e,configurable:!0});import{prepared as a}from"../../sqlite-statements.js";import{resolve as d,sep as f}from"node:path";import{CrtrError as m}from"../../errors.js";import{realpathOrSelf as l}from"../../fs-utils.js";import{ExitCode as u}from"../../../types.js";import{ensureOwner as E}from"../objects.js";import{checkoutChain as w,handleHint as N}from"./identity.js";function x(t,e,r){return a(t,`SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object
2
- WHERE o.type = 'repo' AND i.scheme = ? AND i.external_id = ?`).get(e,r)??null}s(x,"existingRepo");function O(t,e,r){const n=x(t,e.scheme,e.externalId);if(n)return n;const p=r??e.handleHint,c=a(t,"SELECT 1 FROM objects WHERE name = ? AND type = 'repo' AND home_machine IS NULL");let o=p;for(let i=2;c.get(o);i++)o=`${p}-${i}`;return E(t,"repo",e.scheme,e.externalId,o)}s(O,"ensureRepo");function F(t,e){return R(t,e).map(r=>r.repo)}s(F,"reposForCwd");function R(t,e){const r=l(d(e)),n=[];for(const o of w(r)){if(!o.ok)throw new m("git-lookup-failed",`cannot identify the repo at ${o.dir}: ${o.reason}`,u.GENERAL,{dir:o.dir});n.push({root:o.root,repo:O(t,o)})}const p=a(t,`SELECT o.*, i.external_id AS path FROM identities i JOIN objects o ON o.rowid = i.object
3
- WHERE o.type = 'repo' AND i.scheme = 'local-path'`).all();for(const{path:o,...i}of p)(r===o||r.startsWith(o.endsWith(f)?o:o+f))&&n.push({root:o,repo:i});n.sort((o,i)=>i.root.length-o.root.length);const c=new Set;return n.filter(({repo:o})=>!c.has(o.rowid)&&(c.add(o.rowid),!0))}s(R,"checkoutsForCwd");export{R as checkoutsForCwd,O as ensureRepo,N as handleHint,F as reposForCwd};
1
+ var l=Object.defineProperty;var a=(t,o)=>l(t,"name",{value:o,configurable:!0});import{resolve as c,sep as f}from"node:path";import{CrtrError as u}from"../../errors.js";import{realpathOrSelf as h}from"../../fs-utils.js";import{ExitCode as m}from"../../../types.js";import{ensureOwner as w}from"../objects.js";import{checkoutChain as d,handleHint as E}from"./identity.js";async function x(t,o,r){return await t.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object
2
+ WHERE o.type = 'repo' AND i.scheme = ? AND i.external_id = ?`).get(o,r)??null}a(x,"existingRepo");async function N(t,o,r){const n=await x(t,o.scheme,o.externalId);if(n)return n;const s=r??o.handleHint,p=t.prepare("SELECT 1 FROM objects WHERE name = ? AND type = 'repo' AND home_machine IS NULL");let e=s;for(let i=2;await p.get(e);i++)e=`${s}-${i}`;return await w(t,"repo",o.scheme,o.externalId,e)}a(N,"ensureRepo");async function I(t,o){return(await C(t,o)).map(r=>r.repo)}a(I,"reposForCwd");function L(t){d(h(c(t)))}a(L,"warmCheckoutIdentities");async function C(t,o){const r=h(c(o)),n=[];for(const e of d(r)){if(!e.ok)throw new u("git-lookup-failed",`cannot identify the repo at ${e.dir}: ${e.reason}`,m.GENERAL,{dir:e.dir});n.push({root:e.root,repo:await N(t,e)})}const s=await t.prepare(`SELECT o.*, i.external_id AS path FROM identities i JOIN objects o ON o.rowid = i.object
3
+ WHERE o.type = 'repo' AND i.scheme = 'local-path'`).all();for(const{path:e,...i}of s)(r===e||r.startsWith(e.endsWith(f)?e:e+f))&&n.push({root:e,repo:i});n.sort((e,i)=>i.root.length-e.root.length);const p=new Set;return n.filter(({repo:e})=>!p.has(e.rowid)&&(p.add(e.rowid),!0))}a(C,"checkoutsForCwd");export{C as checkoutsForCwd,N as ensureRepo,E as handleHint,I as reposForCwd,L as warmCheckoutIdentities};
@@ -1,10 +1,7 @@
1
- /** The repo-sync engine in crtrd: per repo at most one sync running and one queued. No timer and
2
- * no retry loop — the next trigger is the retry. A failed sync keeps the local mirror commit and
3
- * every canvas.db revision; the next run sends them. Every outcome is written as an event. */
4
- import type { DatabaseSync } from 'node:sqlite';
5
1
  import type { DetachedWorkLifecycle } from '../../../daemon/reconcilers/broker-supervision.js';
6
2
  import type { ObjectRow } from '../types.js';
7
3
  import { type ImportResult } from './exchange.js';
4
+ import { type CanvasDb } from '../../canvas/db.js';
8
5
  export declare const FIRST_FETCH_WAIT_MS = 20000;
9
6
  export type SyncStep = 'export' | 'fetch' | 'merge' | 'import' | 'push';
10
7
  export type SyncOutcome = {
@@ -17,7 +14,7 @@ export type SyncOutcome = {
17
14
  reason: string;
18
15
  };
19
16
  /** Called once by crtrd. Until then triggers are refused loudly. */
20
- export declare function startRepoSync(lifecycle: DetachedWorkLifecycle, db: () => DatabaseSync): void;
17
+ export declare function startRepoSync(lifecycle: DetachedWorkLifecycle, db: () => Promise<CanvasDb>): Promise<void>;
21
18
  /**
22
19
  * A node starts working in `cwd`, enclosed by `repos`. For each syncing repo: when no fetch has
23
20
  * ever succeeded on this machine and none was attempted in this daemon's lifetime, wait for its
@@ -34,7 +31,7 @@ export declare function noteNodeBooting(nodeId: string): Promise<void>;
34
31
  /** A repo-owned document changed (write, edit, move at either end, delete). `dirs`, the caller's
35
32
  * cwd and the checkouts it reaches, record the fetch URL of any that is a checkout of the repo; the
36
33
  * sync itself never depends on where the writer runs. */
37
- export declare function noteRepoDocumentsChanged(repo: ObjectRow, dirs?: readonly string[]): void;
34
+ export declare function noteRepoDocumentsChanged(repo: ObjectRow, dirs?: readonly string[]): Promise<void>;
38
35
  /**
39
36
  * One sync: export canvas.db to a local commit, fetch the remote ref, fast-forward or merge,
40
37
  * import the merged tree into canvas.db, push (never forced). A rejected push fetches again,
@@ -1,2 +1,2 @@
1
- var B=Object.defineProperty;var c=(t,r)=>B(t,"name",{value:r,configurable:!0});import{prepared as v}from"../../sqlite-statements.js";import{existsSync as D}from"node:fs";import{readFile as K,writeFile as q}from"node:fs/promises";import{join as S}from"node:path";import{emitEvent as G}from"../../events/emit.js";import{exportRepo as J,importTree as Q,pendingPaths as V}from"./exchange.js";import{checkoutChain as X}from"./identity.js";import{checkoutsForCwd as Y,reposForCwd as Z}from"./repos.js";import{commitTree as k,fetchDocs as ee,FIRST_FETCH_MARKER as te,isAncestor as L,mergeBase as re,openMirror as _,pushDocs as ne,readTree as p,remoteDocsTip as oe,resolveRef as h,setRef as y}from"./mirror.js";import{mergeTrees as se}from"./ref-format.js";const ie=2e4,A=3,H="remote-url",m="refs/crtr/docs",ae="refs/crtr/remote-docs",g="refs/crtr/imported";function T(t){try{G(t)}catch{}}c(T,"emitEvent");let M=null;const b=new Map,O=new Set;function Se(t,r){M={lifecycle:t,db:r}}c(Se,"startRepoSync");function P(t,r){return r.type!=="repo"?!1:v(t,"SELECT 1 FROM identities WHERE object = ? AND scheme = 'git'").get(r.rowid)!==void 0}c(P,"gitScheme");async function U(t,r){const e=new Map;for(const f of r)for(const o of X(f))o.ok&&o.scheme==="git"&&e.set(o.externalId,o.remoteUrl);if(e.size===0)return;const a=M.db(),n=v(a,"SELECT external_id FROM identities WHERE object = ? AND scheme = 'git'");for(const f of t){const o=n.get(f.rowid),i=o&&e.get(o.external_id);if(!i)continue;const s=await _(f.id);await q(S(s.dir,H),`${i}
2
- `)}}c(U,"recordRemoteUrls");async function ce(t,r){const a=E().db(),n=t.filter(s=>P(a,s));if(n.length===0)return;await U(n,[r]);const f=[];for(const s of n){const l=!O.has(s.id)&&!D(S((await _(s.id)).dir,te)),u=R(s);l&&u&&f.push(u)}if(f.length===0)return;let o;const i=new Promise(s=>{o=setTimeout(s,ie)});await Promise.race([Promise.all(f),i]),clearTimeout(o)}c(ce,"noteNodeWorking");async function ke(t){try{const r=E().db(),e=v(r,"SELECT cwd FROM nodes WHERE node_id = ?").get(t);if(!e)return;const a=fe(r,()=>Z(r,e.cwd));a.length>0&&await ce(a,e.cwd)}catch(r){T({level:"warn",event:"repo_sync.failed",outcome:"failed",error:r,node_id:t,fields:{step:"fetch",reason:`the boot trigger failed: ${r instanceof Error?r.message:String(r)}`}})}}c(ke,"noteNodeBooting");function fe(t,r){if(t.isTransaction)return r();t.exec("BEGIN IMMEDIATE");try{const e=r();return t.exec("COMMIT"),e}catch(e){throw t.exec("ROLLBACK"),e}}c(fe,"inWrite");function _e(t,r=[]){const e=E();if(!P(e.db(),t))return;if(r.length===0){R(t);return}const a=U([t],r).then(()=>{R(t)},n=>{T({level:"error",event:"repo_sync.failed",error:n,fields:{repo:t.name,step:"fetch",reason:"recording the remote URL failed"}})});e.lifecycle.registerDetached(a)}c(_e,"noteRepoDocumentsChanged");function E(){if(!M)throw new Error("repo sync is not started: crtrd must call startRepoSync first");return M}c(E,"requireEngine");function R(t){const r=E(),e=b.get(t.id)??{running:null,again:!1};if(b.set(t.id,e),e.running)return e.again=!0,e.running.then(()=>b.get(t.id)?.running??null).then(n=>n??{ok:!0,pushed:!1,imported:$()});if(!r.lifecycle.acceptsDetachedWork())return null;O.add(t.id);const a=de(t).then(n=>(W(t,n),n),n=>{const f={ok:!1,step:"export",reason:n instanceof Error?n.message:String(n)};return W(t,f),f}).finally(()=>{e.running=null,e.again&&(e.again=!1,R(t))});return e.running=a,r.lifecycle.registerDetached(a.then(()=>{})),a}c(R,"schedule");function W(t,r){if(r.ok){const e=r.imported;T({level:"info",event:"repo_sync.completed",outcome:"succeeded",fields:{repo:t.name,pushed:r.pushed,created:e.created,revisions:e.revisions,deleted:e.deleted,needs_merge:e.needsMerge,refused:e.refused}})}else T({level:"warn",event:"repo_sync.failed",outcome:"failed",fields:{repo:t.name,step:r.step,reason:r.reason}})}c(W,"report");function $(){return{created:0,revisions:0,deleted:0,needsMerge:[],refused:[]}}c($,"emptyImport");class x extends Error{static{c(this,"StepError")}step;constructor(r,e){super(e),this.step=r}}async function C(t,r){try{return await r()}catch(e){throw e instanceof x?e:new x(t,e instanceof Error?e.message:String(e))}}c(C,"step");async function de(t){const r=E();try{const e=await _(t.id),a=await ue(e);if(a===null)return{ok:!1,step:"fetch",reason:`no checkout of ${t.name} with an origin remote has been seen by this runtime`};let n=$();const f=c(()=>C("import",async()=>{const o=await h(e,m),i=await h(e,g);if(o===null||i===o)return;const s=i?await p(e,g):new Map,l=r.db(),u=await p(e,m),d=Q(l,t,s,u,w=>Y(l,w));n={created:n.created+d.created,revisions:n.revisions+d.revisions,deleted:n.deleted+d.deleted,needsMerge:[...new Set([...n.needsMerge,...d.needsMerge])],refused:[...n.refused,...d.refused]},await j(e,o,u,s,new Set(d.refused.map(w=>w.path)),i)}),"importLocal");await f(),await C("export",async()=>{const o=await h(e,m),i=o?await p(e,m):null,s=await h(e,g),l=s?await p(e,g):null,u=J(r.db(),t,i,l);if(o?z(i,u):u.size===0)return;const d=await k(e,u,o?[o]:[],`crtr: export ${t.name}`);await y(e,m,d,o),await j(e,d,u,l??new Map,new Set(V(i,l)),s)});for(let o=1;;o++){const i=await oe(e,a);if(!i.ok)return{ok:!1,step:"fetch",reason:i.reason};let s=await h(e,m);if(i.value!==null&&!(s&&await le(e,i.value)&&await L(e,i.value,s))){const u=await ee(e,a);if(!u.ok)return{ok:!1,step:"fetch",reason:u.reason};const d=u.value;s=await C("merge",async()=>{if(!s||await L(e,s,d))return await y(e,m,d,s),d;const w=await re(e,s,d),F=se(w?await p(e,w):new Map,await p(e,m),await p(e,ae));for(const N of F.refused)n.refused.push(N);const I=await k(e,F.tree,[s,d],`crtr: merge ${t.name}`);return await y(e,m,I,s),I})}if(await f(),s===null||s===i.value)return{ok:!0,pushed:!1,imported:n};const l=await ne(e,a,s);if(l.ok)return{ok:!0,pushed:!0,imported:n};if(l.reason!=="rejected")return{ok:!1,step:"push",reason:l.reason};if(o>=A)return{ok:!1,step:"push",reason:`push rejected ${A} times`}}}catch(e){if(e instanceof x)return{ok:!1,step:e.step,reason:e.message};throw e}}c(de,"syncRepo");async function j(t,r,e,a,n,f){if(n.size===0){await y(t,g,r,f);return}const o=new Map(e);for(const i of n)a.has(i)?o.set(i,a.get(i)):o.delete(i);f!==null&&z(a,o)||await y(t,g,await k(t,o,[],"crtr: imported baseline (some files pending)"),f)}c(j,"advanceImported");async function ue(t){const r=S(t.dir,H);return D(r)&&(await K(r,"utf8")).trim()||null}c(ue,"readUrl");async function le(t,r){return await h(t,r)!==null}c(le,"hasCommit");function z(t,r){if(t.size!==r.size)return!1;for(const[e,a]of t)if(r.get(e)!==a)return!1;return!0}c(z,"sameTree");export{ie as FIRST_FETCH_WAIT_MS,ke as noteNodeBooting,ce as noteNodeWorking,_e as noteRepoDocumentsChanged,Se as startRepoSync,de as syncRepo};
1
+ var N=Object.defineProperty;var c=(t,n)=>N(t,"name",{value:n,configurable:!0});import{existsSync as D}from"node:fs";import{readFile as B,writeFile as q}from"node:fs/promises";import{join as R}from"node:path";import{emitEvent as K}from"../../events/emit.js";import{exportRepo as G,importTree as J,pendingPaths as Q}from"./exchange.js";import{checkoutChain as V}from"./identity.js";import{checkoutsForCwd as X,reposForCwd as Y,warmCheckoutIdentities as Z}from"./repos.js";import{commitTree as S,fetchDocs as ee,FIRST_FETCH_MARKER as te,isAncestor as I,mergeBase as ne,openMirror as b,pushDocs as re,readTree as m,remoteDocsTip as ae,resolveRef as h,setRef as y}from"./mirror.js";import{mergeTrees as ie}from"./ref-format.js";import{withCanvasWrite as se}from"../../canvas/db.js";import{filterAsync as oe}from"../../async-array.js";const ce=2e4,L=3,A="remote-url",w="refs/crtr/docs",fe="refs/crtr/remote-docs",g="refs/crtr/imported";function v(t){try{K(t)}catch{}}c(v,"emitEvent");let T=null;const M=new Map,H=new Set;async function Me(t,n){T={lifecycle:t,db:n}}c(Me,"startRepoSync");async function P(t,n){return n.type!=="repo"?!1:await t.prepare("SELECT 1 FROM identities WHERE object = ? AND scheme = 'git'").get(n.rowid)!==void 0}c(P,"gitScheme");async function U(t,n){const e=new Map;for(const f of n)for(const a of V(f))a.ok&&a.scheme==="git"&&e.set(a.externalId,a.remoteUrl);if(e.size===0)return;const r=(await T.db()).prepare("SELECT external_id FROM identities WHERE object = ? AND scheme = 'git'");for(const f of t){const a=await r.get(f.rowid),s=a&&e.get(a.external_id);if(!s)continue;const i=await b(f.id);await q(R(i.dir,A),`${s}
2
+ `)}}c(U,"recordRemoteUrls");async function de(t,n){const o=await E().db(),r=await oe(t,async i=>await P(o,i));if(r.length===0)return;await U(r,[n]);const f=[];for(const i of r){const l=!H.has(i.id)&&!D(R((await b(i.id)).dir,te)),u=k(i);l&&u&&f.push(u)}if(f.length===0)return;let a;const s=new Promise(i=>{a=setTimeout(i,ce)});await Promise.race([Promise.all(f),s]),clearTimeout(a)}c(de,"noteNodeWorking");async function _e(t){try{const n=await E().db(),e=await n.prepare("SELECT cwd FROM nodes WHERE node_id = ?").get(t);if(!e)return;Z(e.cwd);const o=await se(async()=>await Y(n,e.cwd));o.length>0&&await de(o,e.cwd)}catch(n){v({level:"warn",event:"repo_sync.failed",outcome:"failed",error:n,node_id:t,fields:{step:"fetch",reason:`the boot trigger failed: ${n instanceof Error?n.message:String(n)}`}})}}c(_e,"noteNodeBooting");async function xe(t,n=[]){const e=E();if(!await P(await e.db(),t))return;if(n.length===0){k(t);return}const o=U([t],n).then(()=>{k(t)},r=>{v({level:"error",event:"repo_sync.failed",error:r,fields:{repo:t.name,step:"fetch",reason:"recording the remote URL failed"}})});e.lifecycle.registerDetached(o)}c(xe,"noteRepoDocumentsChanged");function E(){if(!T)throw new Error("repo sync is not started: crtrd must call startRepoSync first");return T}c(E,"requireEngine");function k(t){const n=E(),e=M.get(t.id)??{running:null,again:!1};if(M.set(t.id,e),e.running)return e.again=!0,e.running.then(()=>M.get(t.id)?.running??null).then(r=>r??{ok:!0,pushed:!1,imported:$()});if(!n.lifecycle.acceptsDetachedWork())return null;H.add(t.id);const o=ue(t).then(r=>(W(t,r),r),r=>{const f={ok:!1,step:"export",reason:r instanceof Error?r.message:String(r)};return W(t,f),f}).finally(()=>{e.running=null,e.again&&(e.again=!1,k(t))});return e.running=o,n.lifecycle.registerDetached(o.then(()=>{})),o}c(k,"schedule");function W(t,n){if(n.ok){const e=n.imported;v({level:"info",event:"repo_sync.completed",outcome:"succeeded",fields:{repo:t.name,pushed:n.pushed,created:e.created,revisions:e.revisions,deleted:e.deleted,needs_merge:e.needsMerge,refused:e.refused}})}else v({level:"warn",event:"repo_sync.failed",outcome:"failed",fields:{repo:t.name,step:n.step,reason:n.reason}})}c(W,"report");function $(){return{created:0,revisions:0,deleted:0,needsMerge:[],refused:[]}}c($,"emptyImport");class _ extends Error{static{c(this,"StepError")}step;constructor(n,e){super(e),this.step=n}}async function x(t,n){try{return await n()}catch(e){throw e instanceof _?e:new _(t,e instanceof Error?e.message:String(e))}}c(x,"step");async function ue(t){const n=E();try{const e=await b(t.id),o=await le(e);if(o===null)return{ok:!1,step:"fetch",reason:`no checkout of ${t.name} with an origin remote has been seen by this runtime`};let r=$();const f=c(()=>x("import",async()=>{const a=await h(e,w),s=await h(e,g);if(a===null||s===a)return;const i=s?await m(e,g):new Map,l=await n.db(),u=await m(e,w),d=await J(l,t,i,u,async p=>await X(l,p));r={created:r.created+d.created,revisions:r.revisions+d.revisions,deleted:r.deleted+d.deleted,needsMerge:[...new Set([...r.needsMerge,...d.needsMerge])],refused:[...r.refused,...d.refused]},await j(e,a,u,i,new Set(d.refused.map(p=>p.path)),s)}),"importLocal");await f(),await x("export",async()=>{const a=await h(e,w),s=a?await m(e,w):null,i=await h(e,g),l=i?await m(e,g):null,u=await G(await n.db(),t,s,l);if(a?z(s,u):u.size===0)return;const d=await S(e,u,a?[a]:[],`crtr: export ${t.name}`);await y(e,w,d,a),await j(e,d,u,l??new Map,new Set(Q(s,l)),i)});for(let a=1;;a++){const s=await ae(e,o);if(!s.ok)return{ok:!1,step:"fetch",reason:s.reason};let i=await h(e,w);if(s.value!==null&&!(i&&await we(e,s.value)&&await I(e,s.value,i))){const u=await ee(e,o);if(!u.ok)return{ok:!1,step:"fetch",reason:u.reason};const d=u.value;i=await x("merge",async()=>{if(!i||await I(e,i,d))return await y(e,w,d,i),d;const p=await ne(e,i,d),C=ie(p?await m(e,p):new Map,await m(e,w),await m(e,fe));for(const O of C.refused)r.refused.push(O);const F=await S(e,C.tree,[i,d],`crtr: merge ${t.name}`);return await y(e,w,F,i),F})}if(await f(),i===null||i===s.value)return{ok:!0,pushed:!1,imported:r};const l=await re(e,o,i);if(l.ok)return{ok:!0,pushed:!0,imported:r};if(l.reason!=="rejected")return{ok:!1,step:"push",reason:l.reason};if(a>=L)return{ok:!1,step:"push",reason:`push rejected ${L} times`}}}catch(e){if(e instanceof _)return{ok:!1,step:e.step,reason:e.message};throw e}}c(ue,"syncRepo");async function j(t,n,e,o,r,f){if(r.size===0){await y(t,g,n,f);return}const a=new Map(e);for(const s of r)o.has(s)?a.set(s,o.get(s)):a.delete(s);f!==null&&z(o,a)||await y(t,g,await S(t,a,[],"crtr: imported baseline (some files pending)"),f)}c(j,"advanceImported");async function le(t){const n=R(t.dir,A);return D(n)&&(await B(n,"utf8")).trim()||null}c(le,"readUrl");async function we(t,n){return await h(t,n)!==null}c(we,"hasCommit");function z(t,n){if(t.size!==n.size)return!1;for(const[e,o]of t)if(n.get(e)!==o)return!1;return!0}c(z,"sameTree");export{ce as FIRST_FETCH_WAIT_MS,_e as noteNodeBooting,de as noteNodeWorking,xe as noteRepoDocumentsChanged,Me as startRepoSync,ue as syncRepo};
@@ -1,8 +1,8 @@
1
1
  /** A document's delivery rules as `rules` rows. `rules.owner` mirrors the
2
2
  * document's `objects.owner` so delivery can select rules by owner through
3
3
  * `rules_on_owner`; `replaceRules` and `setRulesOwner` are the only writers. */
4
- import type { DatabaseSync } from 'node:sqlite';
5
4
  import type { ObjectRow, RuleOn, RuleSpec } from './types.js';
5
+ import type { CanvasDb } from '../canvas/db.js';
6
6
  export declare const RULE_ONS: readonly RuleOn[];
7
7
  export interface RuleRow extends RuleSpec {
8
8
  rowid: number;
@@ -11,12 +11,12 @@ export interface RuleRow extends RuleSpec {
11
11
  position: number;
12
12
  }
13
13
  /** Replace the document's rules; `position` is the array index, `owner` the document's owner. */
14
- export declare function replaceRules(db: DatabaseSync, object: ObjectRow, specs: readonly RuleSpec[]): void;
14
+ export declare function replaceRules(db: CanvasDb, object: ObjectRow, specs: readonly RuleSpec[]): Promise<void>;
15
15
  /** Re-point the document's rule rows at its current owner (after a move). */
16
- export declare function setRulesOwner(db: DatabaseSync, object: ObjectRow): void;
17
- export declare function rulesOf(db: DatabaseSync, object: ObjectRow): RuleRow[];
16
+ export declare function setRulesOwner(db: CanvasDb, object: ObjectRow): Promise<void>;
17
+ export declare function rulesOf(db: CanvasDb, object: ObjectRow): Promise<RuleRow[]>;
18
18
  /** Every rule on one of `on` whose document belongs to one of `owners`. */
19
- export declare function rulesForOwners(db: DatabaseSync, on: readonly RuleOn[], owners: readonly number[]): RuleRow[];
19
+ export declare function rulesForOwners(db: CanvasDb, on: readonly RuleOn[], owners: readonly number[]): Promise<RuleRow[]>;
20
20
  /** The only converter from package/legacy frontmatter (`surfaces`, `gate`,
21
21
  * `slash`) to rules. Tolerant like the runtime parser it replaces: invalid
22
22
  * entries are dropped; `lintRules` is the strict check. A document-level
@@ -1,3 +1,3 @@
1
- var R=Object.defineProperty;var a=(e,n)=>R(e,"name",{value:n,configurable:!0});import{prepared as u}from"../sqlite-statements.js";const E=["boot","workspace-open","file-read","document-read","command","pre-command","slash-command"],p=["name","preview","content"],y=["file-read","document-read","command","pre-command"],O=["on","match","matchFrontmatter","if","deliver"];function g(e){return{rowid:e.rowid,object:e.object,owner:e.owner,position:e.position,on:e.on_event,deliver:e.deliver,...e.match_json!==null?{match:JSON.parse(e.match_json)}:{},...e.match_frontmatter_json!==null?{matchFrontmatter:JSON.parse(e.match_frontmatter_json)}:{},...e.if_json!==null?{if:JSON.parse(e.if_json)}:{}}}a(g,"fromRaw");function _(e,n,t){const i=w(t);if(i!==null)throw new Error(`replaceRules(${n.id}): ${i}`);u(e,"DELETE FROM rules WHERE object = ?").run(n.rowid);const c=u(e,`INSERT INTO rules (object, owner, position, on_event, match_json, match_frontmatter_json, if_json, deliver)
2
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);t.forEach((r,o)=>{c.run(n.rowid,n.owner,o,r.on,r.match!==void 0?JSON.stringify(r.match):null,r.matchFrontmatter!==void 0?JSON.stringify(r.matchFrontmatter):null,r.if!==void 0?JSON.stringify(r.if):null,r.deliver)})}a(_,"replaceRules");function v(e,n){const t=u(e,"SELECT owner FROM objects WHERE rowid = ?").get(n.rowid);if(t===void 0)throw new Error(`setRulesOwner: object ${n.id} does not exist`);u(e,"UPDATE rules SET owner = ? WHERE object = ?").run(t.owner,n.rowid)}a(v,"setRulesOwner");function $(e,n){return u(e,"SELECT * FROM rules WHERE object = ? ORDER BY position").all(n.rowid).map(g)}a($,"rulesOf");function b(e,n,t){if(n.length===0||t.length===0)return[];const i=`SELECT * FROM rules WHERE on_event IN (${n.map(()=>"?").join(",")})
3
- AND owner IN (${t.map(()=>"?").join(",")}) ORDER BY object, position`;return e.prepare(i).all(...n,...t).map(g)}a(b,"rulesForOwners");const S={boot:"boot","workspace-open":"workspace-open",read:"file-read","memory-read":"document-read",command:"command","pre-command":"pre-command"};function s(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:void 0}a(s,"predicate");function j(e){if(typeof e=="string")return e.trim()===""?void 0:[e.trim()];if(!Array.isArray(e))return;const n=e.filter(t=>typeof t=="string"&&t.trim()!=="").map(t=>t.trim());return n.length>0?n:void 0}a(j,"globs");function x(e){const n=s(e.gate),t=a(r=>n!==void 0&&r!==void 0?{all:[n,r]}:n??r,"withGate"),i=[],c=Array.isArray(e.surfaces)?e.surfaces:[];for(const r of c){const o=s(r);if(o===void 0)continue;const d=typeof o.on=="string"?S[o.on]:void 0,f=o.at;if(d===void 0||typeof f!="string"||!p.includes(f))continue;const l=j(o.match),m=d==="file-read"?s(o["match-frontmatter"]):void 0;if(y.includes(d)&&l===void 0&&m===void 0)continue;const h=t(s(o.gate));i.push({on:d,deliver:f,...l!==void 0&&d!=="boot"&&d!=="workspace-open"?{match:l}:{},...m!==void 0?{matchFrontmatter:m}:{},...h!==void 0?{if:h}:{}})}return e.slash===!0&&i.push({on:"slash-command",deliver:"content",...n!==void 0?{if:n}:{}}),i}a(x,"rulesFromFrontmatter");function w(e){if(!Array.isArray(e))return`invalid rules: ${JSON.stringify(e)} (expected a list of {on, deliver, match?, matchFrontmatter?, if?} entries)`;for(const n of e){const t=s(n);if(t===void 0)return`invalid rule: ${JSON.stringify(n)} (expected an {on, deliver, match?, matchFrontmatter?, if?} object)`;for(const d of Object.keys(t))if(!O.includes(d))return`invalid rule: unknown key \`${d}\` (a rule carries only ${O.join(", ")})`;const i=t.on;if(typeof i!="string"||!E.includes(i))return`invalid rule \`on\`: ${JSON.stringify(i)} (expected ${E.join("|")})`;const c=t.deliver;if(typeof c!="string"||!p.includes(c))return`invalid rule \`deliver\`: ${JSON.stringify(c)} (expected ${p.join("|")})`;const r=t.match;if(r!==void 0){if(i==="boot"||i==="workspace-open"||i==="slash-command")return`invalid rule: \`match\` is meaningless on \`${i}\`; drop it`;if(!Array.isArray(r)||r.length===0||r.some(d=>typeof d!="string"||d.trim()===""))return`invalid rule \`match\`: ${JSON.stringify(r)} (expected a non-empty list of non-empty globs)`}const o=t.matchFrontmatter;if(o!==void 0){if(i!=="file-read")return"invalid rule: `matchFrontmatter` applies to `file-read` rules only";if(s(o)===void 0)return`invalid rule \`matchFrontmatter\`: ${JSON.stringify(o)} (expected a field\u2192matcher object)`}if(y.includes(i)&&r===void 0&&o===void 0)return`invalid rule: a \`${i}\` rule requires \`match\`${i==="file-read"?" or `matchFrontmatter`":""}`;if(t.if!==void 0&&s(t.if)===void 0)return`invalid rule \`if\`: ${JSON.stringify(t.if)} (expected a predicate object)`}return null}a(w,"lintRules");export{E as RULE_ONS,w as lintRules,_ as replaceRules,b as rulesForOwners,x as rulesFromFrontmatter,$ as rulesOf,v as setRulesOwner};
1
+ var O=Object.defineProperty;var d=(e,n)=>O(e,"name",{value:n,configurable:!0});import{forEachAsync as g}from"../async-array.js";const h=["boot","workspace-open","file-read","document-read","command","pre-command","slash-command"],m=["name","preview","content"],y=["file-read","document-read","command","pre-command"],E=["on","match","matchFrontmatter","if","deliver"];function w(e){return{rowid:e.rowid,object:e.object,owner:e.owner,position:e.position,on:e.on_event,deliver:e.deliver,...e.match_json!==null?{match:JSON.parse(e.match_json)}:{},...e.match_frontmatter_json!==null?{matchFrontmatter:JSON.parse(e.match_frontmatter_json)}:{},...e.if_json!==null?{if:JSON.parse(e.if_json)}:{}}}d(w,"fromRaw");async function _(e,n,t){const i=S(t);if(i!==null)throw new Error(`replaceRules(${n.id}): ${i}`);await e.prepare("DELETE FROM rules WHERE object = ?").run(n.rowid);const c=e.prepare(`INSERT INTO rules (object, owner, position, on_event, match_json, match_frontmatter_json, if_json, deliver)
2
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`);await g(t,async(r,o)=>{await c.run(n.rowid,n.owner,o,r.on,r.match!==void 0?JSON.stringify(r.match):null,r.matchFrontmatter!==void 0?JSON.stringify(r.matchFrontmatter):null,r.if!==void 0?JSON.stringify(r.if):null,r.deliver)})}d(_,"replaceRules");async function v(e,n){const t=await e.prepare("SELECT owner FROM objects WHERE rowid = ?").get(n.rowid);if(t===void 0)throw new Error(`setRulesOwner: object ${n.id} does not exist`);await e.prepare("UPDATE rules SET owner = ? WHERE object = ?").run(t.owner,n.rowid)}d(v,"setRulesOwner");async function $(e,n){return(await e.prepare("SELECT * FROM rules WHERE object = ? ORDER BY position").all(n.rowid)).map(w)}d($,"rulesOf");async function A(e,n,t){if(n.length===0||t.length===0)return[];const i=`SELECT * FROM rules WHERE on_event IN (${n.map(()=>"?").join(",")})
3
+ AND owner IN (${t.map(()=>"?").join(",")}) ORDER BY object, position`;return(await e.prepareUncached(i).all(...n,...t)).map(w)}d(A,"rulesForOwners");const R={boot:"boot","workspace-open":"workspace-open",read:"file-read","memory-read":"document-read",command:"command","pre-command":"pre-command"};function s(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)?e:void 0}d(s,"predicate");function j(e){if(typeof e=="string")return e.trim()===""?void 0:[e.trim()];if(!Array.isArray(e))return;const n=e.filter(t=>typeof t=="string"&&t.trim()!=="").map(t=>t.trim());return n.length>0?n:void 0}d(j,"globs");function b(e){const n=s(e.gate),t=d(r=>n!==void 0&&r!==void 0?{all:[n,r]}:n??r,"withGate"),i=[],c=Array.isArray(e.surfaces)?e.surfaces:[];for(const r of c){const o=s(r);if(o===void 0)continue;const a=typeof o.on=="string"?R[o.on]:void 0,u=o.at;if(a===void 0||typeof u!="string"||!m.includes(u))continue;const f=j(o.match),l=a==="file-read"?s(o["match-frontmatter"]):void 0;if(y.includes(a)&&f===void 0&&l===void 0)continue;const p=t(s(o.gate));i.push({on:a,deliver:u,...f!==void 0&&a!=="boot"&&a!=="workspace-open"?{match:f}:{},...l!==void 0?{matchFrontmatter:l}:{},...p!==void 0?{if:p}:{}})}return e.slash===!0&&i.push({on:"slash-command",deliver:"content",...n!==void 0?{if:n}:{}}),i}d(b,"rulesFromFrontmatter");function S(e){if(!Array.isArray(e))return`invalid rules: ${JSON.stringify(e)} (expected a list of {on, deliver, match?, matchFrontmatter?, if?} entries)`;for(const n of e){const t=s(n);if(t===void 0)return`invalid rule: ${JSON.stringify(n)} (expected an {on, deliver, match?, matchFrontmatter?, if?} object)`;for(const a of Object.keys(t))if(!E.includes(a))return`invalid rule: unknown key \`${a}\` (a rule carries only ${E.join(", ")})`;const i=t.on;if(typeof i!="string"||!h.includes(i))return`invalid rule \`on\`: ${JSON.stringify(i)} (expected ${h.join("|")})`;const c=t.deliver;if(typeof c!="string"||!m.includes(c))return`invalid rule \`deliver\`: ${JSON.stringify(c)} (expected ${m.join("|")})`;const r=t.match;if(r!==void 0){if(i==="boot"||i==="workspace-open"||i==="slash-command")return`invalid rule: \`match\` is meaningless on \`${i}\`; drop it`;if(!Array.isArray(r)||r.length===0||r.some(a=>typeof a!="string"||a.trim()===""))return`invalid rule \`match\`: ${JSON.stringify(r)} (expected a non-empty list of non-empty globs)`}const o=t.matchFrontmatter;if(o!==void 0){if(i!=="file-read")return"invalid rule: `matchFrontmatter` applies to `file-read` rules only";if(s(o)===void 0)return`invalid rule \`matchFrontmatter\`: ${JSON.stringify(o)} (expected a field\u2192matcher object)`}if(y.includes(i)&&r===void 0&&o===void 0)return`invalid rule: a \`${i}\` rule requires \`match\`${i==="file-read"?" or `matchFrontmatter`":""}`;if(t.if!==void 0&&s(t.if)===void 0)return`invalid rule \`if\`: ${JSON.stringify(t.if)} (expected a predicate object)`}return null}d(S,"lintRules");export{h as RULE_ONS,S as lintRules,_ as replaceRules,A as rulesForOwners,b as rulesFromFrontmatter,$ as rulesOf,v as setRulesOwner};
@@ -1 +1 @@
1
- var d=Object.defineProperty;var c=(t,n)=>d(t,"name",{value:n,configurable:!0});import{covers as u}from"@north-light/identity";import{identityOf as r}from"./index.js";import{memoryScope as p,missingOwnMemoryScope as f}from"./own-memory.js";import{objectPlace as x,runPlace as m,runsSeeEachOther as O}from"../../runs/confinement.js";const M={identity:r,sync:"runtime",canRead(t,n,e,o,s){if(n.class==="person"||o.length===0)return!0;if(n.app.rowid===e.rowid)return y(t,n,o)&&f(t,n,e,o,s,"read")===null;const i=r(t,e).external_id,l=c(g=>n.scopes!==null&&n.scopes.some(S=>u(S,g)),"held");return o[0].type==="node"?l(`crtr:objects:read:${i}`)||s.type==="document"&&s.kind==="report"&&l(`crtr:conversations:read:${i}`):l(p(t,i,"read",o))},canChange(t,n,e,o,s){if(n.class==="person")return!0;if(n.app.rowid===e.rowid)return o.length===0||y(t,n,o)&&f(t,n,e,o,s,"rw")===null;if(o.length===0||o[0].type==="node")return!1;const i=p(t,r(t,e).external_id,"rw",o);return n.scopes!==null&&n.scopes.some(l=>u(l,i))}},w=new WeakMap;function y(t,n,e){if(n.class==="person"||e.length===0||e[0].type!=="node"||n.class==="app"&&n.place===void 0)return!0;let o=w.get(n);if(o===void 0&&(o=n.class==="app"?n.place:n.class==="node"?m(n.node.id,t):n.place??x(n.object.rowid,t),w.set(n,o)),o===null)return!0;const s=m(e[0].id,t);return s===null?!o.isolated:O(o,s)}c(y,"runConfined");export{M as appSpace};
1
+ var S=Object.defineProperty;var l=(o,n)=>S(o,"name",{value:n,configurable:!0});import{covers as r}from"@north-light/identity";import{identityOf as u}from"./index.js";import{memoryScope as a,missingOwnMemoryScope as p}from"./own-memory.js";import{objectPlace as x,runPlace as w,runsSeeEachOther as O}from"../../runs/confinement.js";const M={sync:"runtime",async canRead(o,n,i,t,e){if(n.class==="person"||t.length===0)return!0;if(n.app.rowid===i.rowid)return await m(o,n,t)&&await p(o,n,i,t,e,"read")===null;const s=(await u(o,i)).external_id,c=l(y=>n.scopes!==null&&n.scopes.some(g=>r(g,y)),"held");return t[0].type==="node"?c(`crtr:objects:read:${s}`)||e.type==="document"&&e.kind==="report"&&c(`crtr:conversations:read:${s}`):c(await a(o,s,"read",t))},async canChange(o,n,i,t,e){if(n.class==="person")return!0;if(n.app.rowid===i.rowid)return t.length===0||await m(o,n,t)&&await p(o,n,i,t,e,"rw")===null;if(t.length===0||t[0].type==="node")return!1;const s=await a(o,(await u(o,i)).external_id,"rw",t);return n.scopes!==null&&n.scopes.some(c=>r(c,s))}},f=new WeakMap;async function m(o,n,i){if(n.class==="person"||i.length===0||i[0].type!=="node"||n.class==="app"&&n.place===void 0)return!0;let t=f.get(n);if(t===void 0&&(t=n.class==="app"?n.place:n.class==="node"?await w(n.node.id,o):n.place??await x(n.object.rowid,o),f.set(n,t)),t===null)return!0;const e=await w(i[0].id,o);return e===null?!t.isolated:O(t,e)}l(m,"runConfined");export{M as appSpace};
@@ -1,5 +1,5 @@
1
- import type { DatabaseSync } from 'node:sqlite';
2
1
  import type { ObjectRow, Reader } from '../types.js';
2
+ import type { CanvasDb } from '../../canvas/db.js';
3
3
  export interface IdentityRow {
4
4
  object: number;
5
5
  scheme: string;
@@ -10,10 +10,9 @@ export type SpaceType = 'person' | 'app' | 'repo';
10
10
  * `path` is the owner chain below the space, top first, ending at the object
11
11
  * (e.g. `[node, document]`); it is empty when the object is the space itself. */
12
12
  export interface Space {
13
- identity(db: DatabaseSync, space: ObjectRow): IdentityRow;
14
13
  sync: 'runtime' | 'repo-ref';
15
- canRead(db: DatabaseSync, reader: Reader, space: ObjectRow, path: ObjectRow[], object: ObjectRow): boolean;
16
- canChange(db: DatabaseSync, reader: Reader, space: ObjectRow, path: ObjectRow[], object: ObjectRow): boolean;
14
+ canRead(db: CanvasDb, reader: Reader, space: ObjectRow, path: ObjectRow[], object: ObjectRow): Promise<boolean>;
15
+ canChange(db: CanvasDb, reader: Reader, space: ObjectRow, path: ObjectRow[], object: ObjectRow): Promise<boolean>;
17
16
  }
18
17
  export declare const SPACES: Record<SpaceType, Space>;
19
- export declare function identityOf(db: DatabaseSync, object: ObjectRow): IdentityRow;
18
+ export declare function identityOf(db: CanvasDb, object: ObjectRow): Promise<IdentityRow>;
@@ -1 +1 @@
1
- var p=Object.defineProperty;var o=(r,e)=>p(r,"name",{value:e,configurable:!0});import{prepared as i}from"../../sqlite-statements.js";import{appSpace as n}from"./app.js";import{personSpace as a}from"./person.js";import{repoSpace as m}from"./repo.js";const E={person:a,app:n,repo:m};function h(r,e){const t=i(r,"SELECT object, scheme, external_id FROM identities WHERE object = ?").get(e.rowid);if(!t)throw new Error(`${e.type} ${e.id} has no identity`);return t}o(h,"identityOf");export{E as SPACES,h as identityOf};
1
+ var p=Object.defineProperty;var t=(r,e)=>p(r,"name",{value:e,configurable:!0});import{appSpace as i}from"./app.js";import{personSpace as n}from"./person.js";import{repoSpace as a}from"./repo.js";const f={person:n,app:i,repo:a};async function E(r,e){const o=await r.prepare("SELECT object, scheme, external_id FROM identities WHERE object = ?").get(e.rowid);if(!o)throw new Error(`${e.type} ${e.id} has no identity`);return o}t(E,"identityOf");export{f as SPACES,E as identityOf};
@@ -1,18 +1,18 @@
1
- import type { DatabaseSync } from 'node:sqlite';
2
1
  import type { ObjectRow, Reader } from '../types.js';
2
+ import type { CanvasDb } from '../../canvas/db.js';
3
3
  type Path = ObjectRow[];
4
4
  /** The scope a run launched with a `scopes` list lacks to read (`read`) or change (`rw`) one of its own app's documents, or null.
5
5
  * Own-app memory needs no grant scope, but a launched list narrows it (identity MEM-2): reading needs `crtr:memory:read:app:<A>`,
6
6
  * writing `crtr:memory:rw:app:<A>` (profile forms for a profile's documents). Only documents are gated — never a node, job or
7
7
  * lifecycle object — and a run with no list, an app's server and the person keep full access. A report is readable inside its
8
8
  * own run (a run hears its children through them); writing one is the runtime's own act (see `asRuntimeWriter`). */
9
- export declare function missingOwnMemoryScope(db: DatabaseSync, reader: Reader, space: ObjectRow, path: Path, object: {
9
+ export declare function missingOwnMemoryScope(db: CanvasDb, reader: Reader, space: ObjectRow, path: Path, object: {
10
10
  type: string;
11
11
  kind: string | null;
12
- } | null, access: 'read' | 'rw'): string | null;
12
+ } | null, access: 'read' | 'rw'): Promise<string | null>;
13
13
  /** The same reader with its launched list lifted, for the runtime's own writes inside a narrowed run: a `crtr push` report and the
14
14
  * scaffolded roadmap of a promoted node. Wrap only the one call that creates the document the runtime names. */
15
15
  export declare function asRuntimeWriter<R extends Reader>(reader: R): R;
16
16
  /** `crtr:memory:<access>:app:<B>` for an app document, or its profile form for a profile and what it owns. */
17
- export declare function memoryScope(db: DatabaseSync, app: string, access: 'read' | 'rw', path: Path): string;
17
+ export declare function memoryScope(db: CanvasDb, app: string, access: 'read' | 'rw', path: Path): Promise<string>;
18
18
  export {};
@@ -1 +1 @@
1
- var f=Object.defineProperty;var l=(n,e)=>f(n,"name",{value:e,configurable:!0});import{prepared as d}from"../../sqlite-statements.js";import{covers as a}from"@north-light/identity";import{runPlace as s}from"../../runs/confinement.js";const m=l((n,e)=>d(n,"SELECT external_id FROM identities WHERE object = ?").get(e.rowid).external_id,"externalId");function S(n,e,o,t,r,i){if(e.class==="person"||t.length===0||r!==null&&r.type!=="document")return null;const u=e.launched;if(u==null||i==="read"&&r?.kind==="report"&&t[0].type==="node"&&y(n,e,t[0].id))return null;const c=x(n,m(n,o),i,t);return u.some(p=>a(p,c))?null:c}l(S,"missingOwnMemoryScope");function y(n,e,o){const t=e.class==="node"?s(e.node.id,n):e.class==="person"?null:e.place??null,r=s(o,n);return t!==null&&r!==null&&t.run===r.run}l(y,"inReadersRun");function w(n){return n.class==="person"?n:{...n,launched:null}}l(w,"asRuntimeWriter");function x(n,e,o,t){const r=t[0];return r.type!=="profile"?`crtr:memory:${o}:${e}`:`crtr:memory:${o}:${e}:profile:${m(n,r)}`}l(x,"memoryScope");export{w as asRuntimeWriter,x as memoryScope,S as missingOwnMemoryScope};
1
+ var m=Object.defineProperty;var l=(n,t)=>m(n,"name",{value:t,configurable:!0});import{covers as f}from"@north-light/identity";import{runPlace as s}from"../../runs/confinement.js";const a=l(async(n,t)=>(await n.prepare("SELECT external_id FROM identities WHERE object = ?").get(t.rowid)).external_id,"externalId");async function $(n,t,o,e,r,u){if(t.class==="person"||e.length===0||r!==null&&r.type!=="document")return null;const i=t.launched;if(i==null||u==="read"&&r?.kind==="report"&&e[0].type==="node"&&await y(n,t,e[0].id))return null;const c=await w(n,await a(n,o),u,e);return i.some(p=>f(p,c))?null:c}l($,"missingOwnMemoryScope");async function y(n,t,o){const e=t.class==="node"?await s(t.node.id,n):t.class==="person"?null:t.place??null,r=await s(o,n);return e!==null&&r!==null&&e.run===r.run}l(y,"inReadersRun");function g(n){return n.class==="person"?n:{...n,launched:null}}l(g,"asRuntimeWriter");async function w(n,t,o,e){const r=e[0];return r.type!=="profile"?`crtr:memory:${o}:${t}`:`crtr:memory:${o}:${t}:profile:${await a(n,r)}`}l(w,"memoryScope");export{g as asRuntimeWriter,w as memoryScope,$ as missingOwnMemoryScope};
@@ -1,3 +1,3 @@
1
- import{prepared as p}from"../../sqlite-statements.js";import{covers as o}from"@north-light/identity";import{identityOf as f}from"./index.js";const d={identity:f,sync:"runtime",canRead(c,r,s,t,i){return r.class==="person"||r.class==="object"&&r.owner.rowid===s.rowid?!0:r.scopes===null?!1:r.app.rowid===s.rowid||t.length===0?!0:t[0].type!=="document"?!1:r.scopes.some(n=>o(n,"crtr:memory:manage:user"))||i.privacy==="public"?!0:i.privacy==="private"&&r.scopes.some(n=>o(n,"crtr:memory:read_private:user"))},canChange(c,r,s,t,i){if(r.class==="person"||r.class==="object"&&r.owner.rowid===s.rowid||r.app.rowid===s.rowid||r.scopes?.some(e=>o(e,"crtr:memory:manage:user")))return!0;if(t.length===0)return r.scopes?.some(e=>o(e,"crtr:memory:rw:user"))??!1;if(t[0].type!=="document")return!1;const n=`crtr:memory:rw:user:${i.name}`;if(r.scopes===null||!r.scopes.some(e=>o(e,n)))return!1;const u=p(c,`SELECT author.type, author.owner AS app FROM revisions r JOIN objects author ON author.rowid = r.author
2
- WHERE r.document = ? ORDER BY r.number, r.created_at LIMIT 1`).get(t[0].rowid);return u?u.type==="person"||u.app===r.app.rowid?!0:p(c,`SELECT g.resolved_scopes_json FROM grants g JOIN identities i ON i.external_id = g.grantee
3
- WHERE i.object = ? AND i.scheme = 'app'`).all(u.app).some(({resolved_scopes_json:e})=>JSON.parse(e).some(({scope:a,mode:m})=>m==="always"&&o(a,"crtr:memory:manage:user"))):!1}};export{d as personSpace};
1
+ import{covers as t}from"@north-light/identity";const f={sync:"runtime",async canRead(a,r,o,s,i){return r.class==="person"||r.class==="object"&&r.owner.rowid===o.rowid?!0:r.scopes===null?!1:r.app.rowid===o.rowid||s.length===0?!0:s[0].type!=="document"?!1:r.scopes.some(n=>t(n,"crtr:memory:manage:user"))||i.privacy==="public"?!0:i.privacy==="private"&&r.scopes.some(n=>t(n,"crtr:memory:read_private:user"))},async canChange(a,r,o,s,i){if(r.class==="person"||r.class==="object"&&r.owner.rowid===o.rowid||r.app.rowid===o.rowid||r.scopes?.some(e=>t(e,"crtr:memory:manage:user")))return!0;if(s.length===0)return r.scopes?.some(e=>t(e,"crtr:memory:rw:user"))??!1;if(s[0].type!=="document")return!1;const n=`crtr:memory:rw:user:${i.name}`;if(r.scopes===null||!r.scopes.some(e=>t(e,n)))return!1;const u=await a.prepare(`SELECT author.type, author.owner AS app FROM revisions r JOIN objects author ON author.rowid = r.author
2
+ WHERE r.document = ? ORDER BY r.number, r.created_at LIMIT 1`).get(s[0].rowid);return u?u.type==="person"||u.app===r.app.rowid?!0:(await a.prepare(`SELECT g.resolved_scopes_json FROM grants g JOIN identities i ON i.external_id = g.grantee
3
+ WHERE i.object = ? AND i.scheme = 'app'`).all(u.app)).some(({resolved_scopes_json:e})=>JSON.parse(e).some(({scope:c,mode:p})=>p==="always"&&t(c,"crtr:memory:manage:user"))):!1}};export{f as personSpace};
@@ -7,7 +7,7 @@ import type { Space } from './index.js';
7
7
  * own repo. A Mac terminal node reaches every path. */
8
8
  export declare function insideRepo(db: Parameters<Space['canRead']>[0], reader: Reader, repo: {
9
9
  rowid: number;
10
- }, access: 'read' | 'rw'): boolean;
10
+ }, access: 'read' | 'rw'): Promise<boolean>;
11
11
  /** A repo: read and changed by a run with a checkout of it (enclosing its cwd or one of its
12
12
  * profile's project paths) that its file permissions reach (see `insideRepo`). It owns only public documents, so a
13
13
  * non-public one is never changed. */
@@ -1 +1 @@
1
- var u=Object.defineProperty;var i=(t,o)=>u(t,"name",{value:o,configurable:!0});import{fileRoot as f}from"../../spaces/file-root.js";import{identityOf as c}from"./index.js";function p(t,o,e,r){if(o.class==="object")return o.repos.some(n=>n.rowid===e.rowid);if(o.class!=="node")return!1;const s=[...o.checkouts,...o.projectCheckouts].filter(n=>n.repo.rowid===e.rowid);if(s.length===0)return!1;const l={app:c(t,o.app).external_id,resolved:o.scopes??[],launched:null};return s.some(n=>"root"in f(l,n.root,r))}i(p,"insideRepo");const d={identity:c,sync:"repo-ref",canRead(t,o,e,r){return o.class==="person"||r.length===0?!0:p(t,o,e,"read")},canChange(t,o,e,r,s){return s.privacy!=="public"?!1:o.class==="person"?!0:p(t,o,e,"rw")}};export{p as insideRepo,d as repoSpace};
1
+ var p=Object.defineProperty;var c=(o,t)=>p(o,"name",{value:t,configurable:!0});import{fileRoot as l}from"../../spaces/file-root.js";import{identityOf as u}from"./index.js";async function i(o,t,e,r){if(t.class==="object")return t.repos.some(n=>n.rowid===e.rowid);if(t.class!=="node")return!1;const s=[...t.checkouts,...t.projectCheckouts].filter(n=>n.repo.rowid===e.rowid);if(s.length===0)return!1;const a={app:(await u(o,t.app)).external_id,resolved:t.scopes??[],launched:null};return s.some(n=>"root"in l(a,n.root,r))}c(i,"insideRepo");const m={sync:"repo-ref",async canRead(o,t,e,r){return t.class==="person"||r.length===0?!0:await i(o,t,e,"read")},async canChange(o,t,e,r,s){return s.privacy!=="public"?!1:t.class==="person"?!0:await i(o,t,e,"rw")}};export{i as insideRepo,m as repoSpace};
@@ -1,8 +1,8 @@
1
1
  /** Watches and their subscriptions, message-subscription ending, tree walks and fork copies.
2
2
  * `watches.in_tree` is written only here: it is 1 while any subscription of the watch
3
3
  * started from spawn, job-start or ask. */
4
- import type { DatabaseSync } from 'node:sqlite';
5
4
  import type { ListenConfig, ObjectRow, Reader, WatchStart } from './types.js';
5
+ import type { CanvasDb } from '../canvas/db.js';
6
6
  export interface Subscription {
7
7
  rowid: number;
8
8
  pattern: string;
@@ -36,33 +36,33 @@ export declare function configFromJson(json: string): ListenConfig;
36
36
  /** Record (or extend) watcher's watch on object. Adds only the subscriptions the watch lacks:
37
37
  * a pattern already held without an end covers any new one, except that a tree start
38
38
  * still adds its own subscription when only non-tree ones hold the pattern. */
39
- export declare function recordWatch(db: DatabaseSync, watcher: ObjectRow, object: ObjectRow, start: WatchStart, opts?: RecordWatchOpts): void;
39
+ export declare function recordWatch(db: CanvasDb, watcher: ObjectRow, object: ObjectRow, start: WatchStart, opts?: RecordWatchOpts): Promise<void>;
40
40
  /** Mark the existing watch of `object` by `watcher` as made through `link` by `app`, changing nothing else about it. */
41
- export declare function markLinkWatch(db: DatabaseSync, watcher: ObjectRow, object: ObjectRow, app: ObjectRow): void;
41
+ export declare function markLinkWatch(db: CanvasDb, watcher: ObjectRow, object: ObjectRow, app: ObjectRow): Promise<void>;
42
42
  /** Remove the whole watch, the subscriptions with one pattern, or (tree-only form) the
43
43
  * subscriptions one start made. A watch left with no subscription is deleted. */
44
- export declare function unwatch(db: DatabaseSync, watcher: ObjectRow, object: ObjectRow, which?: string | {
44
+ export declare function unwatch(db: CanvasDb, watcher: ObjectRow, object: ObjectRow, which?: string | {
45
45
  startedBy: WatchStart;
46
- }): void;
46
+ }): Promise<void>;
47
47
  /** Change the listening configuration of the watcher's subscriptions with `pattern`; null = the watcher's default. */
48
- export declare function setSubscriptionConfig(db: DatabaseSync, watcher: ObjectRow, object: ObjectRow, pattern: string, config: ListenConfig | null): void;
48
+ export declare function setSubscriptionConfig(db: CanvasDb, watcher: ObjectRow, object: ObjectRow, pattern: string, config: ListenConfig | null): Promise<void>;
49
49
  /** End the message subscriptions on `object` (a node): 'final' and 'done' end all of them;
50
50
  * `{result}` ends those waiting for that request's answer. */
51
- export declare function endMessageSubscriptions(db: DatabaseSync, object: ObjectRow, cause: 'final' | 'done' | {
51
+ export declare function endMessageSubscriptions(db: CanvasDb, object: ObjectRow, cause: 'final' | 'done' | {
52
52
  result: string;
53
- }): void;
53
+ }): Promise<void>;
54
54
  /** The watches `watcher` holds that the reader may see (both ends readable). */
55
- export declare function watchesOf(db: DatabaseSync, reader: Reader, watcher: ObjectRow): Watch[];
55
+ export declare function watchesOf(db: CanvasDb, reader: Reader, watcher: ObjectRow): Promise<Watch[]>;
56
56
  /** The watches held on `object` that the reader may see (both ends readable). */
57
- export declare function watchersOf(db: DatabaseSync, reader: Reader, object: ObjectRow): Watch[];
57
+ export declare function watchersOf(db: CanvasDb, reader: Reader, object: ObjectRow): Promise<Watch[]>;
58
58
  /** The ids of every object that watches `object`, whatever started the watch. */
59
- export declare function watcherIdsOf(db: DatabaseSync, object: ObjectRow): string[];
59
+ export declare function watcherIdsOf(db: CanvasDb, object: ObjectRow): Promise<string[]>;
60
60
  /** Every node below `root` in the tree (in-tree watches, watcher → object), each once. */
61
- export declare function descendants(db: DatabaseSync, root: ObjectRow): ObjectRow[];
61
+ export declare function descendants(db: CanvasDb, root: ObjectRow): Promise<ObjectRow[]>;
62
62
  /** Every node above `leaf` in the tree (in-tree watches, object → watcher), each once. */
63
- export declare function ancestors(db: DatabaseSync, leaf: ObjectRow): ObjectRow[];
63
+ export declare function ancestors(db: CanvasDb, leaf: ObjectRow): Promise<ObjectRow[]>;
64
64
  /** The objects whose in-tree watch covers `object` (its spawner, job starter, explicit watchers). */
65
- export declare function treeWatchersOf(db: DatabaseSync, object: ObjectRow): ObjectRow[];
65
+ export declare function treeWatchersOf(db: CanvasDb, object: ObjectRow): Promise<ObjectRow[]>;
66
66
  /** Give `fork` a copy of every watch `source` holds, with the same subscriptions, configurations
67
67
  * and read base; each copied subscription records `fork`, so no copy is in the tree. */
68
- export declare function copyWatchesForFork(db: DatabaseSync, source: ObjectRow, fork: ObjectRow): void;
68
+ export declare function copyWatchesForFork(db: CanvasDb, source: ObjectRow, fork: ObjectRow): Promise<void>;