@north-light/crouter 0.3.353 → 0.3.354

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 (609) hide show
  1. package/dist/api/client.d.ts +35 -25
  2. package/dist/api/client.js +2 -2
  3. package/dist/api/dto/broker-ops.d.ts +2 -36
  4. package/dist/api/dto/canvas.d.ts +8 -13
  5. package/dist/api/dto/config.d.ts +4 -0
  6. package/dist/api/dto/delivery.d.ts +61 -0
  7. package/dist/api/dto/docs.d.ts +133 -0
  8. package/dist/api/dto/docs.js +1 -0
  9. package/dist/api/dto/health.d.ts +26 -79
  10. package/dist/api/dto/node-outcomes.d.ts +1 -3
  11. package/dist/api/dto/nodes.d.ts +5 -26
  12. package/dist/api/dto/objects.d.ts +167 -0
  13. package/dist/api/dto/objects.js +1 -0
  14. package/dist/api/dto/profiles.d.ts +14 -8
  15. package/dist/api/dto/reports.d.ts +9 -7
  16. package/dist/api/dto/reviews.d.ts +9 -3
  17. package/dist/api/dto/worktree.d.ts +1 -1
  18. package/dist/api/index.d.ts +0 -1
  19. package/dist/api/index.js +1 -1
  20. package/dist/api/routes.d.ts +14 -12
  21. package/dist/api/routes.js +1 -1
  22. package/dist/build-root.js +1 -1
  23. package/dist/builtin-memory/00-runtime-base/00-authoring.md +10 -5
  24. package/dist/builtin-memory/04-orchestration-kernel.md +7 -7
  25. package/dist/builtin-memory/05-kinds/advisor/01-orchestrator.md +1 -1
  26. package/dist/builtin-memory/05-kinds/explore/00-base.md +2 -2
  27. package/dist/builtin-memory/05-kinds/explore/01-orchestrator.md +2 -2
  28. package/dist/builtin-memory/crouter-concepts/INDEX.md +2 -2
  29. package/dist/builtin-memory/crouter-concepts/lifecycle-and-wakes.md +1 -1
  30. package/dist/builtin-memory/crouter-concepts/memory.md +15 -15
  31. package/dist/builtin-memory/crouter-concepts/nodes-and-the-canvas.md +1 -1
  32. package/dist/builtin-memory/crouter-concepts/profiles-kinds-and-modes.md +5 -5
  33. package/dist/builtin-memory/crouter-concepts/scopes-and-trust.md +1 -1
  34. package/dist/builtin-memory/crouter-concepts/why-a-daemon.md +1 -1
  35. package/dist/builtin-memory/crouter-sdk/INDEX.md +2 -2
  36. package/dist/builtin-memory/crouter-sdk/README.md +5 -6
  37. package/dist/builtin-memory/crouter-sdk/errors.md +0 -13
  38. package/dist/builtin-memory/crouter-sdk/guides/README.md +0 -1
  39. package/dist/builtin-memory/crouter-sdk/guides/event-driven-assistant.md +2 -2
  40. package/dist/builtin-memory/crouter-sdk/nodes.md +0 -2
  41. package/dist/builtin-memory/crouter-sdk/resources.md +0 -1
  42. package/dist/builtin-memory/explore/exploration-doc.md +4 -4
  43. package/dist/builtin-memory/insights/capture.md +6 -6
  44. package/dist/builtin-memory/insights/init.md +14 -14
  45. package/dist/builtin-memory/internal/INDEX.md +4 -4
  46. package/dist/builtin-memory/internal/agent-shaping.md +20 -20
  47. package/dist/builtin-memory/internal/examples/imessage-assistant.md +2 -2
  48. package/dist/builtin-memory/internal/marketplaces.md +2 -2
  49. package/dist/builtin-memory/internal/memory-loading.md +31 -30
  50. package/dist/builtin-memory/internal/nodes-and-canvas.md +1 -1
  51. package/dist/builtin-memory/internal/plugins.md +16 -14
  52. package/dist/builtin-memory/internal/storage-tiers.md +4 -4
  53. package/dist/builtin-memory/memory-read-orientation.md +1 -1
  54. package/dist/builtin-pi-packages/pi-crtr-extensions/extensions/memory-slash-commands.ts +32 -40
  55. package/dist/clients/attach/input/controller.js +1 -1
  56. package/dist/clients/attach/input/ref-autocomplete.js +1 -1
  57. package/dist/clients/attach/input/titled-editor.js +1 -1
  58. package/dist/clients/attach/render/chat-view.js +1 -1
  59. package/dist/clients/attach/render/crtr-output.d.ts +1 -2
  60. package/dist/clients/attach/render/crtr-output.js +17 -17
  61. package/dist/clients/attach/render/group-activity.d.ts +8 -8
  62. package/dist/clients/attach/render/group-activity.js +2 -2
  63. package/dist/clients/attach/render/group-recap.js +1 -1
  64. package/dist/clients/attach/render/tool-calls.d.ts +1 -1
  65. package/dist/clients/attach/session/profile-files.js +1 -1
  66. package/dist/clients/attach/slash/dispatch.js +1 -1
  67. package/dist/clients/attach/viewer.js +806 -1553
  68. package/dist/commands/api-client.d.ts +2 -0
  69. package/dist/commands/api-client.js +3 -3
  70. package/dist/commands/canvas/edges.d.ts +2 -0
  71. package/dist/commands/canvas/edges.js +2 -0
  72. package/dist/commands/canvas/list.d.ts +4 -0
  73. package/dist/commands/canvas/list.js +3 -0
  74. package/dist/commands/canvas/read.d.ts +8 -0
  75. package/dist/commands/canvas/read.js +5 -0
  76. package/dist/commands/canvas/search.d.ts +2 -0
  77. package/dist/commands/canvas/search.js +3 -0
  78. package/dist/commands/canvas/unwatch.d.ts +2 -0
  79. package/dist/commands/canvas/unwatch.js +1 -0
  80. package/dist/commands/canvas/watch.d.ts +3 -0
  81. package/dist/commands/canvas/watch.js +1 -0
  82. package/dist/commands/canvas-analytics.js +1 -1
  83. package/dist/commands/canvas-history/grep.js +4 -4
  84. package/dist/commands/canvas-history/read.js +2 -2
  85. package/dist/commands/canvas-history/search.js +7 -7
  86. package/dist/commands/canvas-history/shared.d.ts +0 -1
  87. package/dist/commands/canvas-history/shared.js +1 -1
  88. package/dist/commands/canvas-history/stats.js +2 -2
  89. package/dist/commands/canvas-history.js +1 -1
  90. package/dist/commands/canvas.js +1 -1
  91. package/dist/commands/doc/delete.d.ts +2 -0
  92. package/dist/commands/doc/delete.js +1 -0
  93. package/dist/commands/doc/edit.d.ts +2 -0
  94. package/dist/commands/doc/edit.js +1 -0
  95. package/dist/commands/doc/history.d.ts +2 -0
  96. package/dist/commands/doc/history.js +2 -0
  97. package/dist/commands/doc/lint.d.ts +2 -0
  98. package/dist/commands/doc/lint.js +2 -0
  99. package/dist/commands/doc/list.d.ts +2 -0
  100. package/dist/commands/doc/list.js +1 -0
  101. package/dist/commands/doc/move.d.ts +2 -0
  102. package/dist/commands/doc/move.js +1 -0
  103. package/dist/commands/doc/read.d.ts +2 -0
  104. package/dist/commands/doc/read.js +1 -0
  105. package/dist/commands/doc/shared.d.ts +25 -0
  106. package/dist/commands/doc/shared.js +2 -0
  107. package/dist/commands/doc/write.d.ts +2 -0
  108. package/dist/commands/doc/write.js +1 -0
  109. package/dist/commands/{memory.d.ts → doc.d.ts} +1 -1
  110. package/dist/commands/doc.js +1 -0
  111. package/dist/commands/human/review.js +1 -1
  112. package/dist/commands/node/bash.js +2 -2
  113. package/dist/commands/node/create.js +1 -1
  114. package/dist/commands/node/inspect.js +10 -10
  115. package/dist/commands/node/lifecycle.js +2 -2
  116. package/dist/commands/node/outcome.js +1 -1
  117. package/dist/commands/node/subscription.js +1 -1
  118. package/dist/commands/node-context.js +2 -2
  119. package/dist/commands/pkg/browse/catalog.js +1 -1
  120. package/dist/commands/pkg/browse/doc-view.js +1 -1
  121. package/dist/commands/pkg/browse/model.d.ts +9 -17
  122. package/dist/commands/pkg/plugin-inspect.js +1 -1
  123. package/dist/commands/pkg/plugin-manage.d.ts +4 -8
  124. package/dist/commands/pkg/plugin-manage.js +15 -17
  125. package/dist/commands/profile/list.js +1 -1
  126. package/dist/commands/profile/new.js +1 -1
  127. package/dist/commands/profile/project.js +1 -1
  128. package/dist/commands/profile/show.js +1 -1
  129. package/dist/commands/push.js +3 -3
  130. package/dist/commands/sys/config.js +1 -1
  131. package/dist/commands/sys/context/admin/actions.d.ts +18 -43
  132. package/dist/commands/sys/context/admin/actions.js +1 -2
  133. package/dist/commands/sys/context/admin/detail-panel.d.ts +17 -25
  134. package/dist/commands/sys/context/admin/detail-panel.js +2 -1
  135. package/dist/commands/sys/context/admin/docs-panel.d.ts +7 -6
  136. package/dist/commands/sys/context/admin/docs-panel.js +1 -1
  137. package/dist/commands/sys/context/admin/list-view.d.ts +12 -12
  138. package/dist/commands/sys/context/admin/list-view.js +1 -1
  139. package/dist/commands/sys/context/admin/model.d.ts +96 -69
  140. package/dist/commands/sys/context/admin/model.js +1 -1
  141. package/dist/commands/sys/context/admin/rail-panel.d.ts +7 -5
  142. package/dist/commands/sys/context/admin/rail-panel.js +1 -1
  143. package/dist/commands/sys/context/admin/read-view.d.ts +10 -14
  144. package/dist/commands/sys/context/admin/read-view.js +1 -2
  145. package/dist/commands/sys/context/admin/shell.d.ts +26 -31
  146. package/dist/commands/sys/context/admin/shell.js +1 -1
  147. package/dist/commands/sys/context/admin.js +2 -2
  148. package/dist/commands/sys/context/doc.js +2 -3
  149. package/dist/commands/sys/context/expose.js +2 -2
  150. package/dist/commands/sys/context/prompt-review.js +4 -4
  151. package/dist/commands/sys/context/resolve.d.ts +92 -65
  152. package/dist/commands/sys/context/resolve.js +7 -9
  153. package/dist/commands/sys/context.js +1 -1
  154. package/dist/commands/sys/doctor.js +1 -1
  155. package/dist/commands/sys/migrate.js +1 -1
  156. package/dist/commands/sys/panels/profiles-panel.d.ts +3 -1
  157. package/dist/commands/sys/panels/profiles-panel.js +1 -1
  158. package/dist/commands/sys/sync-deps.d.ts +6 -11
  159. package/dist/commands/sys/sync-deps.js +7 -8
  160. package/dist/commands/sys/sync-project-guidance.js +5 -4
  161. package/dist/commands/sys/sync-shared.d.ts +41 -4
  162. package/dist/commands/sys/sync-shared.js +1 -1
  163. package/dist/commands/sys/sync-skills.js +2 -2
  164. package/dist/commands/sys/sync.js +1 -1
  165. package/dist/core/bash-job-supervisor.d.ts +2 -3
  166. package/dist/core/bash-job-supervisor.js +3 -3
  167. package/dist/core/bash-jobs.d.ts +0 -5
  168. package/dist/core/bash-jobs.js +7 -7
  169. package/dist/core/bootstrap.js +2 -2
  170. package/dist/core/canvas/canvas.d.ts +6 -50
  171. package/dist/core/canvas/canvas.js +16 -21
  172. package/dist/core/canvas/db.d.ts +4 -1
  173. package/dist/core/canvas/db.js +2 -2
  174. package/dist/core/canvas/history.d.ts +11 -39
  175. package/dist/core/canvas/history.js +9 -20
  176. package/dist/core/canvas/install-id.d.ts +2 -2
  177. package/dist/core/canvas/install-id.js +1 -1
  178. package/dist/core/canvas/memory-reads.d.ts +5 -0
  179. package/dist/core/canvas/memory-reads.js +1 -1
  180. package/dist/core/canvas/migrations.js +215 -41
  181. package/dist/core/canvas/node-agent-paths.js +1 -1
  182. package/dist/core/canvas/node-tokens.js +1 -1
  183. package/dist/core/canvas/paths.d.ts +0 -4
  184. package/dist/core/canvas/paths.js +1 -1
  185. package/dist/core/canvas/remote-canvas-source.d.ts +0 -1
  186. package/dist/core/canvas/remote-canvas-source.js +1 -1
  187. package/dist/core/canvas/render-source.d.ts +9 -6
  188. package/dist/core/canvas/render-source.js +6 -6
  189. package/dist/core/canvas/sessions.js +2 -2
  190. package/dist/core/canvas/source.d.ts +6 -0
  191. package/dist/core/canvas/tree.d.ts +29 -0
  192. package/dist/core/canvas/tree.js +12 -0
  193. package/dist/core/canvas/types.d.ts +0 -20
  194. package/dist/core/command-plugins/bundle.js +1 -1
  195. package/dist/core/config.d.ts +1 -1
  196. package/dist/core/conversation-store/listener.js +4 -2
  197. package/dist/core/feed/feed.d.ts +9 -7
  198. package/dist/core/feed/feed.js +3 -7
  199. package/dist/core/feed/inbox.d.ts +3 -5
  200. package/dist/core/feed/inbox.js +1 -10
  201. package/dist/core/feed/messages.d.ts +33 -6
  202. package/dist/core/feed/messages.js +10 -7
  203. package/dist/core/feed/reports.d.ts +10 -0
  204. package/dist/core/feed/reports.js +2 -0
  205. package/dist/core/grants/remove.js +1 -1
  206. package/dist/core/graph/access.d.ts +24 -0
  207. package/dist/core/graph/access.js +8 -0
  208. package/dist/core/graph/bodies.d.ts +6 -0
  209. package/dist/core/graph/bodies.js +1 -0
  210. package/dist/core/graph/deletion.d.ts +9 -0
  211. package/dist/core/graph/deletion.js +5 -0
  212. package/dist/core/graph/diff.d.ts +4 -0
  213. package/dist/core/graph/diff.js +4 -0
  214. package/dist/core/graph/documents.d.ts +160 -0
  215. package/dist/core/graph/documents.js +7 -0
  216. package/dist/core/graph/edges.d.ts +24 -0
  217. package/dist/core/graph/edges.js +1 -0
  218. package/dist/core/graph/events.d.ts +26 -0
  219. package/dist/core/graph/events.js +6 -0
  220. package/dist/core/graph/exposures.d.ts +53 -0
  221. package/dist/core/graph/exposures.js +4 -0
  222. package/dist/core/graph/jobs.d.ts +31 -0
  223. package/dist/core/graph/jobs.js +2 -0
  224. package/dist/core/graph/names.d.ts +28 -0
  225. package/dist/core/graph/names.js +3 -0
  226. package/dist/core/graph/objects.d.ts +55 -0
  227. package/dist/core/graph/objects.js +9 -0
  228. package/dist/core/graph/package-docs.d.ts +31 -0
  229. package/dist/core/graph/package-docs.js +5 -0
  230. package/dist/core/graph/package-files.d.ts +20 -0
  231. package/dist/core/graph/package-files.js +2 -0
  232. package/dist/core/graph/reader.d.ts +21 -0
  233. package/dist/core/graph/reader.js +3 -0
  234. package/dist/core/graph/repo-sync/exchange.d.ts +34 -0
  235. package/dist/core/graph/repo-sync/exchange.js +2 -0
  236. package/dist/core/graph/repo-sync/identity.d.ts +30 -0
  237. package/dist/core/graph/repo-sync/identity.js +1 -0
  238. package/dist/core/graph/repo-sync/index.d.ts +4 -0
  239. package/dist/core/graph/repo-sync/index.js +1 -0
  240. package/dist/core/graph/repo-sync/mirror.d.ts +30 -0
  241. package/dist/core/graph/repo-sync/mirror.js +6 -0
  242. package/dist/core/graph/repo-sync/ref-format.d.ts +76 -0
  243. package/dist/core/graph/repo-sync/ref-format.js +2 -0
  244. package/dist/core/graph/repo-sync/repos.d.ts +17 -0
  245. package/dist/core/graph/repo-sync/repos.js +3 -0
  246. package/dist/core/graph/repo-sync/sync.d.ts +42 -0
  247. package/dist/core/graph/repo-sync/sync.js +2 -0
  248. package/dist/core/graph/rules.d.ts +26 -0
  249. package/dist/core/graph/rules.js +3 -0
  250. package/dist/core/graph/spaces/app.d.ts +3 -0
  251. package/dist/core/graph/spaces/app.js +1 -0
  252. package/dist/core/graph/spaces/index.d.ts +19 -0
  253. package/dist/core/graph/spaces/index.js +1 -0
  254. package/dist/core/graph/spaces/person.d.ts +5 -0
  255. package/dist/core/graph/spaces/person.js +2 -0
  256. package/dist/core/graph/spaces/repo.d.ts +4 -0
  257. package/dist/core/graph/spaces/repo.js +1 -0
  258. package/dist/core/graph/types.d.ts +75 -0
  259. package/dist/core/graph/types.js +1 -0
  260. package/dist/core/graph/watches.d.ts +62 -0
  261. package/dist/core/graph/watches.js +18 -0
  262. package/dist/core/human/feedback-companion.js +1 -1
  263. package/dist/core/human/requests.d.ts +3 -1
  264. package/dist/core/human/requests.js +6 -6
  265. package/dist/core/inspector/model.js +2 -2
  266. package/dist/core/io.js +5 -5
  267. package/dist/core/layout-migrate/index.d.ts +24 -1
  268. package/dist/core/layout-migrate/index.js +4 -4
  269. package/dist/core/layout-migrate/paths.d.ts +4 -0
  270. package/dist/core/layout-migrate/paths.js +1 -1
  271. package/dist/core/layout-migrate/stored-paths.d.ts +7 -0
  272. package/dist/core/layout-migrate/stored-paths.js +11 -11
  273. package/dist/core/layout-migrate/stores.d.ts +19 -6
  274. package/dist/core/layout-migrate/stores.js +3 -4
  275. package/dist/core/manifest.d.ts +0 -2
  276. package/dist/core/manifest.js +1 -1
  277. package/dist/core/{memory/extensions.d.ts → plugin-extensions.d.ts} +9 -10
  278. package/dist/core/plugin-extensions.js +1 -0
  279. package/dist/core/preview-registry.d.ts +1 -1
  280. package/dist/core/preview-registry.js +3 -2
  281. package/dist/core/profiles/manifest.d.ts +7 -7
  282. package/dist/core/profiles/manifest.js +1 -1
  283. package/dist/core/profiles/select.js +3 -3
  284. package/dist/core/review/birth.js +1 -1
  285. package/dist/core/review/companion.js +1 -1
  286. package/dist/core/review/stage.d.ts +12 -1
  287. package/dist/core/review/stage.js +1 -1
  288. package/dist/core/review/store.d.ts +2 -0
  289. package/dist/core/review/store.js +1 -1
  290. package/dist/core/review/types.d.ts +7 -1
  291. package/dist/core/runs/events.js +1 -1
  292. package/dist/core/runs/operations.js +5 -5
  293. package/dist/core/runs/questions.js +2 -2
  294. package/dist/core/runtime/bearings-render.d.ts +13 -7
  295. package/dist/core/runtime/bearings-render.js +12 -12
  296. package/dist/core/runtime/bearings.d.ts +8 -18
  297. package/dist/core/runtime/bearings.js +7 -7
  298. package/dist/core/runtime/broker/daemon-ops.d.ts +7 -12
  299. package/dist/core/runtime/broker/daemon-ops.js +1 -1
  300. package/dist/core/runtime/broker/fault-retry.d.ts +2 -0
  301. package/dist/core/runtime/broker/fault-retry.js +1 -1
  302. package/dist/core/runtime/broker/frame-dispatch.d.ts +1 -1
  303. package/dist/core/runtime/broker/frame-memory-refs.d.ts +7 -2
  304. package/dist/core/runtime/broker/frame-memory-refs.js +1 -1
  305. package/dist/core/runtime/broker/inbox.d.ts +1 -4
  306. package/dist/core/runtime/broker/inbox.js +1 -10
  307. package/dist/core/runtime/broker/rebind.js +1 -1
  308. package/dist/core/runtime/broker/retry-card-elision.d.ts +7 -0
  309. package/dist/core/runtime/broker/retry-card-elision.js +1 -0
  310. package/dist/core/runtime/broker-extension-render.d.ts +0 -13
  311. package/dist/core/runtime/broker-extension-render.js +2 -4
  312. package/dist/core/runtime/broker-persona-guidance.js +3 -3
  313. package/dist/core/runtime/broker-protocol.d.ts +1 -1
  314. package/dist/core/runtime/broker.js +1 -1
  315. package/dist/core/runtime/close.d.ts +9 -4
  316. package/dist/core/runtime/close.js +1 -1
  317. package/dist/core/runtime/deliver-live.js +1 -1
  318. package/dist/core/runtime/kickoff.js +17 -19
  319. package/dist/core/runtime/launch-target.d.ts +7 -0
  320. package/dist/core/runtime/launch-target.js +1 -1
  321. package/dist/core/runtime/ledger.d.ts +10 -0
  322. package/dist/core/runtime/ledger.js +3 -0
  323. package/dist/core/runtime/lifecycle.js +2 -2
  324. package/dist/core/runtime/nodes.d.ts +10 -2
  325. package/dist/core/runtime/nodes.js +1 -1
  326. package/dist/core/runtime/outcome-document.d.ts +2 -2
  327. package/dist/core/runtime/outcome-document.js +1 -1
  328. package/dist/core/runtime/persona.js +2 -2
  329. package/dist/core/runtime/placement.js +1 -1
  330. package/dist/core/runtime/promote.d.ts +2 -2
  331. package/dist/core/runtime/promote.js +1 -1
  332. package/dist/core/runtime/prospective-inventory-cli.js +2 -2
  333. package/dist/core/runtime/recycle.js +1 -1
  334. package/dist/core/runtime/reopen.js +1 -1
  335. package/dist/core/runtime/revive.js +2 -2
  336. package/dist/core/runtime/roadmap.d.ts +17 -9
  337. package/dist/core/runtime/roadmap.js +4 -4
  338. package/dist/core/runtime/spawn-env.js +1 -1
  339. package/dist/core/runtime/spawn.d.ts +5 -3
  340. package/dist/core/runtime/spawn.js +2 -2
  341. package/dist/core/runtime/structured-output.d.ts +3 -1
  342. package/dist/core/runtime/structured-output.js +4 -4
  343. package/dist/core/scope.d.ts +1 -32
  344. package/dist/core/scope.js +1 -1
  345. package/dist/core/scoped-state/db.js +2 -1
  346. package/dist/core/scoped-state/migrate.js +2 -2
  347. package/dist/core/scoped-state/profiles.d.ts +11 -0
  348. package/dist/core/scoped-state/profiles.js +1 -1
  349. package/dist/core/scoped-state/schema.d.ts +1 -1
  350. package/dist/core/scoped-state/schema.js +7 -5
  351. package/dist/core/spaces/permissions.d.ts +0 -14
  352. package/dist/core/spaces/permissions.js +1 -1
  353. package/dist/core/spaces/stop.d.ts +13 -0
  354. package/dist/core/spaces/stop.js +2 -2
  355. package/dist/core/storage/tables.d.ts +1 -1
  356. package/dist/core/substrate/delivery/corpus.d.ts +21 -0
  357. package/dist/core/substrate/delivery/corpus.js +3 -0
  358. package/dist/core/substrate/delivery/deliver.d.ts +76 -0
  359. package/dist/core/substrate/delivery/deliver.js +6 -0
  360. package/dist/core/substrate/delivery/listings.d.ts +27 -0
  361. package/dist/core/substrate/delivery/listings.js +4 -0
  362. package/dist/core/substrate/delivery/match.d.ts +28 -0
  363. package/dist/core/substrate/delivery/match.js +1 -0
  364. package/dist/core/substrate/delivery/plan.d.ts +67 -0
  365. package/dist/core/substrate/delivery/plan.js +3 -0
  366. package/dist/core/substrate/delivery/render-boot.d.ts +20 -0
  367. package/dist/core/substrate/delivery/render-boot.js +54 -0
  368. package/dist/core/substrate/delivery/render-event.d.ts +47 -0
  369. package/dist/core/substrate/delivery/render-event.js +6 -0
  370. package/dist/core/substrate/delivery/sub-persona-menu.d.ts +2 -0
  371. package/dist/core/substrate/delivery/sub-persona-menu.js +6 -0
  372. package/dist/core/substrate/delivery/types.d.ts +30 -0
  373. package/dist/core/substrate/delivery/types.js +0 -0
  374. package/dist/core/substrate/gate-explain.d.ts +0 -13
  375. package/dist/core/substrate/gate-explain.js +1 -1
  376. package/dist/core/substrate/schema.d.ts +11 -139
  377. package/dist/core/substrate/schema.js +1 -1
  378. package/dist/core/substrate/subject-fields.d.ts +3 -0
  379. package/dist/core/substrate/subject.d.ts +2 -1
  380. package/dist/core/substrate/subject.js +1 -1
  381. package/dist/daemon/api/handlers/app-profiles.js +1 -1
  382. package/dist/daemon/api/handlers/bash-jobs.js +1 -2
  383. package/dist/daemon/api/handlers/broker-ops.js +1 -1
  384. package/dist/daemon/api/handlers/canvas.js +5 -5
  385. package/dist/daemon/api/handlers/daemon.js +1 -1
  386. package/dist/daemon/api/handlers/delivery.d.ts +2 -0
  387. package/dist/daemon/api/handlers/delivery.js +1 -0
  388. package/dist/daemon/api/handlers/{memory.d.ts → docs.d.ts} +1 -1
  389. package/dist/daemon/api/handlers/docs.js +1 -0
  390. package/dist/daemon/api/handlers/hook-exec.js +1 -1
  391. package/dist/daemon/api/handlers/messages.js +2 -2
  392. package/dist/daemon/api/handlers/node-records.js +2 -2
  393. package/dist/daemon/api/handlers/nodes.js +1 -1
  394. package/dist/daemon/api/handlers/objects.d.ts +2 -0
  395. package/dist/daemon/api/handlers/objects.js +5 -0
  396. package/dist/daemon/api/handlers/package-docs.d.ts +2 -0
  397. package/dist/daemon/api/handlers/package-docs.js +1 -0
  398. package/dist/daemon/api/handlers/profiles.js +1 -1
  399. package/dist/daemon/api/handlers/reports.d.ts +2 -2
  400. package/dist/daemon/api/handlers/reports.js +4 -4
  401. package/dist/daemon/api/handlers/reviews.js +1 -1
  402. package/dist/daemon/api/map.d.ts +2 -2
  403. package/dist/daemon/api/map.js +2 -2
  404. package/dist/daemon/api/operations.d.ts +1 -1
  405. package/dist/daemon/api/operations.js +1 -1
  406. package/dist/daemon/api/reader.d.ts +17 -0
  407. package/dist/daemon/api/reader.js +1 -0
  408. package/dist/daemon/api/server.js +1 -1
  409. package/dist/daemon/control.d.ts +2 -3
  410. package/dist/daemon/crtrd.js +8 -6
  411. package/dist/daemon/fleet.js +4 -4
  412. package/dist/daemon/reconcilers/bash-deadline.d.ts +11 -1
  413. package/dist/daemon/reconcilers/bash-deadline.js +2 -1
  414. package/dist/daemon/reconcilers/broker-supervision.js +4 -4
  415. package/dist/daemon/reconcilers/live-obligation.js +1 -1
  416. package/dist/daemon/reconcilers/node-deadline.js +1 -1
  417. package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
  418. package/dist/daemon/reconcilers/storage-maintenance.d.ts +1 -0
  419. package/dist/daemon/reconcilers/storage-maintenance.js +1 -1
  420. package/dist/daemon/review/deliver.js +2 -2
  421. package/dist/daemon/review/finish.js +1 -1
  422. package/dist/hook-authoring.d.ts +0 -1
  423. package/dist/hook-authoring.js +3 -3
  424. package/dist/migrations/004-canvas-documents/apply.d.ts +10 -0
  425. package/dist/migrations/004-canvas-documents/apply.js +1 -0
  426. package/dist/migrations/004-canvas-documents/fields.d.ts +24 -0
  427. package/dist/migrations/004-canvas-documents/fields.js +2 -0
  428. package/dist/migrations/004-canvas-documents/index.d.ts +16 -0
  429. package/dist/migrations/004-canvas-documents/index.js +2 -0
  430. package/dist/migrations/004-canvas-documents/legacy/discover.d.ts +16 -0
  431. package/dist/migrations/004-canvas-documents/legacy/discover.js +1 -0
  432. package/dist/migrations/004-canvas-documents/legacy/history.d.ts +5 -0
  433. package/dist/migrations/004-canvas-documents/legacy/history.js +2 -0
  434. package/dist/migrations/004-canvas-documents/legacy/nested.d.ts +7 -0
  435. package/dist/migrations/004-canvas-documents/legacy/nested.js +1 -0
  436. package/dist/migrations/004-canvas-documents/legacy/parse.d.ts +14 -0
  437. package/dist/migrations/004-canvas-documents/legacy/parse.js +1 -0
  438. package/dist/migrations/004-canvas-documents/legacy/types.d.ts +91 -0
  439. package/dist/migrations/004-canvas-documents/legacy/types.js +0 -0
  440. package/dist/migrations/004-canvas-documents/legacy-edges.d.ts +6 -0
  441. package/dist/migrations/004-canvas-documents/legacy-edges.js +18 -0
  442. package/dist/migrations/004-canvas-documents/plan.d.ts +102 -0
  443. package/dist/migrations/004-canvas-documents/plan.js +3 -0
  444. package/dist/migrations/004-canvas-documents/pointers.d.ts +23 -0
  445. package/dist/migrations/004-canvas-documents/pointers.js +4 -0
  446. package/dist/migrations/activation.d.ts +9 -18
  447. package/dist/migrations/activation.js +2 -2
  448. package/dist/pi-extensions/broker-local.d.ts +2 -2
  449. package/dist/pi-extensions/broker-local.js +2 -2
  450. package/dist/pi-extensions/canvas-bash-valve.js +5 -4
  451. package/dist/pi-extensions/canvas-context-intro.js +2 -2
  452. package/dist/pi-extensions/canvas-doc-substrate.d.ts +0 -1
  453. package/dist/pi-extensions/canvas-doc-substrate.js +6 -6
  454. package/dist/pi-extensions/canvas-inbox-watcher.js +2 -2
  455. package/dist/pi-extensions/canvas-passive-context.js +1 -1
  456. package/dist/pi-extensions/canvas-recap.js +2 -2
  457. package/dist/pi-extensions/canvas-stophook.d.ts +1 -1
  458. package/dist/pi-extensions/canvas-stophook.js +1 -1
  459. package/dist/prompts/review.js +3 -3
  460. package/dist/shared/env.d.ts +5 -0
  461. package/dist/shared/env.js +1 -1
  462. package/dist/shared/generated-context.js +2 -10
  463. package/dist/shared/inbox-entry-body.d.ts +22 -0
  464. package/dist/shared/inbox-entry-body.js +10 -0
  465. package/dist/{core/memory → shared}/inline-ref-guidance.d.ts +2 -2
  466. package/dist/shared/inline-ref-guidance.js +2 -0
  467. package/dist/types.d.ts +3 -1
  468. package/docs/cli/memory-and-preferences.md +12 -14
  469. package/docs/concepts/README.md +1 -1
  470. package/docs/concepts/lifecycle-and-wakes.md +1 -1
  471. package/docs/concepts/memory.md +15 -15
  472. package/docs/concepts/nodes-and-the-canvas.md +1 -1
  473. package/docs/concepts/profiles-kinds-and-modes.md +5 -5
  474. package/docs/concepts/scopes-and-trust.md +1 -1
  475. package/docs/concepts/why-a-daemon.md +1 -1
  476. package/docs/sdk/README.md +5 -6
  477. package/docs/sdk/errors.md +0 -13
  478. package/docs/sdk/guides/README.md +0 -1
  479. package/docs/sdk/nodes.md +0 -2
  480. package/docs/sdk/resources.md +0 -1
  481. package/package.json +2 -2
  482. package/packages/crouter-identity/package.json +1 -1
  483. package/runtime.lock.json +11 -11
  484. package/dist/api/dto/memory.d.ts +0 -171
  485. package/dist/api/dto/memory.js +0 -1
  486. package/dist/builtin-memory/crouter-sdk/guides/app-memory.md +0 -73
  487. package/dist/builtin-memory/crouter-sdk/memory.md +0 -87
  488. package/dist/commands/broker-permissions.d.ts +0 -2
  489. package/dist/commands/broker-permissions.js +0 -1
  490. package/dist/commands/memory/client.d.ts +0 -11
  491. package/dist/commands/memory/client.js +0 -1
  492. package/dist/commands/memory/delete.d.ts +0 -1
  493. package/dist/commands/memory/delete.js +0 -1
  494. package/dist/commands/memory/edit.d.ts +0 -1
  495. package/dist/commands/memory/edit.js +0 -21
  496. package/dist/commands/memory/find.d.ts +0 -1
  497. package/dist/commands/memory/find.js +0 -1
  498. package/dist/commands/memory/history.d.ts +0 -1
  499. package/dist/commands/memory/history.js +0 -5
  500. package/dist/commands/memory/lint.d.ts +0 -1
  501. package/dist/commands/memory/lint.js +0 -1
  502. package/dist/commands/memory/list.d.ts +0 -1
  503. package/dist/commands/memory/list.js +0 -1
  504. package/dist/commands/memory/move.d.ts +0 -1
  505. package/dist/commands/memory/move.js +0 -1
  506. package/dist/commands/memory/origin.d.ts +0 -1
  507. package/dist/commands/memory/origin.js +0 -1
  508. package/dist/commands/memory/read.d.ts +0 -1
  509. package/dist/commands/memory/read.js +0 -6
  510. package/dist/commands/memory/shared.d.ts +0 -22
  511. package/dist/commands/memory/shared.js +0 -1
  512. package/dist/commands/memory/write.d.ts +0 -1
  513. package/dist/commands/memory/write.js +0 -13
  514. package/dist/commands/memory.js +0 -1
  515. package/dist/commands/node-inspect-artifacts.d.ts +0 -1
  516. package/dist/commands/node-inspect-artifacts.js +0 -8
  517. package/dist/core/help/memory-extensions.d.ts +0 -3
  518. package/dist/core/help/memory-extensions.js +0 -2
  519. package/dist/core/memory/cli-selector.d.ts +0 -13
  520. package/dist/core/memory/cli-selector.js +0 -1
  521. package/dist/core/memory/doc-link-grammar.d.ts +0 -20
  522. package/dist/core/memory/doc-link-grammar.js +0 -2
  523. package/dist/core/memory/extensions.js +0 -1
  524. package/dist/core/memory/history.d.ts +0 -87
  525. package/dist/core/memory/history.js +0 -6
  526. package/dist/core/memory/identity.d.ts +0 -65
  527. package/dist/core/memory/identity.js +0 -1
  528. package/dist/core/memory/inline-ref-guidance.js +0 -2
  529. package/dist/core/memory/inline-ref-inventory.d.ts +0 -9
  530. package/dist/core/memory/inline-ref-inventory.js +0 -1
  531. package/dist/core/memory/lint.d.ts +0 -163
  532. package/dist/core/memory/lint.js +0 -2
  533. package/dist/core/memory/mutation-domain.d.ts +0 -113
  534. package/dist/core/memory/mutation-domain.js +0 -12
  535. package/dist/core/memory/mutations.d.ts +0 -74
  536. package/dist/core/memory/mutations.js +0 -1
  537. package/dist/core/memory/project-namespace.d.ts +0 -31
  538. package/dist/core/memory/project-namespace.js +0 -2
  539. package/dist/core/memory/repository-association.d.ts +0 -31
  540. package/dist/core/memory/repository-association.js +0 -1
  541. package/dist/core/memory/service.d.ts +0 -145
  542. package/dist/core/memory/service.js +0 -2
  543. package/dist/core/memory/tree.d.ts +0 -39
  544. package/dist/core/memory/tree.js +0 -1
  545. package/dist/core/memory-resolver.d.ts +0 -280
  546. package/dist/core/memory-resolver.js +0 -2
  547. package/dist/core/nested-stores.d.ts +0 -18
  548. package/dist/core/nested-stores.js +0 -1
  549. package/dist/core/runtime/memory.d.ts +0 -3
  550. package/dist/core/runtime/memory.js +0 -1
  551. package/dist/core/substrate/frontmatter-validation.d.ts +0 -11
  552. package/dist/core/substrate/frontmatter-validation.js +0 -1
  553. package/dist/core/substrate/gate.d.ts +0 -16
  554. package/dist/core/substrate/gate.js +0 -1
  555. package/dist/core/substrate/index.d.ts +0 -18
  556. package/dist/core/substrate/index.js +0 -1
  557. package/dist/core/substrate/injected-store.d.ts +0 -75
  558. package/dist/core/substrate/injected-store.js +0 -2
  559. package/dist/core/substrate/listings.d.ts +0 -28
  560. package/dist/core/substrate/listings.js +0 -1
  561. package/dist/core/substrate/memory-events.d.ts +0 -6
  562. package/dist/core/substrate/memory-events.js +0 -1
  563. package/dist/core/substrate/on-read-node.d.ts +0 -6
  564. package/dist/core/substrate/on-read-node.js +0 -1
  565. package/dist/core/substrate/on-read.d.ts +0 -101
  566. package/dist/core/substrate/on-read.js +0 -9
  567. package/dist/core/substrate/plan.d.ts +0 -94
  568. package/dist/core/substrate/plan.js +0 -1
  569. package/dist/core/substrate/render-node.d.ts +0 -12
  570. package/dist/core/substrate/render-node.js +0 -1
  571. package/dist/core/substrate/render.d.ts +0 -41
  572. package/dist/core/substrate/render.js +0 -65
  573. package/dist/core/substrate/session-cache.d.ts +0 -27
  574. package/dist/core/substrate/session-cache.js +0 -1
  575. package/dist/core/substrate/surface-match.d.ts +0 -73
  576. package/dist/core/substrate/surface-match.js +0 -1
  577. package/dist/daemon/api/handlers/memory.js +0 -5
  578. package/dist/migrations/001-surfaces-frontmatter.d.ts +0 -2
  579. package/dist/migrations/001-surfaces-frontmatter.js +0 -1
  580. package/dist/migrations/002-profile-project-memory.d.ts +0 -2
  581. package/dist/migrations/002-profile-project-memory.js +0 -1
  582. package/dist/migrations/003-repository-root-memory-identity/front-door.d.ts +0 -26
  583. package/dist/migrations/003-repository-root-memory-identity/front-door.js +0 -11
  584. package/dist/migrations/003-repository-root-memory-identity/index.d.ts +0 -2
  585. package/dist/migrations/003-repository-root-memory-identity/index.js +0 -5
  586. package/dist/migrations/003-repository-root-memory-identity/references.d.ts +0 -95
  587. package/dist/migrations/003-repository-root-memory-identity/references.js +0 -5
  588. package/dist/migrations/003-repository-root-memory-identity/repository-facts.d.ts +0 -39
  589. package/dist/migrations/003-repository-root-memory-identity/repository-facts.js +0 -3
  590. package/dist/migrations/convergent.d.ts +0 -43
  591. package/dist/migrations/convergent.js +0 -2
  592. package/dist/migrations/corpus.d.ts +0 -75
  593. package/dist/migrations/corpus.js +0 -3
  594. package/dist/migrations/frontmatter-splice.d.ts +0 -15
  595. package/dist/migrations/frontmatter-splice.js +0 -8
  596. package/dist/migrations/profile-manifests.d.ts +0 -30
  597. package/dist/migrations/profile-manifests.js +0 -2
  598. package/dist/migrations/registry.d.ts +0 -7
  599. package/dist/migrations/registry.js +0 -1
  600. package/dist/migrations/runner.d.ts +0 -43
  601. package/dist/migrations/runner.js +0 -1
  602. package/dist/migrations/types.d.ts +0 -211
  603. package/dist/shared/birth-announcement.d.ts +0 -12
  604. package/dist/shared/birth-announcement.js +0 -1
  605. package/docs/sdk/guides/app-memory.md +0 -22
  606. package/docs/sdk/memory.md +0 -85
  607. /package/dist/{migrations/types.js → api/dto/delivery.js} +0 -0
  608. /package/dist/{core/memory → shared}/inline-ref-grammar.d.ts +0 -0
  609. /package/dist/{core/memory → shared}/inline-ref-grammar.js +0 -0
@@ -0,0 +1,4 @@
1
+ var S=Object.defineProperty;var a=(n,e)=>S(n,"name",{value:e,configurable:!0});const p={name:1,preview:2,content:3},O=["system","transcript"],E=new WeakMap;function j(n){return{node:n.node,preferenceSnapshot:n.preferenceSnapshot,objects:new Map([...n.objects].map(([e,t])=>[e,{...t}])),listed:new Map([...n.listed].map(([e,t])=>[e,{...t}]))}}a(j,"cloneLedger");function _(n){return{node:n,preferenceSnapshot:null,objects:new Map,listed:new Map}}a(_,"emptyLedger");function y(n,e){const t=_(e),s=n.prepare("SELECT preference_snapshot, listed_json FROM context_sessions WHERE node = ?").get(e);if(s!==void 0){t.preferenceSnapshot=s.preference_snapshot;for(const[o,c]of Object.entries(JSON.parse(s.listed_json)))t.listed.set(o,c)}const r=n.prepare("SELECT object, channel, level, heads_key, content_hash FROM exposures WHERE node = ?").all(e);for(const o of r){const c=t.objects.get(o.object)??{headsKey:o.heads_key,contentHash:o.content_hash};c[o.channel]=o.level,t.objects.set(o.object,c)}return E.set(t,j(t)),t}a(y,"loadLedger");function N(n,e){const t=E.get(e)??_(e.node),s=JSON.stringify(Object.fromEntries(e.listed));(e.preferenceSnapshot!==t.preferenceSnapshot||s!==JSON.stringify(Object.fromEntries(t.listed)))&&n.prepare(`INSERT INTO context_sessions (node, preference_snapshot, listed_json) VALUES (?, ?, ?)
2
+ ON CONFLICT(node) DO UPDATE SET preference_snapshot = excluded.preference_snapshot, listed_json = excluded.listed_json`).run(e.node,e.preferenceSnapshot,s);const r=n.prepare(`INSERT INTO exposures (node, object, channel, level, heads_key, content_hash) VALUES (?, ?, ?, ?, ?, ?)
3
+ ON CONFLICT(node, object, channel) DO UPDATE SET level = excluded.level, heads_key = excluded.heads_key, content_hash = excluded.content_hash`),o=n.prepare("DELETE FROM exposures WHERE node = ? AND object = ? AND channel = ?"),c=new Set([...t.objects.keys(),...e.objects.keys()]);for(const i of c){const f=e.objects.get(i),u=t.objects.get(i);for(const d of O){const h=f?.[d];h===void 0?u?.[d]!==void 0&&o.run(e.node,i,d):(h!==u?.[d]||f.headsKey!==u?.headsKey||f.contentHash!==u?.contentHash)&&r.run(e.node,i,d,h,f.headsKey,f.contentHash)}}E.set(e,j(e))}a(N,"saveLedger");function T(n,e){return n.prepare("SELECT 1 FROM context_sessions WHERE node = ? UNION ALL SELECT 1 FROM exposures WHERE node = ? LIMIT 1").get(e,e)!==void 0}a(T,"hasLedger");function b(n,e){n.prepare("DELETE FROM exposures WHERE node = ?").run(e),n.prepare("DELETE FROM context_sessions WHERE node = ?").run(e)}a(b,"clearLedger");function x(n,e,t){b(n,t),n.prepare(`INSERT INTO exposures (node, object, channel, level, heads_key, content_hash)
4
+ SELECT ?, object, channel, level, heads_key, content_hash FROM exposures WHERE node = ? AND channel = 'transcript'`).run(t,e);const s=n.prepare("SELECT listed_json FROM context_sessions WHERE node = ?").get(e);if(s===void 0)return;const r={};for(const[o,c]of Object.entries(JSON.parse(s.listed_json)))c.transcript!==void 0&&(r[o]={transcript:c.transcript});n.prepare("INSERT INTO context_sessions (node, preference_snapshot, listed_json) VALUES (?, NULL, ?)").run(t,JSON.stringify(r))}a(x,"forkLedger");function l(n,e){if(n===void 0)return 0;const t=a(s=>n[s]!==void 0?p[n[s]]:0,"of");return e!==void 0?t(e):Math.max(t("system"),t("transcript"))}a(l,"rankIn");function H(n,e,t,s){const r=p[t],o=n.objects.get(e.object);if(o!==void 0&&l(o,s)>=r&&(t!=="content"||o.headsKey===e.headsKey))return!0;if(e.contentHash===null)return!1;for(const c of n.objects.values())if(c.contentHash===e.contentHash&&l(c,s)>=r)return!0;return!1}a(H,"heldAtOrAbove");function R(n,e,t,s){const r=n.objects.get(t.object),o=r!==void 0&&r.headsKey===t.headsKey&&r.contentHash===t.contentHash,c=o?{...r}:{headsKey:t.headsKey,contentHash:t.contentHash},i=o?r[e]:void 0;c[e]=i!==void 0&&p[i]>=p[s]?i:s,n.objects.set(t.object,c)}a(R,"hold");function M(n,e,t,s){return l(n.listed.get(e),s)>=p[t]}a(M,"listedAtOrAbove");function m(n,e,t,s){const r=n.listed.get(t)??{},o=r[e];o!==void 0&&p[o]>=p[s]||n.listed.set(t,{...r,[e]:s})}a(m,"holdListing");function A(n,e){const t=n.objects.get(e);if(t!==void 0)for(const[s,r]of n.objects){if(s!==e&&(t.contentHash===null||r.contentHash!==t.contentHash))continue;const{transcript:o,...c}=r;c.system===void 0?n.objects.delete(s):n.objects.set(s,c)}}a(A,"demoteTranscript");function v(n,e){return n.preferenceSnapshot===null&&(n.preferenceSnapshot=e),n.preferenceSnapshot}a(v,"freezePreferences");function I(n){return[...n.objects.values()].some(e=>e.transcript!==void 0)||[...n.listed.values()].some(e=>e.transcript!==void 0)}a(I,"hasTranscript");export{b as clearLedger,A as demoteTranscript,x as forkLedger,v as freezePreferences,T as hasLedger,I as hasTranscript,H as heldAtOrAbove,R as hold,m as holdListing,M as listedAtOrAbove,y as loadLedger,N as saveLedger};
@@ -0,0 +1,31 @@
1
+ /** Jobs: a backgrounded bash command as an object the node that started it owns, with its
2
+ * `jobs` row and the events of its start and end. Runs in the caller's transaction. */
3
+ import type { DatabaseSync } from 'node:sqlite';
4
+ import type { ObjectRow } from './types.js';
5
+ export type JobStatus = 'running' | 'exited' | 'killed';
6
+ export interface JobRow {
7
+ object: number;
8
+ command: string;
9
+ status: JobStatus;
10
+ exit_code: number | null;
11
+ job_dir: string;
12
+ log_path: string;
13
+ }
14
+ export declare function jobRow(db: DatabaseSync, job: ObjectRow): JobRow | null;
15
+ /** Create the job object (`id` keeps the job id the runner already uses), its `running` row,
16
+ * the node's acted-on edge and `job-start` watch, and publish `created`. */
17
+ export declare function startJob(db: DatabaseSync, node: ObjectRow, spec: {
18
+ id?: string;
19
+ command: string;
20
+ jobDir: string;
21
+ logPath: string;
22
+ }): ObjectRow;
23
+ /** End a running job: `exited` with its exit code, or `killed` with the killer as actor (null
24
+ * when the runtime killed it, e.g. at its deadline; `reason` then names why). The event carries
25
+ * the exit code and log path, never output. A job already ended is left as is. */
26
+ export declare function finishJob(db: DatabaseSync, job: ObjectRow, end: {
27
+ exitCode: number;
28
+ } | {
29
+ killedBy: ObjectRow | null;
30
+ reason?: string;
31
+ }): ObjectRow;
@@ -0,0 +1,2 @@
1
+ var w=Object.defineProperty;var n=(t,r)=>w(t,"name",{value:r,configurable:!0});import{recordActedOn as s}from"./edges.js";import{levelFor as u,publish as d}from"./events.js";import{createObject as E,getByRowid as h}from"./objects.js";import{recordWatch as b}from"./watches.js";function p(t){return t.split(`
2
+ `,1)[0].trim()}n(p,"firstLine");function m(t,r){return`${p(t)} (${r})`}n(m,"previewOf");function j(t,r){return t.prepare("SELECT * FROM jobs WHERE object = ?").get(r.rowid)??null}n(j,"jobRow");function R(t,r,o){if(r.type!=="node")throw new Error(`startJob: ${r.id} is a ${r.type}, not a node`);const e=E(t,{...o.id===void 0?{}:{id:o.id},type:"job",kind:"bash",owner:r.rowid,privacy:"public",name:p(o.command)||"bash",preview:m(o.command,"running")});return t.prepare("INSERT INTO jobs (object, command, status, exit_code, job_dir, log_path) VALUES (?, ?, 'running', NULL, ?, ?)").run(e.rowid,o.command,o.jobDir,o.logPath),s(t,r,e),b(t,r,e,"job-start"),d(t,{event:"created",object:e,actor:r,level:u("created"),attrs:{}}),e}n(R,"startJob");function T(t,r,o){const e=j(t,r);if(e===null)throw new Error(`finishJob: ${r.id} has no jobs row`);if(e.status!=="running")return r;const i="killedBy"in o,a=i?"killed":"exited",l=i?null:o.exitCode;t.prepare("UPDATE jobs SET status = ?, exit_code = ? WHERE object = ?").run(a,l,r.rowid);const f=i?"killed":`exited ${l}`;t.prepare("UPDATE objects SET preview = ? WHERE rowid = ?").run(m(e.command,f),r.rowid);const c=h(t,r.rowid);return i&&o.killedBy!==null&&s(t,o.killedBy,c),d(t,{event:a,object:c,actor:i?o.killedBy:null,level:u(a),attrs:i?{"log-path":e.log_path,...o.reason===void 0?{}:{reason:o.reason}}:{"exit-code":l,"log-path":e.log_path}}),c}n(T,"finishJob");export{T as finishJob,j as jobRow,R as startJob};
@@ -0,0 +1,28 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import type { ObjectRow, Reader } from './types.js';
3
+ export type Resolution = {
4
+ object: ObjectRow;
5
+ } | {
6
+ deleted: ObjectRow;
7
+ } | {
8
+ remote: string;
9
+ } | {
10
+ ambiguous: ObjectRow[];
11
+ } | {
12
+ missing: true;
13
+ };
14
+ /** The owners a bare name is looked up under, in order: own node, repos nearest
15
+ * first, profile, app, you, then the apps whose tools the run may use (installed
16
+ * plugins) with `crtr` last. */
17
+ export declare function viewOf(db: DatabaseSync, reader: Reader): ObjectRow[];
18
+ /** The owner types that carry a handle; `<type>:<handle>/<name>` names one exactly. */
19
+ export declare const HANDLE_TYPES: readonly ["person", "app", "repo", "profile"];
20
+ /** Every owner a handle names: a node by id, and each handle-carrying owner type
21
+ * holding that handle (handles are unique per type, not across types). */
22
+ export declare function ownersByHandle(db: DatabaseSync, handle: string, type?: string): ObjectRow[];
23
+ /** `name` may be wrapped in `[[ ]]`, a raw object id, a bare document name,
24
+ * `<owner handle>/<name>`, or `<type>:<owner handle>/<name>`. Under a handle
25
+ * several owner types share, owners in the reader's view come first in view
26
+ * order; otherwise exactly one holder wins and more are `ambiguous`. Anything
27
+ * the reader cannot read answers `missing`. */
28
+ export declare function resolveName(db: DatabaseSync, reader: Reader, raw: string): Resolution;
@@ -0,0 +1,3 @@
1
+ var L=Object.defineProperty;var a=(e,t)=>L(e,"name",{value:t,configurable:!0});import{isSafeNodeId as O}from"../canvas/paths.js";import{canRead as S,toolApps as j}from"./access.js";import{getById as x}from"./objects.js";function I(e,t){const r=e.prepare("SELECT * FROM objects WHERE type = 'person' AND name = 'user'").get(),o=j(e,t),u=t.class==="node"?[t.node,...t.repos,t.profile,t.app]:t.class==="app"?[t.app]:[],s=new Set;return[...u,r,...o].filter(i=>!!i&&!s.has(i.rowid)&&!!s.add(i.rowid))}a(I,"viewOf");function d(e,t,r,o){return e.prepare(`SELECT * FROM objects WHERE type = 'document' AND owner = ? AND name = ?
2
+ AND deleted_at IS ${o?"NOT NULL ORDER BY deleted_at DESC":"NULL"}`).all(t.rowid,r)}a(d,"documentsNamed");const C=["person","app","repo","profile"],g=/^(person|app|repo|profile|node):([^/]+)\/(.+)$/;function T(e,t,r){return r==="node"?e.prepare("SELECT * FROM objects WHERE type = 'node' AND id = ?").all(t):r?e.prepare("SELECT * FROM objects WHERE type = ? AND name = ?").all(r,t):e.prepare(`SELECT * FROM objects WHERE (type = 'node' AND id = ?)
3
+ OR (type IN ('person','app','repo','profile') AND name = ?)`).all(t,t)}a(T,"ownersByHandle");function F(e,t,r){let o=r.trim().replace(/^\[\[(.*)\]\]$/,"$1").trim();const u=/^([^:/]+):reports\/(.+?)(?:\.md)?$/.exec(o);u&&!g.test(o)&&(o=`${u[1]}/reports/${u[2]}`);const s=a(c=>S(e,t,c),"readable"),i=x(e,o);if(i&&s(i))return i.deleted_at?{deleted:i}:{object:i};const N=I(e,t);for(const c of N){const p=d(e,c,o,!1).find(s);if(p)return{object:p}}const f=g.exec(o),w=o.indexOf("/");if(f||w>0){const c=f?f[2]:o.slice(0,w),p=f?f[3]:o.slice(w+1),E=T(e,c,f?.[1]),R=a(n=>{const l=N.findIndex(A=>A.rowid===n.rowid);return l<0?1/0:l},"rank"),y=E.filter(n=>R(n)<1/0).sort((n,l)=>R(n)-R(l));for(const n of y){const l=d(e,n,p,!1).find(s);if(l)return{object:l}}const m=E.flatMap(n=>d(e,n,p,!1)).filter(s);if(m.length===1)return{object:m[0]};if(m.length>1)return{ambiguous:m};const D=E.flatMap(n=>d(e,n,p,!0)).find(s);return D?{deleted:D}:!f&&E.length===0&&O(c)?{remote:o}:{missing:!0}}for(const c of N){const p=d(e,c,o,!0).find(s);if(p)return{deleted:p}}return{missing:!0}}a(F,"resolveName");export{C as HANDLE_TYPES,T as ownersByHandle,F as resolveName,I as viewOf};
@@ -0,0 +1,55 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import type { ObjectRow, ObjectType, Privacy, Reader } from './types.js';
3
+ export declare function getById(db: DatabaseSync, id: string): ObjectRow | null;
4
+ export declare function getByRowid(db: DatabaseSync, rowid: number): ObjectRow | null;
5
+ export declare function createObject(db: DatabaseSync, spec: {
6
+ id?: string;
7
+ type: ObjectType;
8
+ kind: string | null;
9
+ owner: number | null;
10
+ privacy: Privacy;
11
+ name: string;
12
+ preview: string;
13
+ }): ObjectRow;
14
+ /** The owner object for an identity, created on first sight. Idempotent on
15
+ * (scheme, externalId). Handles are unique per owner type: a handle already held
16
+ * by a different identity of the same type throws `conflict` naming both; it is
17
+ * never renamed silently. */
18
+ export declare function ensureOwner(db: DatabaseSync, type: ObjectType, scheme: string, externalId: string, handle: string, owner?: ObjectRow): ObjectRow;
19
+ /** The owner object of a node grantee: `user:local` → person `user`; `app:<x>` → app `<x>`. */
20
+ export declare function ownerForGrantee(db: DatabaseSync, grantee: string): ObjectRow;
21
+ /** The owner's live document named `name`, or null. */
22
+ export declare function liveDocumentNamed(db: DatabaseSync, owner: number, name: string): ObjectRow | null;
23
+ export declare function nodeObject(db: DatabaseSync, nodeId: string): ObjectRow;
24
+ export declare function setObjectName(db: DatabaseSync, object: ObjectRow, name: string): void;
25
+ export declare function setObjectKind(db: DatabaseSync, object: ObjectRow, kind: string | null): void;
26
+ export interface ObjectFilter {
27
+ type?: ObjectType;
28
+ kind?: string;
29
+ owner?: ObjectRow;
30
+ privacy?: Privacy;
31
+ name?: string;
32
+ deleted?: boolean;
33
+ }
34
+ export interface Page {
35
+ limit?: number;
36
+ after_rowid?: number;
37
+ }
38
+ /** Objects the reader can read, in rowid order. Records nothing. `limit` ≤ 100. */
39
+ export declare function listObjects(db: DatabaseSync, reader: Reader, filter: ObjectFilter, page?: Page): ObjectRow[];
40
+ export interface SearchQuery {
41
+ text: string;
42
+ body?: boolean;
43
+ grep?: boolean;
44
+ }
45
+ export interface SearchHit {
46
+ object: ObjectRow;
47
+ field: 'name' | 'preview' | 'summary' | 'body';
48
+ line?: number;
49
+ text?: string;
50
+ }
51
+ /** Up to 100 hits over live objects the reader can read. Records nothing. `text`
52
+ * matches name, preview and document summary as a substring; `body` also scans
53
+ * each document's head bodies for the substring, and `grep` scans them for `text`
54
+ * as a regular expression. Body search reads every readable body: linear, no index. */
55
+ export declare function searchObjects(db: DatabaseSync, reader: Reader, query: SearchQuery): SearchHit[];
@@ -0,0 +1,9 @@
1
+ var S=Object.defineProperty;var s=(o,e)=>S(o,"name",{value:e,configurable:!0});import{CrtrError as L,notFound as j}from"../errors.js";import{ExitCode as b}from"../../types.js";import{newNodeId as T}from"../runtime/nodes.js";import{canRead as l}from"./access.js";import{bodyOf as x}from"./bodies.js";const y=new Set(["person","app","repo","profile"]);function h(o){return o||null}s(h,"rowFrom");function I(o,e){return h(o.prepare("SELECT * FROM objects WHERE id = ?").get(e))}s(I,"getById");function W(o,e){return h(o.prepare("SELECT * FROM objects WHERE rowid = ?").get(e))}s(W,"getByRowid");function _(o,e){return o.prepare(`INSERT INTO objects (id, type, kind, owner, privacy, name, preview, created_at)
2
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`).get(e.id??T(),e.type,e.kind,e.owner,e.privacy,e.name,e.preview,new Date().toISOString())}s(_,"createObject");function R(o,e,t,p,r,n){if(!y.has(e))throw new Error(`ensureOwner: ${e} is not an owner type`);const a=o.prepare(`SELECT o.* FROM identities i JOIN objects o ON o.rowid = i.object
3
+ WHERE i.scheme = ? AND i.external_id = ?`).get(t,p);if(a)return a;const c=o.prepare(`SELECT o.id, o.type, i.scheme, i.external_id FROM objects o
4
+ LEFT JOIN identities i ON i.object = o.rowid
5
+ WHERE o.name = ? AND o.type = ?`).get(r,e);if(c)throw new L("conflict",`handle "${r}" is held by ${c.type} ${c.id} (${c.scheme}:${c.external_id}); cannot give it to ${e} ${t}:${p}`,b.GENERAL,{handle:r,holder:c.id});const d=_(o,{type:e,kind:null,owner:e==="profile"?n?.rowid??null:null,privacy:"public",name:r,preview:""});return o.prepare("INSERT INTO identities (object, scheme, external_id) VALUES (?, ?, ?)").run(d.rowid,t,p),d}s(R,"ensureOwner");function H(o,e){if(e==="user:local")return R(o,"person","local-user",e,"user");if(/^app:[a-z0-9][a-z0-9._-]*$/.test(e))return R(o,"app","app",e,e.slice(4));throw new Error(`node grantee ${JSON.stringify(e)} is neither app:<name> nor user:local`)}s(H,"ownerForGrantee");function M(o,e,t){return h(o.prepare("SELECT * FROM objects WHERE type = 'document' AND owner = ? AND name = ? AND deleted_at IS NULL").get(e,t))}s(M,"liveDocumentNamed");function U(o,e){const t=I(o,e);if(!t||t.type!=="node")throw j(`no node object ${e}`);return t}s(U,"nodeObject");function k(o,e,t){o.prepare("UPDATE objects SET name = ? WHERE rowid = ?").run(t,e.rowid)}s(k,"setObjectName");function P(o,e,t){o.prepare("UPDATE objects SET kind = ? WHERE rowid = ?").run(t,e.rowid)}s(P,"setObjectKind");function B(o,e,t,p={}){const r=["rowid > ?"],n=[p.after_rowid??0];return t.type!==void 0&&(r.push("type = ?"),n.push(t.type)),t.kind!==void 0&&(r.push("kind = ?"),n.push(t.kind)),t.owner!==void 0&&(r.push("owner = ?"),n.push(t.owner.rowid)),t.privacy!==void 0&&(r.push("privacy = ?"),n.push(t.privacy)),t.name!==void 0&&(r.push("name = ?"),n.push(t.name)),r.push(t.deleted?"deleted_at IS NOT NULL":"deleted_at IS NULL"),g(o,e,`SELECT * FROM objects WHERE ${r.join(" AND ")}`,n,Math.min(p.limit??100,100))}s(B,"listObjects");function J(o,e,t){const r=[],n=`%${t.text.replace(/[\\%_]/g,i=>`\\${i}`)}%`;if(!t.grep){const i=o.prepare(`SELECT o.*, d.summary AS _summary FROM objects o LEFT JOIN documents d ON d.object = o.rowid
6
+ WHERE o.deleted_at IS NULL AND (o.name LIKE ?1 ESCAPE '\\' OR o.preview LIKE ?1 ESCAPE '\\' OR d.summary LIKE ?1 ESCAPE '\\')
7
+ ORDER BY o.rowid`).all(n),u=t.text.toLowerCase();for(const m of i){const{_summary:w,...E}=m,f=E;if(!l(o,e,f))continue;const O=f.name.toLowerCase().includes(u)?"name":f.preview.toLowerCase().includes(u)?"preview":"summary";if(r.push({object:f,field:O,...O==="summary"?{text:String(w)}:{}}),r.length>=100)return r}}if(!t.body&&!t.grep)return r;const a=new Set(r.map(i=>i.object.rowid)),c=t.grep?(i=>u=>i.test(u))(new RegExp(t.text)):i=>i.includes(t.text),d=o.prepare("SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL ORDER BY rowid").all(),N=o.prepare(`SELECT r.body_hash, d.source_path FROM revisions r JOIN documents d ON d.object = r.document WHERE r.document = ?
8
+ AND NOT EXISTS (SELECT 1 FROM revision_parents p WHERE p.parent = r.rowid)`);for(const i of d)if(!(a.has(i.rowid)||!l(o,e,i)))for(const{body_hash:u,source_path:m}of N.all(i.rowid)){const w=x(u,m).split(`
9
+ `),E=w.findIndex(c);if(!(E<0)){if(r.push({object:i,field:"body",line:E+1,text:w[E]}),r.length>=100)return r;break}}return r}s(J,"searchObjects");function g(o,e,t,p,r){const n=[],a=o.prepare(`${t} ORDER BY rowid LIMIT ${r*4}`);for(;;){const c=a.all(...p);for(const d of c)if(l(o,e,d)&&n.push(d),n.length===r)return n;if(c.length<r*4)return n;p[0]=c[c.length-1].rowid}}s(g,"readablePages");export{_ as createObject,R as ensureOwner,I as getById,W as getByRowid,B as listObjects,M as liveDocumentNamed,U as nodeObject,H as ownerForGrantee,J as searchObjects,P as setObjectKind,k as setObjectName};
@@ -0,0 +1,31 @@
1
+ /** Package documents: builtin (`crtr`) and plugin documents stay files in their package; this
2
+ * converges their `objects`/`documents` rows, their one revision and their rules onto those
3
+ * files (contract §6.6). Bodies are read from `documents.source_path`, never the body store.
4
+ * A plugin is an app: its documents belong to the app `<plugin>` (identity `app:<plugin>`,
5
+ * the one `ownerForGrantee` gives), and a document with a `source_path` is shipped. */
6
+ import type { DatabaseSync } from 'node:sqlite';
7
+ export interface PackageSource {
8
+ plugin: string;
9
+ dir: string;
10
+ }
11
+ /** The builtin corpus (app `crtr`), then every enabled user-scope plugin's `memory/` folder. */
12
+ export declare function packageSources(): PackageSource[];
13
+ export interface PackageReconcileReport {
14
+ created: number;
15
+ updated: number;
16
+ deleted: number;
17
+ /** plugins provided by more than one package; only the first is reconciled */
18
+ conflicts: Array<{
19
+ plugin: string;
20
+ message: string;
21
+ }>;
22
+ invalid: Array<{
23
+ path: string;
24
+ error: string;
25
+ }>;
26
+ }
27
+ /** Converge every package's documents onto its files. Run inside the caller's transaction.
28
+ * Idempotent: a second run over unchanged files writes nothing. A changed body replaces the
29
+ * document's single revision and publishes `edited`; a vanished file (or plugin) marks its
30
+ * document deleted and publishes `deleted`. */
31
+ export declare function reconcilePackageDocuments(db: DatabaseSync, sources?: readonly PackageSource[]): PackageReconcileReport;
@@ -0,0 +1,5 @@
1
+ var D=Object.defineProperty;var p=(e,s)=>D(e,"name",{value:s,configurable:!0});import{createHash as O,randomUUID as I}from"node:crypto";import{CrtrError as w}from"../errors.js";import{listInstalledPlugins as v}from"../resolver.js";import{builtinMemoryRoot as A,pluginMemoryDir as _}from"../scope.js";import{documentFields as L}from"../../migrations/004-canvas-documents/fields.js";import{applyDocumentFields as T,deleteDocument as x,documentRecord as R,heads as j,importDocument as k,moveDocument as U}from"./documents.js";import{publish as F}from"./events.js";import{packageFiles as J}from"./package-files.js";import{ensureOwner as b,getByRowid as y,setObjectKind as C}from"./objects.js";import{reposForCwd as H}from"./repo-sync/repos.js";import{rulesOf as W}from"./rules.js";function M(){return[{plugin:"crtr",dir:A()},...v("user").filter(e=>e.enabled).map(e=>({plugin:e.name,dir:_(e)}))]}p(M,"packageSources");const P=p(e=>O("sha256").update(e,"utf8").digest("hex"),"sha256");function te(e,s=M()){const t={created:0,updated:0,deleted:0,conflicts:[],invalid:[]},c=p(r=>H(e,r),"reposFn"),l=new Set,n=new Set;for(const r of s){let o;try{if(n.has(r.plugin))throw new w("conflict",`plugin "${r.plugin}" is already provided by another package`);n.add(r.plugin),o=b(e,"app","app",`app:${r.plugin}`,r.plugin)}catch(a){if(!(a instanceof w)||a.code!=="conflict")throw a;t.conflicts.push({plugin:r.plugin,message:a.message});continue}l.add(o.rowid);const{files:f,invalid:m}=J(r.dir);t.invalid.push(...m);const d=new Set;for(const a of f)d.add(K(e,o,a,t,c));E(e,o,d,t,c)}const i=e.prepare(`SELECT DISTINCT o.owner AS rowid FROM objects o JOIN documents d ON d.object = o.rowid
2
+ WHERE o.type = 'document' AND o.deleted_at IS NULL AND d.source_path IS NOT NULL`).all();for(const{rowid:r}of i)l.has(r)||E(e,y(e,r),new Set,t,c);return t}p(te,"reconcilePackageDocuments");function K(e,s,t,c,l){const n=L(t.frontmatter,t.body,{missingPrivacy:"public"}),i={preview:n.preview.trim()===""?t.name:n.preview,summary:n.summary,whyItExists:n.whyItExists,unlisted:n.unlisted,rules:n.rules,lintIgnore:Array.isArray(n.lintIgnore)?n.lintIgnore.filter(u=>typeof u=="string"):null,extensions:n.extensions!==null&&typeof n.extensions=="object"&&!Array.isArray(n.extensions)?n.extensions:null},r=P(t.body);let o=e.prepare(`SELECT o.* FROM objects o JOIN documents d ON d.object = o.rowid
3
+ WHERE o.type = 'document' AND o.owner = ? AND o.deleted_at IS NULL AND d.source_path = ?`).get(s.rowid,t.path);if(o||(o=e.prepare(`SELECT o.* FROM objects o JOIN documents d ON d.object = o.rowid
4
+ WHERE o.type = 'document' AND o.owner = ? AND o.deleted_at IS NULL AND o.name = ? AND d.source_path IS NOT NULL`).get(s.rowid,t.name),o&&e.prepare("UPDATE documents SET source_path = ? WHERE object = ?").run(t.path,o.rowid)),!o){const u=k(e,{owner:s,name:t.name,kind:n.kind,privacy:"public",...i,revisions:[{body_hash:r,author:s,rationale:null,created_at:new Date().toISOString()}]});return e.prepare("UPDATE documents SET source_path = ? WHERE object = ?").run(t.path,u.rowid),c.created+=1,u.rowid}const f=o.name!==t.name||o.kind!==n.kind;o.name!==t.name&&(o=U(e,null,o,{name:t.name})),o.kind!==n.kind&&(C(e,o,n.kind),o=y(e,o.rowid));const m=R(e,o),[d]=j(e,o),a=d?.body_hash!==r,S=o.preview!==i.preview||m.summary!==i.summary||m.why_it_exists!==i.whyItExists||m.unlisted!==i.unlisted||JSON.stringify(m.lint_ignore)!==JSON.stringify(i.lintIgnore)||JSON.stringify(m.extensions)!==JSON.stringify(i.extensions)||JSON.stringify(W(e,o).map(N))!==JSON.stringify(i.rules.map(N));if(!a&&!S&&!f)return o.rowid;const g=T(e,o,i);if(a&&d){const u=I(),h=d.number+1;e.prepare("UPDATE revisions SET rev_id = ?, number = ?, body_hash = ?, created_at = ? WHERE rowid = ?").run(u,h,r,new Date().toISOString(),d.rowid),e.prepare("UPDATE documents SET heads_key = ?, revision = ? WHERE object = ?").run(u,h,g.rowid),F(e,{event:"edited",object:g,actor:s,level:8,pointer:u,attrs:{revision:h,from_revision:d.number,rationale:"package file changed"}},l)}return c.updated+=1,g.rowid}p(K,"convergeFile");function N(e){return[e.on,e.deliver,e.match??null,e.matchFrontmatter??null,e.if??null]}p(N,"ruleKey");function E(e,s,t,c,l){const n=e.prepare(`SELECT o.* FROM objects o JOIN documents d ON d.object = o.rowid
5
+ WHERE o.type = 'document' AND o.owner = ? AND o.deleted_at IS NULL AND d.source_path IS NOT NULL`).all(s.rowid);for(const i of n)t.has(i.rowid)||(x(e,null,i,l),c.deleted+=1)}p(E,"deleteMissing");export{M as packageSources,te as reconcilePackageDocuments};
@@ -0,0 +1,20 @@
1
+ /** One markdown file of a package's `memory/` folder. */
2
+ export interface PackageFile {
3
+ /** owner-local document name; a package root `INDEX.md` is `index` */
4
+ name: string;
5
+ path: string;
6
+ frontmatter: Record<string, unknown> | null;
7
+ body: string;
8
+ }
9
+ /** The documents of one package folder, sorted by name. A file whose frontmatter does not parse,
10
+ * or whose name another file already holds, is returned in `invalid` and is not a document. */
11
+ export declare function packageFiles(dir: string): {
12
+ files: PackageFile[];
13
+ invalid: Array<{
14
+ path: string;
15
+ error: string;
16
+ }>;
17
+ };
18
+ /** Strict frontmatter check a plugin package's documents must pass before the
19
+ * package installs. */
20
+ export declare function lintPackageFrontmatter(fm: Record<string, unknown> | null): string | null;
@@ -0,0 +1,2 @@
1
+ var b=Object.defineProperty;var u=(e,n)=>b(e,"name",{value:n,configurable:!0});import{readFileSync as v}from"node:fs";import{relative as S,sep as $}from"node:path";import{parseFrontmatterGeneric as w}from"../frontmatter.js";import{pathExists as x,walkFiles as k}from"../fs-utils.js";import{explicitLocalName as N,isDocKind as A,localNameFromPath as y,representationForPath as E}from"../substrate/schema.js";function W(e){const n=[];if(!x(e))return{files:[],invalid:n};const r=new Map;for(const o of k(e,i=>i.endsWith(".md")&&i!=="SKILL.md",i=>i===".crouter"||i.startsWith(".")).sort()){const i=S(e,o).split($).join("/");let s;try{s=w(v(o,"utf8"))}catch(f){n.push({path:o,error:`invalid frontmatter: ${(f instanceof Error?f.message:String(f)).split(`
2
+ `)[0]}`});continue}const d=y(i)===""?"":N(s.data)??y(i),a=d===""?"index":d,l={name:a,path:o,frontmatter:s.data,body:s.body,index:E(i)==="directory-index"},c=r.get(a);if(c&&(c.index||!l.index)){n.push({path:o,error:`name ${a} is already held by ${c.path}`});continue}c&&n.push({path:c.path,error:`name ${a} is already held by ${o}`}),r.set(a,l)}return{files:[...r.values()].map(({index:o,...i})=>i).sort((o,i)=>o.name.localeCompare(i.name)),invalid:n}}u(W,"packageFiles");const p=["public","friends","private"],h=["boot","workspace-open","read","memory-read","command","pre-command"],m=["name","preview","content"],O=["system-prompt-visibility","file-read-visibility","applies-to","read-when"],j=["on","match","match-frontmatter","gate","at"],g=["length","broad-memory-read","orphan"];function J(e){if(e===void 0)return null;if(!Array.isArray(e))return`invalid surfaces: ${JSON.stringify(e)} (expected a list of {on, at, match?, match-frontmatter?, gate?} entries)`;for(const n of e){if(n===null||typeof n!="object"||Array.isArray(n))return`invalid surfaces entry: ${JSON.stringify(n)} (expected an {on, at, match?, match-frontmatter?, gate?} object)`;const r=n;for(const a of Object.keys(r))if(!j.includes(a))return`invalid surfaces entry: unknown key \`${a}\` (an entry carries only on, match, match-frontmatter, gate, at)`;const t=r.on;if(typeof t!="string"||!h.includes(t))return`invalid surfaces entry \`on\`: ${JSON.stringify(t)} (expected ${h.join("|")})`;const o=r.at;if(typeof o!="string"||!m.includes(o))return`invalid surfaces entry \`at\`: ${JSON.stringify(o)} (expected ${m.join("|")})`;let i=!1;if(r.match!==void 0){if(t==="boot"||t==="workspace-open")return`invalid surfaces entry: \`match\` is meaningless on \`${t}\` \u2014 the entry's presence is the match; drop it`;const a=r.match,l=typeof a=="string"?[a]:Array.isArray(a)&&a.every(c=>typeof c=="string")?a:null;if(l===null||l.length===0||l.some(c=>c.trim()===""))return`invalid surfaces entry \`match\`: ${JSON.stringify(a)} (expected a non-empty glob or non-empty glob list)`;i=!0}const s=r["match-frontmatter"];if(s!==void 0){if(t!=="read")return"invalid surfaces entry: `match-frontmatter` is a `read`-event predicate only";if(s===null||typeof s!="object"||Array.isArray(s))return`invalid surfaces entry \`match-frontmatter\`: ${JSON.stringify(s)} (expected a field\u2192matcher object)`}if((t==="read"||t==="memory-read"||t==="command"||t==="pre-command")&&!i&&s===void 0)return`invalid surfaces entry: a \`${t}\` entry requires \`match\`${t==="read"?" or `match-frontmatter`":""}`;const d=r.gate;if(d!==void 0&&(d===null||typeof d!="object"||Array.isArray(d)))return`invalid surfaces entry \`gate\`: ${JSON.stringify(d)} (expected a field\u2192matcher object)`}return null}u(J,"lintPackageSurfaces");function C(e){if(e===null)return"missing frontmatter: a package document requires `kind: knowledge|preference`";if(!A(e.kind))return`invalid kind: ${JSON.stringify(e.kind)} (expected knowledge|preference)`;if("when"in e||"why"in e)return'retired `when`/`why` keys: merge them into one `when-and-why-to-read` line \u2014 "When <circumstance>, this <kind> should be read because <broader downstream payoff>." WHY is the benefit unlocked by reading, not the document summary, rule, or obedience rationale.';if(typeof e["when-and-why-to-read"]!="string"||e["when-and-why-to-read"].trim()==="")return'missing `when-and-why-to-read`: one routing line \u2014 "When <circumstance>, this <kind> should be read because <broader downstream payoff>." WHY is the benefit unlocked by reading, not the document summary, rule, or obedience rationale.';for(const r of O)if(r in e)return`retired \`${r}\` key: the visibility axes were replaced by \`surfaces\` event routing \u2014 run \`crtr sys migrate\` to convert old-format docs, or author \`surfaces\` entries by hand (\`crtr memory write -h\`)`;if("privacy"in e&&!p.includes(e.privacy))return`invalid privacy: ${JSON.stringify(e.privacy)} (expected ${p.join("|")})`;if(e.unlisted!==void 0&&typeof e.unlisted!="boolean")return`invalid unlisted: ${JSON.stringify(e.unlisted)} (expected a boolean)`;const n=J(e.surfaces);if(n!==null)return n;if(e.gate!==void 0&&(e.gate===null||typeof e.gate!="object"||Array.isArray(e.gate)))return`invalid gate: ${JSON.stringify(e.gate)} (expected a field\u2192matcher object)`;if(e.slash!==void 0&&typeof e.slash!="boolean")return`invalid slash: ${JSON.stringify(e.slash)} (expected a boolean)`;if(e.rationale!==void 0&&typeof e.rationale!="string")return`invalid rationale: ${JSON.stringify(e.rationale)} (expected a string)`;if(e["lint-ignore"]!==void 0){const r=Array.isArray(e["lint-ignore"])?e["lint-ignore"]:[e["lint-ignore"]];if(r.length===0||!r.every(t=>typeof t=="string"&&g.includes(t)))return`invalid lint-ignore: ${JSON.stringify(e["lint-ignore"])} (suppressible rules: ${g.map(t=>`\`${t}\``).join(", ")})`}return null}u(C,"lintPackageFrontmatter");export{C as lintPackageFrontmatter,W as packageFiles};
@@ -0,0 +1,21 @@
1
+ import type { DatabaseSync } from 'node:sqlite';
2
+ import type { RequestPrincipal } from '../../daemon/api/router.js';
3
+ import { type ActiveGrant } from '../grants/mirror.js';
4
+ import type { ObjectRow, Reader } from './types.js';
5
+ export type ReposFn = (cwd: string) => ObjectRow[];
6
+ export declare function readerFor(db: DatabaseSync, principal: RequestPrincipal, reposFn: ReposFn): Reader;
7
+ export declare function readerForNode(db: DatabaseSync, nodeId: string, reposFn: ReposFn, lookups?: ReaderLookups): Reader;
8
+ /** What building a node reader looks up besides the node's own row. `liveLookups` reads each
9
+ * one per call; `publishLookups` memoizes them for one publish inside its transaction, so the
10
+ * readers of one event share a single config read and one lookup per grant, owner and
11
+ * profile. Never keep a memoized one past that transaction. */
12
+ export interface ReaderLookups {
13
+ grantById(grantId: string): ActiveGrant | null;
14
+ grantFor(app: string, sub: string): ActiveGrant | null;
15
+ terminalHasIssuer(): boolean;
16
+ object(rowid: number): ObjectRow | null;
17
+ profile(profileId: string, app: ObjectRow): ObjectRow;
18
+ }
19
+ export declare function liveLookups(db: DatabaseSync): ReaderLookups;
20
+ export declare function publishLookups(db: DatabaseSync): ReaderLookups;
21
+ export declare function profileObject(db: DatabaseSync, profileId: string, app: ObjectRow): ObjectRow;
@@ -0,0 +1,3 @@
1
+ var _=Object.defineProperty;var t=(o,e)=>_(o,"name",{value:e,configurable:!0});import{covers as R}from"@north-light/crouter-identity";import{activeGrant as h,grantFor as F}from"../grants/mirror.js";import{prepared as E}from"../canvas/db.js";import{readConfig as $}from"../config.js";import{SCOPE_VOCABULARY as H}from"../scopes.js";import{loadExactProfileManifest as S}from"../profiles/manifest.js";import{ensureOwner as p,getByRowid as x,nodeObject as C}from"./objects.js";function I(o,e,i){if(e.class==="person")return{class:"person",person:j(o)};if(e.class==="app")return{class:"app",app:L(o,e.app),scopes:e.scopes};const s=f(o),r=C(o,e.node),n=r.owner===null?null:s.object(r.owner);if(!n)throw new Error(`node ${e.node} has no owner`);const l=o.prepare("SELECT cwd, profile_id FROM nodes WHERE node_id = ?").get(e.node);return{class:"node",node:r,app:n,scopes:g(e.app,e.sub,e.grant,e.scopes,s),cwd:l.cwd,repos:i(l.cwd),profile:l.profile_id===null?null:s.profile(l.profile_id,n)}}t(I,"readerFor");function D(o,e,i,s=f(o)){const r=E(o,"SELECT o.* FROM objects o WHERE o.id = ? AND o.type = 'node'").get(e),n=E(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(r?.owner??null,e);if(!r||!n)throw new Error(`no node ${e}`);const{grantee:l,sub:c,grant_id:a,scopes_json:d,cwd:w,profile_id:m}=n,u=r.owner===null?null:s.object(r.owner);if(!u)throw new Error(`node ${e} has no owner`);const O=d===null?null:JSON.parse(d);return{class:"node",node:r,app:u,scopes:g(l,c??"",a,O,s),cwd:w,repos:i(w),profile:m===null?null:s.profile(m,u)}}t(D,"readerForNode");function f(o){return{grantById:h,grantFor:F,terminalHasIssuer:t(()=>!!$("user").runtime?.issuer,"terminalHasIssuer"),object:t(e=>x(o,e),"object"),profile:t((e,i)=>b(o,e,i),"profile")}}t(f,"liveLookups");function J(o){const e=f(o),i=new Map,s=t((r,n)=>(i.has(r)||i.set(r,n()),i.get(r)),"memo");return{grantById:t(r=>s(`g\0${r}`,()=>e.grantById(r)),"grantById"),grantFor:t((r,n)=>s(`a\0${r}\0${n}`,()=>e.grantFor(r,n)),"grantFor"),terminalHasIssuer:t(()=>s("issuer",()=>e.terminalHasIssuer()),"terminalHasIssuer"),object:t(r=>s(`o\0${r}`,()=>e.object(r)),"object"),profile:t((r,n)=>s(`p\0${r}\0${n.rowid}`,()=>e.profile(r,n)),"profile")}}t(J,"publishLookups");function g(o,e,i,s,r){const n=i?r.grantById(i):r.grantFor(o,e),l=n&&n.grantee===o?n.resolved:o==="app:terminal"&&!r.terminalHasIssuer()?H:null;if(l===null)throw new Error(`the grant of ${o} is not active`);return s===null?l:s.filter(c=>l.some(a=>R(a,c)))}t(g,"nodeScopes");function j(o){return p(o,"person","local-user","user:local","user")}t(j,"personObject");function L(o,e){return e==="user:local"?j(o):p(o,"app","app",e,e.replace(/^app:/,""))}t(L,"appObject");function b(o,e,i){return 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)??p(o,"profile","profile",e,S(e).manifest.name,i)}t(b,"profileObject");export{f as liveLookups,b as profileObject,J as publishLookups,I as readerFor,D as readerForNode};
@@ -0,0 +1,34 @@
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
+ import type { ReposFn } from '../reader.js';
7
+ import type { ObjectRow } from '../types.js';
8
+ /**
9
+ * The tree (path → file text) of every public document the repo space owns, deleted ones
10
+ * included. A revision already in `previous` is copied verbatim, so a remote author and the
11
+ * links it was written with survive; a revision made here carries its author's object id, and
12
+ * a head carries the document's current `links-to` edges.
13
+ */
14
+ export declare function exportRepo(db: DatabaseSync, repo: ObjectRow, previous: Map<string, string> | null): Map<string, string>;
15
+ export interface ImportResult {
16
+ created: number;
17
+ revisions: number;
18
+ deleted: number;
19
+ needsMerge: string[];
20
+ refused: Array<{
21
+ path: string;
22
+ reason: string;
23
+ }>;
24
+ }
25
+ /**
26
+ * Apply the difference between two trees (the one last imported and the new one) to the
27
+ * repo's documents, in one transaction. Per changed file: a file that does not parse, is not
28
+ * public, or names an id held by an object outside this repo is refused and reported; a new
29
+ * document is created with its id; arriving revisions are added (author NULL); changed record
30
+ * fields and a rename are applied; a tombstone or a removed file deletes. Each document
31
+ * publishes once: `created`, `edited` (with `heads` and `needs_merge`) or `deleted`. A
32
+ * document that fails is rolled back alone and reported in `refused`.
33
+ */
34
+ export declare function importTree(db: DatabaseSync, repo: ObjectRow, before: Map<string, string>, after: Map<string, string>, reposFn?: ReposFn): ImportResult;
@@ -0,0 +1,2 @@
1
+ var A=Object.defineProperty;var f=(e,t)=>A(e,"name",{value:t,configurable:!0});import{get as B,put as T}from"../bodies.js";import{setLinks as j}from"../edges.js";import{deleteDocument as S,documentRecord as D,heads as M,importDocument as F,insertImportedRevisions as H,moveDocument as W,setDocumentRecord as J}from"../documents.js";import{publish as $}from"../events.js";import{getById as C,getByRowid as P,setObjectKind as Y}from"../objects.js";import{rulesOf as K}from"../rules.js";import{SPACES as z}from"../spaces/index.js";import{docPath as V,parseDoc as E,serializeDoc as b}from"./ref-format.js";function I(e){const t=z[e.type];if(e.owner!==null||!t||t.sync!=="repo-ref")throw new Error(`${e.type} ${e.id} is not a space that syncs through a repo ref`)}f(I,"assertRepoRefSpace");function q(e){const t=new Map;for(const[r,i]of e??[]){const l=E(r,i);l.ok&&t.set(l.doc.id,l.doc)}return t}f(q,"parseMap");function ce(e,t,r){I(t);const i=q(r),l=e.prepare("SELECT * FROM objects WHERE type = 'document' AND owner = ? AND privacy = 'public' ORDER BY rowid").all(t.rowid),u=e.prepare("SELECT rowid, rev_id, number, body_hash, author, rationale, created_at FROM revisions WHERE document = ? ORDER BY number, rev_id"),p=e.prepare("SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rowid = rp.parent WHERE rp.child = ?"),o=e.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`),d=new Map;for(const n of l){const m=D(e,n),y=new Map((i.get(n.id)?.revisions??[]).map(s=>[s.rev_id,s])),h=new Set(M(e,n).map(s=>s.rev_id)),g=o.all(n.rowid).map(s=>({written_as:s.written_as??"",dst:s.id})),v=u.all(n.rowid).map(s=>y.get(s.rev_id)??{rev_id:s.rev_id,number:s.number,parents:p.all(s.rowid).map(O=>O.rev_id),body:B(s.body_hash),body_hash:s.body_hash,author:s.author===null?null:P(e,s.author)?.id??null,rationale:s.rationale,created_at:s.created_at,links:h.has(s.rev_id)?g:[]});if(v.length===0)continue;const R=K(e,n).map(s=>({position:s.position,on:s.on,match:s.match??null,match_frontmatter:s.matchFrontmatter??null,if:s.if??null,deliver:s.deliver})),_={id:n.id,name:n.name,kind:n.kind??"document",privacy:"public",preview:n.preview,summary:m.summary,why_it_exists:m.why_it_exists,unlisted:m.unlisted,lint_ignore:m.lint_ignore,extensions:m.extensions,created_at:n.created_at,deleted_at:n.deleted_at,rules:R,revisions:v};d.set(V(n.id),b(_))}return d}f(ce,"exportRepo");function G(e){return[...e].sort((t,r)=>t.position-r.position).map(t=>({on:t.on,deliver:t.deliver,...t.match!==null&&t.match!==void 0?{match:t.match}:{},...t.match_frontmatter!==null&&t.match_frontmatter!==void 0?{matchFrontmatter:t.match_frontmatter}:{},...t.if!==null&&t.if!==void 0?{if:t.if}:{}}))}f(G,"toRuleSpecs");const Q=f((e,t)=>JSON.stringify(e??null)===JSON.stringify(t??null),"same");function N(e,t){const r={},i=f(l=>!e||!Q(e[l],t[l]),"differs");return i("preview")&&(r.preview=t.preview),i("summary")&&(r.summary=t.summary),i("why_it_exists")&&(r.whyItExists=t.why_it_exists),i("unlisted")&&(r.unlisted=t.unlisted),i("lint_ignore")&&(r.lintIgnore=t.lint_ignore),i("extensions")&&(r.extensions=t.extensions),i("rules")&&(r.rules=G(t.rules)),r}f(N,"changedFields");let U=0;function L(e,t){const r=`repo_sync_import_${++U}`;e.exec(`SAVEPOINT ${r}`);try{const i=t();return e.exec(`RELEASE ${r}`),i}catch(i){throw e.exec(`ROLLBACK TO ${r}`),e.exec(`RELEASE ${r}`),i}}f(L,"atomic");function de(e,t,r,i,l){I(t);const u={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]},p=[];for(const[o,d]of i){if(r.get(o)===d)continue;const n=E(o,d);if(!n.ok){u.refused.push({path:o,reason:n.reason});continue}const m=r.has(o)?E(o,r.get(o)):null;p.push({path:o,prior:m?.ok?m.doc:null,doc:n.doc})}for(const[o,d]of r){if(i.has(o))continue;const n=E(o,d);n.ok&&p.push({path:o,prior:n.doc,doc:null,priorId:n.doc.id})}for(const o of p)for(const d of o.doc?.revisions??[])T(d.body);return L(e,()=>{for(const o of p)try{L(e,()=>X(e,t,o.prior,o.doc,o.priorId??o.doc.id,u,l))}catch(d){u.refused.push({path:o.path,reason:d.message})}}),u}f(de,"importTree");function X(e,t,r,i,l,u,p){const o=C(e,l);if(o&&(o.type!=="document"||o.owner!==t.rowid))throw new Error(`id ${l} is held by ${o.type} ${o.name} outside ${t.name}`);if(!i){o&&!o.deleted_at&&(S(e,null,o,p),u.deleted++);return}const d=e.prepare("SELECT count(*) AS n FROM revisions WHERE document = ?");let n,m=!1,y=0,h=0;if(o){n=o,y=D(e,n).revision;const a=i.kind;(r?r.kind!==a:n.kind!==a)&&Y(e,n,a);const c=N(r,i);Object.keys(c).length>0&&(n=J(e,null,n,c)),i.name!==n.name&&!n.deleted_at&&(n=W(e,null,n,{name:i.name}))}else{const c=i.revisions.filter(w=>w.parents.length===0).sort((w,x)=>w.number-x.number||w.rev_id.localeCompare(x.rev_id))[0];if(!c)throw new Error(`${i.name}: no root revision`);n=F(e,{id:i.id,owner:t,name:i.name,kind:i.kind,preview:i.preview,privacy:"public",...N(null,i),revisions:[{rev_id:c.rev_id,body_hash:c.body_hash,author:null,rationale:c.rationale,created_at:c.created_at}]}),m=!0,h=1}const g=d.get(n.rowid).n,{headCount:v}=H(e,n,i.revisions.map(a=>({rev_id:a.rev_id,parents:a.parents,body_hash:a.body_hash,rationale:a.rationale,created_at:a.created_at})));h+=d.get(n.rowid).n-g,u.revisions+=h;const _=M(e,n)[0],s=new Map(i.revisions.map(a=>[a.rev_id,a]));if(h>0){const a=(s.get(_.rev_id)?.links??[]).map(c=>({written_as:c.written_as,dst:C(e,c.dst)})).filter(c=>c.dst!==null);j(e,n,a)}if(v>1&&u.needsMerge.push(n.id),i.deleted_at&&!n.deleted_at){S(e,null,n,p),u.deleted++;return}if(m){u.created++,$(e,{event:"created",object:n,actor:null,level:4,attrs:{revision:_.number},pointer:_.rev_id},p);return}if(h===0)return;const k=i.revisions.filter(a=>!r?.revisions.some(c=>c.rev_id===a.rev_id)).sort((a,c)=>c.number-a.number||c.created_at.localeCompare(a.created_at))[0]??s.get(_.rev_id);$(e,{event:"edited",object:n,actor:null,level:8,pointer:_.rev_id,attrs:{revision:_.number,from_revision:y,rationale:k?.rationale??null,author:k?.author??null,heads:v,needs_merge:v>1}},p)}f(X,"importOne");export{ce as exportRepo,de as importTree};
@@ -0,0 +1,30 @@
1
+ export type CheckoutIdentity = {
2
+ ok: true;
3
+ scheme: 'git';
4
+ externalId: string;
5
+ remoteUrl: string;
6
+ root: string;
7
+ commonDir: string;
8
+ handleHint: string;
9
+ } | {
10
+ ok: true;
11
+ scheme: 'local-path';
12
+ externalId: string;
13
+ root: string;
14
+ handleHint: string;
15
+ } | {
16
+ ok: false;
17
+ code: 'not-a-repo' | 'git-lookup-failed';
18
+ dir: string;
19
+ reason: string;
20
+ };
21
+ /** `https://User@GitHub.com:443/Org/Repo.git/` and `git@github.com:org/repo`
22
+ * both give `github.com/org/repo`. A local remote (absolute path or
23
+ * `file://`) gives `file:<realpath>`, resolved against `base` when relative. */
24
+ export declare function normalizeRemoteUrl(url: string, base?: string): string;
25
+ /** Owner handle a new repo object takes: the last segment of its external id (the normalized remote path, or the folder of a local-path repo), without `.git`. */
26
+ export declare function handleHint(externalId: string): string;
27
+ export declare function identifyCheckout(dir: string): CheckoutIdentity;
28
+ /** Checkouts enclosing `dir`, innermost first; stops at the first directory
29
+ * that is not in a repo. A failed lookup ends the chain and is returned last. */
30
+ export declare function checkoutChain(dir: string): CheckoutIdentity[];
@@ -0,0 +1 @@
1
+ var C=Object.defineProperty;var u=(o,e)=>C(o,"name",{value:e,configurable:!0});import{existsSync as O}from"node:fs";import{basename as h,dirname as g,isAbsolute as v,resolve as k}from"node:path";import{gitSync as $}from"../../git.js";import{realpathOrSelf as f}from"../../fs-utils.js";const p=5e3,M=6e4,x=new Map;function b(o,e){const r=o.trim();let t,s;const l=/^([a-z][a-z0-9+.-]*):\/\//i.exec(r);if(l){if(l[1].toLowerCase()==="file")return`file:${w(decodeURIComponent(r.slice(7)),e)}`;const i=r.slice(l[0].length),n=i.indexOf("/"),a=n<0?i:i.slice(0,n);s=n<0?"":i.slice(n),t=a.replace(/^.*@/,"").replace(/:\d*$/,"")}else{const i=/^(?:[^@/]+@)?([^:/]+):(.*)$/.exec(r);if(!i)return`file:${w(r,e)}`;t=i[1],s=i[2]}return s=s.replace(/^\/*~?/,"").replace(/\/+$/,"").replace(/\.git$/i,"").replace(/\/+$/,""),`${t}/${s}`.toLowerCase()}u(b,"normalizeRemoteUrl");function w(o,e){const r=v(o)?o:k(e??process.cwd(),o);return f(r).replace(/\/+$/,"")||"/"}u(w,"localPath");function y(o){const e=o.startsWith("file:")?o.slice(5):o;return h(e).replace(/\.git$/i,"")||"repo"}u(y,"handleHint");function L(o){const e=f(k(o)),r=x.get(e);if(r&&Date.now()-r.at<M)return r.id;if(!O(e))return{ok:!1,code:"not-a-repo",dir:e,reason:"directory does not exist"};const t=$(["rev-parse","--path-format=absolute","--show-toplevel","--git-common-dir"],e,void 0,{timeoutMs:p});if(t.timedOut)return{ok:!1,code:"git-lookup-failed",dir:e,reason:`git lookup timed out after ${p}ms`};if(t.status!==0)return/not a git repository/i.test(t.stderr)?{ok:!1,code:"not-a-repo",dir:e,reason:t.stderr.trim()}:{ok:!1,code:"git-lookup-failed",dir:e,reason:t.stderr.trim()||t.processError||`git rev-parse exited ${t.status}`};const[s,l]=t.stdout.split(/\r?\n/).map(c=>c.trim());if(!s||!l)return{ok:!1,code:"git-lookup-failed",dir:e,reason:"git rev-parse returned no work tree (bare repository?)"};const i=f(s),n=f(l),a=$(["remote","get-url","origin"],i,void 0,{timeoutMs:p});if(a.timedOut)return{ok:!1,code:"git-lookup-failed",dir:e,reason:`git remote lookup timed out after ${p}ms`};let d;const m=a.stdout.trim();if(a.status===0&&m!==""){const c=b(m,i);d={ok:!0,scheme:"git",externalId:c,remoteUrl:m,root:i,commonDir:n,handleHint:y(c)}}else if(/no such remote/i.test(a.stderr)){const c=h(n)===".git"?g(n):n;d={ok:!0,scheme:"local-path",externalId:c,root:i,handleHint:y(c)}}else return{ok:!1,code:"git-lookup-failed",dir:e,reason:a.stderr.trim()||`git remote get-url exited ${a.status}`};return x.set(e,{at:Date.now(),id:d}),d}u(L,"identifyCheckout");function D(o){const e=[];let r=o;for(;;){const t=L(r);if(!t.ok)return t.code==="git-lookup-failed"&&e.push(t),e;e.push(t);const s=g(t.root);if(s===t.root)return e;r=s}}u(D,"checkoutChain");export{D as checkoutChain,y as handleHint,L as identifyCheckout,b as normalizeRemoteUrl};
@@ -0,0 +1,4 @@
1
+ /** The import surface of repo sync for other domains. */
2
+ export { startRepoSync, noteNodeWorking, noteNodeBooting, noteRepoDocumentsChanged, syncRepo, FIRST_FETCH_WAIT_MS } from './sync.js';
3
+ export type { SyncOutcome, SyncStep } from './sync.js';
4
+ export type { ImportResult } from './exchange.js';
@@ -0,0 +1 @@
1
+ import{startRepoSync as n,noteNodeWorking as t,noteNodeBooting as p,noteRepoDocumentsChanged as r,syncRepo as R,FIRST_FETCH_WAIT_MS as c}from"./sync.js";export{c as FIRST_FETCH_WAIT_MS,p as noteNodeBooting,t as noteNodeWorking,r as noteRepoDocumentsChanged,n as startRepoSync,R as syncRepo};
@@ -0,0 +1,30 @@
1
+ /** crtr's own bare git repo holding one repo object's `refs/crtr/docs`. Nothing
2
+ * here touches a user's checkout: fetch and push address the remote URL directly.
3
+ * Local refs: `refs/crtr/docs` (local tip), `refs/crtr/remote-docs` (last fetched),
4
+ * `refs/crtr/imported` (tree last imported into canvas.db). */
5
+ export interface Mirror {
6
+ dir: string;
7
+ }
8
+ export type RemoteResult<T> = {
9
+ ok: true;
10
+ value: T;
11
+ } | {
12
+ ok: false;
13
+ reason: string;
14
+ };
15
+ export declare const FIRST_FETCH_MARKER = "first-fetch-done";
16
+ export declare function openMirror(repoObjectId: string): Promise<Mirror>;
17
+ export declare function resolveRef(m: Mirror, ref: string): Promise<string | null>;
18
+ export declare function readTree(m: Mirror, ref: string): Promise<Map<string, string> | null>;
19
+ export declare function commitTree(m: Mirror, files: Map<string, string>, parents: string[], message: string): Promise<string>;
20
+ /** `expectOld` null requires the ref to not exist yet. */
21
+ export declare function setRef(m: Mirror, ref: string, sha: string, expectOld: string | null): Promise<void>;
22
+ export declare function mergeBase(m: Mirror, a: string, b: string): Promise<string | null>;
23
+ export declare function isAncestor(m: Mirror, a: string, b: string): Promise<boolean>;
24
+ export declare function remoteDocsTip(m: Mirror, url: string): Promise<RemoteResult<string | null>>;
25
+ export declare function fetchDocs(m: Mirror, url: string): Promise<RemoteResult<string>>;
26
+ /** Never forced; `--no-verify` so no user hook runs. A non-fast-forward answers `rejected`. */
27
+ export declare function pushDocs(m: Mirror, url: string, sha: string): Promise<RemoteResult<'pushed'> | {
28
+ ok: false;
29
+ reason: 'rejected';
30
+ }>;
@@ -0,0 +1,6 @@
1
+ var k=Object.defineProperty;var i=(t,r)=>k(t,"name",{value:r,configurable:!0});import{spawn as A}from"node:child_process";import{existsSync as R}from"node:fs";import{mkdir as F,mkdtemp as S,rm as N,writeFile as _}from"node:fs/promises";import{join as x}from"node:path";import{gitAsync as $}from"../../git.js";import{crtrHome as G}from"../../canvas/paths.js";const g=6e4,j="first-fetch-done",T={...process.env,GIT_TERMINAL_PROMPT:"0",GIT_AUTHOR_NAME:"crtr",GIT_AUTHOR_EMAIL:"crtr@localhost",GIT_COMMITTER_NAME:"crtr",GIT_COMMITTER_EMAIL:"crtr@localhost"};function u(t,r,s,e={}){return $(["--git-dir",t.dir,...r],void 0,s,{env:e.env??T,timeoutMs:e.timeoutMs})}i(u,"git");function f(t,r){return new Error(`git ${t} failed (${r.timedOut?"timed out":`exit ${r.status}`}): ${r.stderr.trim()}`)}i(f,"fail");function y(t){return t.timedOut?"timed out":t.stderr.trim()||`exit ${t.status}`}i(y,"reason");async function K(t){const r=x(G(),"repo-sync",t),s={dir:r};if(!R(x(r,"HEAD"))){await F(r,{recursive:!0});const e=await $(["init","--bare","--quiet",r],void 0,void 0,{env:T});if(e.status!==0)throw f("init",e)}return s}i(K,"openMirror");async function v(t,r){const s=await u(t,["rev-parse","--verify","--quiet",`${r}^{commit}`]);if(s.status===0)return s.stdout.trim();if(s.status===1&&!s.executionFailed)return null;throw f("rev-parse",s)}i(v,"resolveRef");function D(t,r){return new Promise((s,e)=>{const o=A("git",["--git-dir",t.dir,"cat-file","--batch"],{env:{...T,GIT_OPTIONAL_LOCKS:"0"}}),d=[];let a="";o.stdout.on("data",n=>d.push(n)),o.stderr.on("data",n=>a+=n.toString()),o.on("error",e),o.on("close",n=>{if(n!==0)return e(new Error(`git cat-file failed (exit ${n}): ${a.trim()}`));const l=Buffer.concat(d),p=[];let w=0;for(const h of r){const b=l.indexOf(10,w),c=l.subarray(w,b).toString(),[m,I,O]=c.split(" ");if(m!==h||I!=="blob")return e(new Error(`git cat-file: unexpected header "${c}" for ${h}`));const M=b+1,E=M+Number(O);p.push(l.subarray(M,E)),w=E+1}s(p)}),o.stdin.end(r.map(n=>`${n}
2
+ `).join(""))})}i(D,"catFileBatch");async function U(t,r){const s=await v(t,r);if(s===null)return null;const e=await u(t,["ls-tree","-r","-z",s]);if(e.status!==0)throw f("ls-tree",e);const o=e.stdout.split("\0").filter(Boolean).map(a=>{const n=a.indexOf(" "),[,l,p]=a.slice(0,n).split(" ");if(l!=="blob")throw new Error(`repo-sync mirror: ${a.slice(n+1)} is a ${l}, not a file`);return{path:a.slice(n+1),blob:p}}),d=o.length===0?[]:await D(t,o.map(a=>a.blob));return new Map(o.map((a,n)=>[a.path,d[n].toString("utf8")]))}i(U,"readTree");async function W(t,r,s,e){const o=await S(x(t.dir,"commit-"));try{const d=[...r.keys()].sort(),a=d.map((c,m)=>x(o,`blob-${m}`));await Promise.all(d.map((c,m)=>_(a[m],r.get(c),"utf8")));let n=[];if(d.length>0){const c=await u(t,["hash-object","-w","--stdin-paths"],a.map(m=>`${m}
3
+ `).join(""));if(c.status!==0)throw f("hash-object",c);n=c.stdout.trim().split(`
4
+ `)}const l={...T,GIT_INDEX_FILE:x(o,"index")},p=d.map((c,m)=>`100644 ${n[m]} ${c}\0`).join(""),w=await u(t,["update-index","-z","--index-info"],p,{env:l});if(w.status!==0)throw f("update-index",w);const h=await u(t,["write-tree"],void 0,{env:l});if(h.status!==0)throw f("write-tree",h);const b=await u(t,["commit-tree",h.stdout.trim(),...s.flatMap(c=>["-p",c]),"-m",e]);if(b.status!==0)throw f("commit-tree",b);return b.stdout.trim()}finally{await N(o,{recursive:!0,force:!0})}}i(W,"commitTree");async function V(t,r,s,e){const o=await u(t,["update-ref",r,s,e??"0".repeat(40)]);if(o.status!==0)throw f("update-ref",o)}i(V,"setRef");async function X(t,r,s){const e=await u(t,["merge-base",r,s]);if(e.status===0)return e.stdout.trim();if(e.status===1&&!e.executionFailed)return null;throw f("merge-base",e)}i(X,"mergeBase");async function J(t,r,s){const e=await u(t,["merge-base","--is-ancestor",r,s]);if(e.status===0)return!0;if(e.status===1&&!e.executionFailed)return!1;throw f("merge-base --is-ancestor",e)}i(J,"isAncestor");async function Q(t,r){const s=await u(t,["ls-remote",r,"refs/crtr/docs"],void 0,{timeoutMs:g});if(s.status!==0)return{ok:!1,reason:y(s)};const e=s.stdout.split(`
5
+ `).find(o=>o.endsWith(" refs/crtr/docs"));return{ok:!0,value:e?e.split(" ")[0]:null}}i(Q,"remoteDocsTip");async function Y(t,r){const s=await u(t,["fetch","--no-tags","--quiet",r,"+refs/crtr/docs:refs/crtr/remote-docs"],void 0,{timeoutMs:g});if(s.status!==0)return{ok:!1,reason:y(s)};const e=await v(t,"refs/crtr/remote-docs");return e===null?{ok:!1,reason:"fetch succeeded but refs/crtr/remote-docs is missing"}:(await _(x(t.dir,j),`${new Date().toISOString()}
6
+ `),{ok:!0,value:e})}i(Y,"fetchDocs");async function Z(t,r,s){const e=await u(t,["push","--no-verify","--porcelain",r,`${s}:refs/crtr/docs`],void 0,{timeoutMs:g});return e.status===0?{ok:!0,value:"pushed"}:/\[rejected\]|non-fast-forward|fetch first/.test(e.stdout+e.stderr)?{ok:!1,reason:"rejected"}:{ok:!1,reason:y(e)}}i(Z,"pushDocs");export{j as FIRST_FETCH_MARKER,W as commitTree,Y as fetchDocs,J as isAncestor,X as mergeBase,K as openMirror,Z as pushDocs,U as readTree,Q as remoteDocsTip,v as resolveRef,V as setRef};
@@ -0,0 +1,76 @@
1
+ import type { RuleOn } from '../types.js';
2
+ export interface RefRule {
3
+ position: number;
4
+ on: RuleOn;
5
+ match: unknown;
6
+ match_frontmatter: unknown;
7
+ if: unknown;
8
+ deliver: 'name' | 'preview' | 'content';
9
+ }
10
+ export interface RefRevision {
11
+ rev_id: string;
12
+ number: number;
13
+ parents: string[];
14
+ body: string;
15
+ body_hash: string;
16
+ /** Object id of the author on the runtime that wrote it; null when unknown. */
17
+ author: string | null;
18
+ rationale: string | null;
19
+ created_at: string;
20
+ links: Array<{
21
+ written_as: string;
22
+ dst: string;
23
+ }>;
24
+ }
25
+ export interface RefDocument {
26
+ id: string;
27
+ name: string;
28
+ kind: string;
29
+ privacy: 'public';
30
+ preview: string;
31
+ summary: string | null;
32
+ why_it_exists: string | null;
33
+ unlisted: boolean;
34
+ lint_ignore: unknown;
35
+ extensions: unknown;
36
+ created_at: string;
37
+ deleted_at: string | null;
38
+ rules: RefRule[];
39
+ revisions: RefRevision[];
40
+ }
41
+ export declare const docPath: (id: string) => string;
42
+ /** Every field merged three-way: all but id, created_at and revisions. */
43
+ export declare const RECORD_FIELDS: readonly ["name", "kind", "privacy", "preview", "summary", "why_it_exists", "unlisted", "lint_ignore", "extensions", "deleted_at", "rules"];
44
+ export declare function sha256(body: string): string;
45
+ export declare function serializeDoc(doc: RefDocument): string;
46
+ /** Parse one ref file. Refuses anything not public, a body whose hash disagrees, or an id that is not the file name. */
47
+ export declare function parseDoc(path: string, text: string): {
48
+ ok: true;
49
+ doc: RefDocument;
50
+ } | {
51
+ ok: false;
52
+ reason: string;
53
+ };
54
+ /**
55
+ * Merge one document. Revisions: union by rev_id (first copy kept verbatim). Fields: three-way
56
+ * against base, remote wins when both changed. A side missing the file while base had it deleted
57
+ * it: the result is marked deleted (at `now`) and keeps every revision.
58
+ */
59
+ export declare function mergeDoc(base: RefDocument | null, local: RefDocument | null, remote: RefDocument | null, now?: string): RefDocument | null;
60
+ /**
61
+ * Merge three trees (path → file text). Per path mergeDoc; then two live documents with one name:
62
+ * the one already on the remote under that name keeps it, the other becomes `<name>-<id first 8>`.
63
+ * A file that fails to parse is refused; it stays in the tree only as the local side's text.
64
+ */
65
+ export declare function mergeTrees(base: Map<string, string>, local: Map<string, string>, remote: Map<string, string>, now?: string): {
66
+ tree: Map<string, string>;
67
+ renamed: Array<{
68
+ id: string;
69
+ from: string;
70
+ to: string;
71
+ }>;
72
+ refused: Array<{
73
+ path: string;
74
+ reason: string;
75
+ }>;
76
+ };
@@ -0,0 +1,2 @@
1
+ var $=Object.defineProperty;var a=(n,r)=>$(n,"name",{value:r,configurable:!0});import{createHash as O}from"node:crypto";const D=a(n=>`docs/${n}.json`,"docPath"),N=["name","kind","privacy","preview","summary","why_it_exists","unlisted","lint_ignore","extensions","deleted_at","rules"];function R(n){return O("sha256").update(n,"utf8").digest("hex")}a(R,"sha256");function h(n){if(Array.isArray(n))return n.map(h);if(n&&typeof n=="object"){const r={};for(const o of Object.keys(n).sort())r[o]=h(n[o]);return r}return n}a(h,"sortKeys");const v=a(n=>JSON.stringify(h(n??null)),"stable");function S(n,r){return n.number-r.number||(n.rev_id<r.rev_id?-1:n.rev_id>r.rev_id?1:0)}a(S,"byRevision");function j(n){const r={...n,rules:[...n.rules].sort((o,t)=>o.position-t.position),revisions:[...n.revisions].map(o=>({...o,parents:[...o.parents].sort()})).sort(S)};return`${JSON.stringify(h(r),null,2)}
2
+ `}a(j,"serializeDoc");const E=new Set(["boot","workspace-open","file-read","document-read","command","pre-command","slash-command"]),I=new Set(["name","preview","content"]),p=a(n=>typeof n=="string","isStr"),g=a(n=>n===null||typeof n=="string","isStrOrNull");function x(n,r){let o;try{o=JSON.parse(r)}catch(e){return{ok:!1,reason:`not JSON: ${e.message}`}}if(!o||typeof o!="object"||Array.isArray(o))return{ok:!1,reason:"not an object"};const t=o;if(t.privacy!=="public")return{ok:!1,reason:`privacy is ${String(t.privacy)}; a repo holds only public documents`};if(!p(t.id)||D(t.id)!==n)return{ok:!1,reason:`id ${String(t.id)} does not match file ${n}`};for(const e of["name","kind","preview","created_at"])if(!p(t[e]))return{ok:!1,reason:`${e} is not a string`};for(const e of["summary","why_it_exists","deleted_at"])if(!g(t[e]))return{ok:!1,reason:`${e} is not a string or null`};if(typeof t.unlisted!="boolean")return{ok:!1,reason:"unlisted is not a boolean"};if(!Array.isArray(t.rules))return{ok:!1,reason:"rules is not an array"};for(const e of t.rules)if(!e||typeof e.position!="number"||!E.has(e.on)||!I.has(e.deliver))return{ok:!1,reason:"malformed rule"};if(!Array.isArray(t.revisions)||t.revisions.length===0)return{ok:!1,reason:"no revisions"};const d=new Set;for(const e of t.revisions){if(!e||!p(e.rev_id)||typeof e.number!="number"||!p(e.body)||!p(e.body_hash)||!p(e.created_at)||!g(e.author)||!g(e.rationale)||!Array.isArray(e.parents)||!e.parents.every(p)||!Array.isArray(e.links))return{ok:!1,reason:"malformed revision"};if(d.has(e.rev_id))return{ok:!1,reason:`revision ${e.rev_id} appears twice`};if(d.add(e.rev_id),R(e.body)!==e.body_hash)return{ok:!1,reason:`revision ${e.rev_id} body does not match body_hash`}}return{ok:!0,doc:t}}a(x,"parseDoc");function A(...n){const r=new Map;for(const o of n)for(const t of o?.revisions??[])r.has(t.rev_id)||r.set(t.rev_id,t);return[...r.values()].sort(S)}a(A,"unionRevisions");function M(n,r,o,t=new Date().toISOString()){if(!r&&!o)return null;if(!r||!o){const e=r??o;return n?{...e,deleted_at:e.deleted_at??t,revisions:A(o,r,n)}:e}const d={...o,revisions:A(o,r,n)};for(const e of N){const u=v(r[e]),m=v(o[e]);if(u===m)continue;(n?v(n[e]):void 0)===m&&(d[e]=r[e])}return d}a(M,"mergeDoc");function L(n,r,o,t=new Date().toISOString()){const d=new Map,e=[],u=new Map,m=[...new Set([...n.keys(),...r.keys(),...o.keys()])].sort();for(const i of m){const s=[];let l=null;for(const c of[n,r,o]){const y=c.get(i);if(y===void 0){s.push(null);continue}const k=x(i,y);k.ok?s.push(k.doc):(l??=k.reason,s.push(null))}if(l!==null){e.push({path:i,reason:l});const c=r.get(i);c!==void 0&&d.set(i,c);continue}const f=M(s[0],s[1],s[2],t);f&&u.set(i,f)}const b=a(i=>{const s=o.get(i);if(s===void 0)return null;const l=x(i,s);return l.ok&&l.doc.deleted_at===null?l.doc.name:null},"remoteNameOf"),_=new Map;for(const[i,s]of u)s.deleted_at===null&&_.set(s.name,[..._.get(s.name)??[],i]);const w=[];for(const[i,s]of _){if(s.length<2)continue;const l=s.find(f=>b(f)===i)??[...s].sort((f,c)=>u.get(f).id.localeCompare(u.get(c).id))[0];for(const f of s){if(f===l)continue;const c=u.get(f),y=`${i}-${c.id.slice(0,8)}`;u.set(f,{...c,name:y}),w.push({id:c.id,from:i,to:y})}}for(const[i,s]of u)d.set(i,j(s));return{tree:new Map([...d].sort(([i],[s])=>i.localeCompare(s))),renamed:w,refused:e}}a(L,"mergeTrees");export{N as RECORD_FIELDS,D as docPath,M as mergeDoc,L as mergeTrees,x as parseDoc,j as serializeDoc,R as sha256};
@@ -0,0 +1,17 @@
1
+ /** Repo objects on the canvas: one per repo identity, handle chosen once. */
2
+ import type { DatabaseSync } from 'node:sqlite';
3
+ import type { ObjectRow } from '../types.js';
4
+ import { handleHint } from './identity.js';
5
+ export { handleHint };
6
+ export interface RepoIdentity {
7
+ scheme: 'git' | 'local-path';
8
+ externalId: string;
9
+ handleHint: string;
10
+ }
11
+ /** The repo object for an identity, created on first sight. A handle already
12
+ * held by another repo gets `-2`, `-3`, … appended. */
13
+ export declare function ensureRepo(db: DatabaseSync, id: RepoIdentity, handle?: string): ObjectRow;
14
+ /** Repos enclosing `cwd`, nearest first: every enclosing git checkout (created
15
+ * on first sight) and every existing local-path repo whose path is `cwd` or
16
+ * an ancestor of it. A non-git folder is never created here. */
17
+ export declare function reposForCwd(db: DatabaseSync, cwd: string): ObjectRow[];
@@ -0,0 +1,3 @@
1
+ var f=Object.defineProperty;var a=(t,o)=>f(t,"name",{value:o,configurable:!0});import{resolve as h,sep as c}from"node:path";import{CrtrError as l}from"../../errors.js";import{realpathOrSelf as d}from"../../fs-utils.js";import{ExitCode as m}from"../../../types.js";import{ensureOwner as u}from"../objects.js";import{checkoutChain as E,handleHint as w}from"./identity.js";function x(t,o,n){return 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,n)??null}a(x,"existingRepo");function N(t,o,n){const r=x(t,o.scheme,o.externalId);if(r)return r;const p=n??o.handleHint,s=t.prepare("SELECT 1 FROM objects WHERE name = ? AND type = 'repo'");let e=p;for(let i=2;s.get(e);i++)e=`${p}-${i}`;return u(t,"repo",o.scheme,o.externalId,e)}a(N,"ensureRepo");function H(t,o){const n=d(h(o)),r=[];for(const e of E(n)){if(!e.ok)throw new l("git-lookup-failed",`cannot identify the repo at ${e.dir}: ${e.reason}`,m.GENERAL,{dir:e.dir});r.push({root:e.root,repo:N(t,e)})}const p=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 p)(n===e||n.startsWith(e.endsWith(c)?e:e+c))&&r.push({root:e,repo:i});r.sort((e,i)=>i.root.length-e.root.length);const s=new Set;return r.filter(({repo:e})=>!s.has(e.rowid)&&(s.add(e.rowid),!0)).map(({repo:e})=>e)}a(H,"reposForCwd");export{N as ensureRepo,w as handleHint,H as reposForCwd};
@@ -0,0 +1,42 @@
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
+ import type { DetachedWorkLifecycle } from '../../../daemon/reconcilers/broker-supervision.js';
6
+ import type { ObjectRow } from '../types.js';
7
+ import { type ImportResult } from './exchange.js';
8
+ export declare const FIRST_FETCH_WAIT_MS = 20000;
9
+ export type SyncStep = 'export' | 'fetch' | 'merge' | 'import' | 'push';
10
+ export type SyncOutcome = {
11
+ ok: true;
12
+ pushed: boolean;
13
+ imported: ImportResult;
14
+ } | {
15
+ ok: false;
16
+ step: SyncStep;
17
+ reason: string;
18
+ };
19
+ /** Called once by crtrd. Until then triggers are refused loudly. */
20
+ export declare function startRepoSync(lifecycle: DetachedWorkLifecycle, db: () => DatabaseSync): void;
21
+ /**
22
+ * A node starts working in `cwd`, enclosed by `repos`. For each syncing repo: when no fetch has
23
+ * ever succeeded on this machine and none was attempted in this daemon's lifetime, wait for its
24
+ * sync, at most FIRST_FETCH_WAIT_MS; otherwise schedule it and return at once.
25
+ */
26
+ export declare function noteNodeWorking(repos: ObjectRow[], cwd: string): Promise<void>;
27
+ /**
28
+ * A node's boot delivery is about to render: it starts working in the repos enclosing its cwd.
29
+ * Sync them first (the first on this machine waits for the first fetch, bounded), so what the
30
+ * repo's collaborators wrote is on the canvas before its bearings. Never throws: a failed sync
31
+ * never fails a boot, and every failure is an event.
32
+ */
33
+ export declare function noteNodeBooting(nodeId: string): Promise<void>;
34
+ /** A repo-owned document changed (write, edit, move at either end, delete). `cwd`, when the caller
35
+ * has one inside a checkout, records the fetch URL. */
36
+ export declare function noteRepoDocumentsChanged(repo: ObjectRow, cwd?: string): void;
37
+ /**
38
+ * One sync: export canvas.db to a local commit, fetch the remote ref, fast-forward or merge,
39
+ * import the merged tree into canvas.db, push (never forced). A rejected push fetches again,
40
+ * at most PUSH_ATTEMPTS times.
41
+ */
42
+ export declare function syncRepo(repo: ObjectRow): Promise<SyncOutcome>;