mrplex 0.0.1

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 (319) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +284 -0
  3. package/dist/cli/config.d.ts +28 -0
  4. package/dist/cli/config.js +48 -0
  5. package/dist/cli/config.js.map +1 -0
  6. package/dist/cli/exit-codes.d.ts +13 -0
  7. package/dist/cli/exit-codes.js +39 -0
  8. package/dist/cli/exit-codes.js.map +1 -0
  9. package/dist/cli/format.d.ts +22 -0
  10. package/dist/cli/format.js +148 -0
  11. package/dist/cli/format.js.map +1 -0
  12. package/dist/cli/main.d.ts +16 -0
  13. package/dist/cli/main.js +1518 -0
  14. package/dist/cli/main.js.map +1 -0
  15. package/dist/client/kernel-client.d.ts +97 -0
  16. package/dist/client/kernel-client.js +14 -0
  17. package/dist/client/kernel-client.js.map +1 -0
  18. package/dist/client/local.d.ts +26 -0
  19. package/dist/client/local.js +103 -0
  20. package/dist/client/local.js.map +1 -0
  21. package/dist/client/remote-mcp.d.ts +35 -0
  22. package/dist/client/remote-mcp.js +174 -0
  23. package/dist/client/remote-mcp.js.map +1 -0
  24. package/dist/embed/backfill.d.ts +24 -0
  25. package/dist/embed/backfill.js +33 -0
  26. package/dist/embed/backfill.js.map +1 -0
  27. package/dist/embed/chunker.d.ts +31 -0
  28. package/dist/embed/chunker.js +121 -0
  29. package/dist/embed/chunker.js.map +1 -0
  30. package/dist/embed/cmd-hook.d.ts +21 -0
  31. package/dist/embed/cmd-hook.js +100 -0
  32. package/dist/embed/cmd-hook.js.map +1 -0
  33. package/dist/embed/config.d.ts +61 -0
  34. package/dist/embed/config.js +109 -0
  35. package/dist/embed/config.js.map +1 -0
  36. package/dist/embed/hook.d.ts +38 -0
  37. package/dist/embed/hook.js +56 -0
  38. package/dist/embed/hook.js.map +1 -0
  39. package/dist/embed/http-hook.d.ts +13 -0
  40. package/dist/embed/http-hook.js +39 -0
  41. package/dist/embed/http-hook.js.map +1 -0
  42. package/dist/embed/worker.d.ts +62 -0
  43. package/dist/embed/worker.js +228 -0
  44. package/dist/embed/worker.js.map +1 -0
  45. package/dist/fixtures/hwe/characters/albion-ever.md +12 -0
  46. package/dist/fixtures/hwe/characters/cent.md +11 -0
  47. package/dist/fixtures/hwe/concepts/cent-demiurge-resonance.md +10 -0
  48. package/dist/fixtures/hwe/concepts/phase-looper.md +10 -0
  49. package/dist/fixtures/hwe/entities/demiurge.md +11 -0
  50. package/dist/fixtures/hwe/entities/monad.md +11 -0
  51. package/dist/fixtures/hwe/moc/globocorp-network.md +19 -0
  52. package/dist/fixtures/hwe/organizations/globocorp.md +11 -0
  53. package/dist/fixtures/hwe/readme.md +24 -0
  54. package/dist/fixtures/starship/crew/aria-okonkwo.md +14 -0
  55. package/dist/fixtures/starship/crew/bexley-orr.md +14 -0
  56. package/dist/fixtures/starship/crew/dax-thorne.md +14 -0
  57. package/dist/fixtures/starship/crew/isolde-marsh.md +16 -0
  58. package/dist/fixtures/starship/crew/kestrel-vance.md +15 -0
  59. package/dist/fixtures/starship/crew/quill-vasquez.md +14 -0
  60. package/dist/fixtures/starship/crew/soren-halloway.md +16 -0
  61. package/dist/fixtures/starship/encounters/the-drift-choir.md +14 -0
  62. package/dist/fixtures/starship/encounters/the-hollow-signal.md +16 -0
  63. package/dist/fixtures/starship/encounters/the-wandering-buoy.md +14 -0
  64. package/dist/fixtures/starship/equipment/coolant-loop-b.md +13 -0
  65. package/dist/fixtures/starship/equipment/emergency-ration-bars.md +12 -0
  66. package/dist/fixtures/starship/equipment/long-range-sensors.md +13 -0
  67. package/dist/fixtures/starship/equipment/plasma-manifold-3.md +15 -0
  68. package/dist/fixtures/starship/equipment/shuttle-corvid.md +13 -0
  69. package/dist/fixtures/starship/logs/marsh-4419-1.md +13 -0
  70. package/dist/fixtures/starship/logs/okonkwo-4415-1.md +13 -0
  71. package/dist/fixtures/starship/logs/orr-4413-1.md +13 -0
  72. package/dist/fixtures/starship/logs/orr-4420-1.md +12 -0
  73. package/dist/fixtures/starship/logs/thorne-4413-2.md +13 -0
  74. package/dist/fixtures/starship/logs/vance-4419-2.md +13 -0
  75. package/dist/fixtures/starship/misc/the-galley-ficus.md +11 -0
  76. package/dist/fixtures/starship/missions/the-cinder-run.md +17 -0
  77. package/dist/fixtures/starship/missions/the-drift-choir.md +17 -0
  78. package/dist/fixtures/starship/missions/the-hollow-signal.md +17 -0
  79. package/dist/fixtures/starship/missions/the-silent-beacon.md +17 -0
  80. package/dist/fixtures/starship/moc/crew.md +19 -0
  81. package/dist/fixtures/starship/moc/encounters.md +14 -0
  82. package/dist/fixtures/starship/moc/missions.md +15 -0
  83. package/dist/fixtures/starship/readme.md +60 -0
  84. package/dist/index.d.ts +1 -0
  85. package/dist/index.js +3 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/kernel/auth/glob.d.ts +46 -0
  88. package/dist/kernel/auth/glob.js +112 -0
  89. package/dist/kernel/auth/glob.js.map +1 -0
  90. package/dist/kernel/auth/scope.d.ts +53 -0
  91. package/dist/kernel/auth/scope.js +83 -0
  92. package/dist/kernel/auth/scope.js.map +1 -0
  93. package/dist/kernel/casefold.d.ts +37 -0
  94. package/dist/kernel/casefold.js +44 -0
  95. package/dist/kernel/casefold.js.map +1 -0
  96. package/dist/kernel/constants.d.ts +21 -0
  97. package/dist/kernel/constants.js +22 -0
  98. package/dist/kernel/constants.js.map +1 -0
  99. package/dist/kernel/context.d.ts +70 -0
  100. package/dist/kernel/context.js +114 -0
  101. package/dist/kernel/context.js.map +1 -0
  102. package/dist/kernel/deletion.d.ts +50 -0
  103. package/dist/kernel/deletion.js +83 -0
  104. package/dist/kernel/deletion.js.map +1 -0
  105. package/dist/kernel/diff.d.ts +36 -0
  106. package/dist/kernel/diff.js +61 -0
  107. package/dist/kernel/diff.js.map +1 -0
  108. package/dist/kernel/errors.d.ts +37 -0
  109. package/dist/kernel/errors.js +55 -0
  110. package/dist/kernel/errors.js.map +1 -0
  111. package/dist/kernel/frontmatter-input.d.ts +32 -0
  112. package/dist/kernel/frontmatter-input.js +85 -0
  113. package/dist/kernel/frontmatter-input.js.map +1 -0
  114. package/dist/kernel/graph.d.ts +34 -0
  115. package/dist/kernel/graph.js +559 -0
  116. package/dist/kernel/graph.js.map +1 -0
  117. package/dist/kernel/history.d.ts +74 -0
  118. package/dist/kernel/history.js +143 -0
  119. package/dist/kernel/history.js.map +1 -0
  120. package/dist/kernel/kernel.d.ts +162 -0
  121. package/dist/kernel/kernel.js +675 -0
  122. package/dist/kernel/kernel.js.map +1 -0
  123. package/dist/kernel/path-config.d.ts +101 -0
  124. package/dist/kernel/path-config.js +171 -0
  125. package/dist/kernel/path-config.js.map +1 -0
  126. package/dist/kernel/query/ast.d.ts +24 -0
  127. package/dist/kernel/query/ast.js +52 -0
  128. package/dist/kernel/query/ast.js.map +1 -0
  129. package/dist/kernel/query/cel-parse.d.ts +37 -0
  130. package/dist/kernel/query/cel-parse.js +88 -0
  131. package/dist/kernel/query/cel-parse.js.map +1 -0
  132. package/dist/kernel/query/degrees.d.ts +31 -0
  133. package/dist/kernel/query/degrees.js +135 -0
  134. package/dist/kernel/query/degrees.js.map +1 -0
  135. package/dist/kernel/query/graph-ast.d.ts +51 -0
  136. package/dist/kernel/query/graph-ast.js +139 -0
  137. package/dist/kernel/query/graph-ast.js.map +1 -0
  138. package/dist/kernel/query/query.d.ts +56 -0
  139. package/dist/kernel/query/query.js +276 -0
  140. package/dist/kernel/query/query.js.map +1 -0
  141. package/dist/kernel/validation.d.ts +64 -0
  142. package/dist/kernel/validation.js +183 -0
  143. package/dist/kernel/validation.js.map +1 -0
  144. package/dist/kernel/version-id.d.ts +10 -0
  145. package/dist/kernel/version-id.js +21 -0
  146. package/dist/kernel/version-id.js.map +1 -0
  147. package/dist/kernel/wire.d.ts +148 -0
  148. package/dist/kernel/wire.js +6 -0
  149. package/dist/kernel/wire.js.map +1 -0
  150. package/dist/links/backfill.d.ts +28 -0
  151. package/dist/links/backfill.js +33 -0
  152. package/dist/links/backfill.js.map +1 -0
  153. package/dist/links/extract.d.ts +29 -0
  154. package/dist/links/extract.js +233 -0
  155. package/dist/links/extract.js.map +1 -0
  156. package/dist/links/link-config.d.ts +70 -0
  157. package/dist/links/link-config.js +107 -0
  158. package/dist/links/link-config.js.map +1 -0
  159. package/dist/links/maintain.d.ts +37 -0
  160. package/dist/links/maintain.js +91 -0
  161. package/dist/links/maintain.js.map +1 -0
  162. package/dist/links/repair.d.ts +46 -0
  163. package/dist/links/repair.js +96 -0
  164. package/dist/links/repair.js.map +1 -0
  165. package/dist/links/resolve.d.ts +41 -0
  166. package/dist/links/resolve.js +121 -0
  167. package/dist/links/resolve.js.map +1 -0
  168. package/dist/links/stale.d.ts +32 -0
  169. package/dist/links/stale.js +73 -0
  170. package/dist/links/stale.js.map +1 -0
  171. package/dist/markdown/content-hash.d.ts +34 -0
  172. package/dist/markdown/content-hash.js +46 -0
  173. package/dist/markdown/content-hash.js.map +1 -0
  174. package/dist/markdown/frontmatter.d.ts +69 -0
  175. package/dist/markdown/frontmatter.js +147 -0
  176. package/dist/markdown/frontmatter.js.map +1 -0
  177. package/dist/markdown/hash-backfill.d.ts +22 -0
  178. package/dist/markdown/hash-backfill.js +43 -0
  179. package/dist/markdown/hash-backfill.js.map +1 -0
  180. package/dist/mcp/query-syntax.d.ts +20 -0
  181. package/dist/mcp/query-syntax.js +194 -0
  182. package/dist/mcp/query-syntax.js.map +1 -0
  183. package/dist/mcp/render.d.ts +31 -0
  184. package/dist/mcp/render.js +110 -0
  185. package/dist/mcp/render.js.map +1 -0
  186. package/dist/mcp/server.d.ts +60 -0
  187. package/dist/mcp/server.js +170 -0
  188. package/dist/mcp/server.js.map +1 -0
  189. package/dist/mcp/tools.d.ts +93 -0
  190. package/dist/mcp/tools.js +1218 -0
  191. package/dist/mcp/tools.js.map +1 -0
  192. package/dist/rest/conditional.d.ts +37 -0
  193. package/dist/rest/conditional.js +58 -0
  194. package/dist/rest/conditional.js.map +1 -0
  195. package/dist/rest/negotiate.d.ts +33 -0
  196. package/dist/rest/negotiate.js +54 -0
  197. package/dist/rest/negotiate.js.map +1 -0
  198. package/dist/rest/routes.d.ts +37 -0
  199. package/dist/rest/routes.js +744 -0
  200. package/dist/rest/routes.js.map +1 -0
  201. package/dist/seed/fixture-seed.d.ts +35 -0
  202. package/dist/seed/fixture-seed.js +75 -0
  203. package/dist/seed/fixture-seed.js.map +1 -0
  204. package/dist/seed/starship-config.d.ts +3 -0
  205. package/dist/seed/starship-config.js +5 -0
  206. package/dist/seed/starship-config.js.map +1 -0
  207. package/dist/server/headers.d.ts +36 -0
  208. package/dist/server/headers.js +30 -0
  209. package/dist/server/headers.js.map +1 -0
  210. package/dist/server/http-error.d.ts +53 -0
  211. package/dist/server/http-error.js +104 -0
  212. package/dist/server/http-error.js.map +1 -0
  213. package/dist/server/serve.d.ts +56 -0
  214. package/dist/server/serve.js +135 -0
  215. package/dist/server/serve.js.map +1 -0
  216. package/dist/shell/audit.d.ts +32 -0
  217. package/dist/shell/audit.js +28 -0
  218. package/dist/shell/audit.js.map +1 -0
  219. package/dist/shell/guard.d.ts +50 -0
  220. package/dist/shell/guard.js +176 -0
  221. package/dist/shell/guard.js.map +1 -0
  222. package/dist/shell/keys.d.ts +36 -0
  223. package/dist/shell/keys.js +64 -0
  224. package/dist/shell/keys.js.map +1 -0
  225. package/dist/shell/login.d.ts +56 -0
  226. package/dist/shell/login.js +130 -0
  227. package/dist/shell/login.js.map +1 -0
  228. package/dist/shell/oidc.d.ts +62 -0
  229. package/dist/shell/oidc.js +102 -0
  230. package/dist/shell/oidc.js.map +1 -0
  231. package/dist/shell/policy.d.ts +100 -0
  232. package/dist/shell/policy.js +232 -0
  233. package/dist/shell/policy.js.map +1 -0
  234. package/dist/shell/proxy-policy.d.ts +34 -0
  235. package/dist/shell/proxy-policy.js +120 -0
  236. package/dist/shell/proxy-policy.js.map +1 -0
  237. package/dist/shell/proxy.d.ts +47 -0
  238. package/dist/shell/proxy.js +253 -0
  239. package/dist/shell/proxy.js.map +1 -0
  240. package/dist/shell/serve.d.ts +86 -0
  241. package/dist/shell/serve.js +0 -0
  242. package/dist/shell/serve.js.map +1 -0
  243. package/dist/shell/stdio.d.ts +55 -0
  244. package/dist/shell/stdio.js +63 -0
  245. package/dist/shell/stdio.js.map +1 -0
  246. package/dist/storage/registry.d.ts +20 -0
  247. package/dist/storage/registry.js +38 -0
  248. package/dist/storage/registry.js.map +1 -0
  249. package/dist/storage/search-plan.d.ts +93 -0
  250. package/dist/storage/search-plan.js +15 -0
  251. package/dist/storage/search-plan.js.map +1 -0
  252. package/dist/storage/types.d.ts +448 -0
  253. package/dist/storage/types.js +14 -0
  254. package/dist/storage/types.js.map +1 -0
  255. package/dist/storage/versions-since.d.ts +72 -0
  256. package/dist/storage/versions-since.js +92 -0
  257. package/dist/storage/versions-since.js.map +1 -0
  258. package/dist/storage-postgres/adapter.d.ts +17 -0
  259. package/dist/storage-postgres/adapter.js +782 -0
  260. package/dist/storage-postgres/adapter.js.map +1 -0
  261. package/dist/storage-postgres/compile-postgres.d.ts +22 -0
  262. package/dist/storage-postgres/compile-postgres.js +830 -0
  263. package/dist/storage-postgres/compile-postgres.js.map +1 -0
  264. package/dist/storage-postgres/errors.d.ts +34 -0
  265. package/dist/storage-postgres/errors.js +50 -0
  266. package/dist/storage-postgres/errors.js.map +1 -0
  267. package/dist/storage-postgres/migrations/0001_init.sql +113 -0
  268. package/dist/storage-postgres/migrations/0002_content_hash.sql +7 -0
  269. package/dist/storage-postgres/migrations/index.d.ts +22 -0
  270. package/dist/storage-postgres/migrations/index.js +70 -0
  271. package/dist/storage-postgres/migrations/index.js.map +1 -0
  272. package/dist/storage-sqlite/adapter.d.ts +2 -0
  273. package/dist/storage-sqlite/adapter.js +688 -0
  274. package/dist/storage-sqlite/adapter.js.map +1 -0
  275. package/dist/storage-sqlite/compile-filter.d.ts +41 -0
  276. package/dist/storage-sqlite/compile-filter.js +881 -0
  277. package/dist/storage-sqlite/compile-filter.js.map +1 -0
  278. package/dist/storage-sqlite/compile-sqlite.d.ts +19 -0
  279. package/dist/storage-sqlite/compile-sqlite.js +176 -0
  280. package/dist/storage-sqlite/compile-sqlite.js.map +1 -0
  281. package/dist/storage-sqlite/migrations/0001_init.sql +123 -0
  282. package/dist/storage-sqlite/migrations/0002_content_hash.sql +7 -0
  283. package/dist/storage-sqlite/migrations/index.d.ts +6 -0
  284. package/dist/storage-sqlite/migrations/index.js +41 -0
  285. package/dist/storage-sqlite/migrations/index.js.map +1 -0
  286. package/dist/storage-sqlite/vec.d.ts +40 -0
  287. package/dist/storage-sqlite/vec.js +62 -0
  288. package/dist/storage-sqlite/vec.js.map +1 -0
  289. package/dist/sync/cursor.d.ts +36 -0
  290. package/dist/sync/cursor.js +66 -0
  291. package/dist/sync/cursor.js.map +1 -0
  292. package/dist/sync/daemon.d.ts +40 -0
  293. package/dist/sync/daemon.js +202 -0
  294. package/dist/sync/daemon.js.map +1 -0
  295. package/dist/sync/feed.d.ts +38 -0
  296. package/dist/sync/feed.js +125 -0
  297. package/dist/sync/feed.js.map +1 -0
  298. package/dist/sync/fs-store.d.ts +8 -0
  299. package/dist/sync/fs-store.js +76 -0
  300. package/dist/sync/fs-store.js.map +1 -0
  301. package/dist/sync/intrinsics.d.ts +52 -0
  302. package/dist/sync/intrinsics.js +76 -0
  303. package/dist/sync/intrinsics.js.map +1 -0
  304. package/dist/sync/paths.d.ts +38 -0
  305. package/dist/sync/paths.js +56 -0
  306. package/dist/sync/paths.js.map +1 -0
  307. package/dist/sync/push.d.ts +48 -0
  308. package/dist/sync/push.js +328 -0
  309. package/dist/sync/push.js.map +1 -0
  310. package/dist/sync/reconcile.d.ts +54 -0
  311. package/dist/sync/reconcile.js +252 -0
  312. package/dist/sync/reconcile.js.map +1 -0
  313. package/dist/sync/run.d.ts +27 -0
  314. package/dist/sync/run.js +46 -0
  315. package/dist/sync/run.js.map +1 -0
  316. package/dist/version.d.ts +2 -0
  317. package/dist/version.js +5 -0
  318. package/dist/version.js.map +1 -0
  319. package/package.json +80 -0
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Startup reconciliation (sync/history plan §4.9) — the entirety of
3
+ * `mrplex sync --once`. No watcher, no remote deletes (by construction, §4.6).
4
+ *
5
+ * The pass walks the remote live set (history.index through a safe head R) and
6
+ * the local files, then resolves each path/identity against the §4.9 table.
7
+ * Every verdict is deterministic and non-destructive: local edits are pushed,
8
+ * clean local copies adopt remote provenance in place, and true conflicts park
9
+ * the remote current as an ignored sibling rather than clobbering local bytes.
10
+ *
11
+ * This module is transport-agnostic: it drives a `KernelClient` and a small
12
+ * `FileStore` seam (real fs in `fs-store.ts`, in-memory in tests), so the whole
13
+ * §4.9 table is testable against a local kernel without touching disk.
14
+ */
15
+ import { withVersionSuffix } from "../kernel/deletion.js";
16
+ import { KernelError } from "../kernel/errors.js";
17
+ import { extractSystemProperties, split } from "../markdown/frontmatter.js";
18
+ import { isDirty, isIgnored, readFileIntrinsics, renderIgnoredSibling, renderMaterialized, } from "./intrinsics.js";
19
+ /**
20
+ * Run the full §4.9 reconciliation once. Returns the safe head R (the cursor to
21
+ * persist) and the list of actions taken (or planned, under dryRun).
22
+ */
23
+ export async function reconcileOnce(client, store, scope, opts) {
24
+ const actions = [];
25
+ const dryRun = opts.dryRun ?? false;
26
+ const log = opts.log ?? (() => { });
27
+ // 1. Enumerate the remote live set through a safe head R (§3.4). Keyset-page.
28
+ const remoteByPath = new Map();
29
+ let through;
30
+ let after;
31
+ for (;;) {
32
+ const page = await client.history.index({
33
+ repo: opts.repo,
34
+ through_version: through,
35
+ after_version: after,
36
+ });
37
+ through = page.through_version;
38
+ for (const item of page.items) {
39
+ if (scope.matches(item.path))
40
+ remoteByPath.set(item.path, item);
41
+ }
42
+ if (page.next_after_version === undefined)
43
+ break;
44
+ after = page.next_after_version;
45
+ }
46
+ const R = through ?? "";
47
+ // Index remote items by embedded version id too, for move detection (§4.7).
48
+ const remoteByVersion = new Map();
49
+ for (const item of remoteByPath.values())
50
+ remoteByVersion.set(item.version_id, item);
51
+ // 2. Walk local files (in scope; $sync: ignore excluded from the walk, §4.9).
52
+ const localPaths = (await store.list()).filter((p) => scope.matches(p));
53
+ const seenRemote = new Set();
54
+ for (const path of localPaths) {
55
+ const text = await store.read(path);
56
+ if (text === null)
57
+ continue; // vanished between list and read — skip
58
+ const intr = readFileIntrinsics(text);
59
+ if (isIgnored(intr)) {
60
+ actions.push({ path, verdict: "ignored" });
61
+ continue;
62
+ }
63
+ const remote = remoteByPath.get(path);
64
+ if (remote)
65
+ seenRemote.add(path);
66
+ const action = await resolveLocalPath(client, store, opts, dryRun, {
67
+ path,
68
+ intr,
69
+ remote,
70
+ remoteByVersion,
71
+ });
72
+ actions.push(action);
73
+ }
74
+ // 3. Remote docs with no local file → materialize (§4.9 row 9; the offline
75
+ // concession restoring deletes). Never a remote delete.
76
+ for (const [path, item] of remoteByPath) {
77
+ if (seenRemote.has(path))
78
+ continue;
79
+ if (!dryRun) {
80
+ const v = await client.docs.get_version(opts.repo, item.version_id);
81
+ await store.write(path, renderMaterialized(v));
82
+ }
83
+ actions.push({ path, verdict: "materialize", detail: "remote doc absent locally" });
84
+ }
85
+ for (const a of actions) {
86
+ if (a.verdict !== "clean" && a.verdict !== "skip") {
87
+ log(`${a.verdict}\t${a.path}${a.detail ? `\t(${a.detail})` : ""}`);
88
+ }
89
+ }
90
+ return { through_version: R, actions };
91
+ }
92
+ /** Resolve one local file against its remote counterpart (the §4.9 table). */
93
+ async function resolveLocalPath(client, store, opts, dryRun, ctx) {
94
+ const { path, intr, remote } = ctx;
95
+ const dirty = isDirty(intr);
96
+ if (remote) {
97
+ // A document lives at this path remotely.
98
+ if (intr.computed_hash === remote.content_hash) {
99
+ // Local user-bytes already equal the remote version — a clean equivalence
100
+ // even if the file has no embedded provenance (row 2) or stale intrinsics.
101
+ // Path equality alone never suffices; only this hash match licenses
102
+ // stamping the remote $version. Metadata-only, no server write.
103
+ if (intr.version === remote.version_id && intr.content_hash === remote.content_hash) {
104
+ return { path, verdict: "clean" };
105
+ }
106
+ if (!dryRun)
107
+ await materializeInPlace(client, store, opts.repo, path, remote.version_id);
108
+ return { path, verdict: "adopt", detail: "content matches remote; provenance repaired" };
109
+ }
110
+ if (!intr.version) {
111
+ // No embedded version and bytes differ from remote → occupied-path
112
+ // conflict (row 6). Never stamp divergent local bytes with remote id.
113
+ if (!dryRun)
114
+ await parkConflict(client, store, opts.repo, path, remote.version_id);
115
+ return { path, verdict: "conflict", detail: "occupied path, no local provenance" };
116
+ }
117
+ if (intr.version === remote.version_id) {
118
+ // Embedded version is the remote current.
119
+ if (!dirty)
120
+ return { path, verdict: "clean" };
121
+ // Local edit on top of the current → push (row 4).
122
+ if (!dryRun)
123
+ await pushEdit(client, store, opts.repo, path, intr.version);
124
+ return { path, verdict: "push", detail: "local edit on current" };
125
+ }
126
+ // Embedded version differs from remote current.
127
+ if (!dirty) {
128
+ // Local unedited but stale → fast-forward to remote current (row 3).
129
+ if (!dryRun)
130
+ await materializeVersion(client, store, opts.repo, path, remote.version_id);
131
+ return { path, verdict: "materialize", detail: "fast-forward to remote current" };
132
+ }
133
+ // Local edited AND remote advanced → conflict (row 5).
134
+ if (!dryRun)
135
+ await parkConflict(client, store, opts.repo, path, remote.version_id);
136
+ return { path, verdict: "conflict", detail: "local edit vs advanced remote" };
137
+ }
138
+ // No remote doc at this path.
139
+ const embeddedVersion = intr.version;
140
+ const known = embeddedVersion ? ctx.remoteByVersion.get(embeddedVersion) : undefined;
141
+ if (known && embeddedVersion) {
142
+ // Embedded version is known at a DIFFERENT remote path → a move (row 8).
143
+ // The clean/dirty + conflict subtleties of live moves belong to the daemon;
144
+ // for --once we push the move (put with the new path) when the local file
145
+ // carries the ancestry. A stale_prev downgrades to a conflict.
146
+ if (!dryRun) {
147
+ try {
148
+ await pushMove(client, store, opts.repo, path, embeddedVersion);
149
+ }
150
+ catch (err) {
151
+ if (err instanceof KernelError && err.code === "stale_prev") {
152
+ await parkConflictForCurrent(client, store, opts.repo, path, embeddedVersion);
153
+ return { path, verdict: "conflict", detail: "move raced remote change" };
154
+ }
155
+ throw err;
156
+ }
157
+ }
158
+ return { path, verdict: "push", detail: `move from ${known.path}` };
159
+ }
160
+ if (!intr.version) {
161
+ // No provenance, path absent remotely → a genuine local creation (row 7).
162
+ if (!dryRun)
163
+ await pushCreate(client, store, opts.repo, path);
164
+ return { path, verdict: "push", detail: "local creation" };
165
+ }
166
+ // Embedded version exists but the document is no longer live at this path and
167
+ // isn't known elsewhere → it was remotely deleted. Clean removes locally;
168
+ // dirty resurrects (push as create). Never discard dirty bytes (§4.9 edge).
169
+ if (!dirty) {
170
+ if (!dryRun)
171
+ await store.remove(path);
172
+ return { path, verdict: "delete-local", detail: "remote-deleted, local clean" };
173
+ }
174
+ if (!dryRun)
175
+ await pushCreate(client, store, opts.repo, path);
176
+ return { path, verdict: "resurrect", detail: "remote-deleted, local dirty" };
177
+ }
178
+ // --- effecting helpers -------------------------------------------------------
179
+ async function readUserContent(store, path) {
180
+ const text = (await store.read(path)) ?? "";
181
+ return stripToUserContent(text);
182
+ }
183
+ /** Split a file into stored-shape fields, dropping all `$*` intrinsic lines. */
184
+ function stripToUserContent(text) {
185
+ const lf = text.replace(/\r\n/g, "\n");
186
+ // Reuse the same split/strip path the hash uses so bytes are canonical.
187
+ const { frontmatter_raw, body } = split(lf);
188
+ return { frontmatter_raw: extractSystemProperties(frontmatter_raw).raw, body };
189
+ }
190
+ async function materializeVersion(client, store, repo, path, versionId) {
191
+ const v = await client.docs.get_version(repo, versionId);
192
+ await store.write(path, renderMaterialized(v));
193
+ }
194
+ /** Repair a clean local file's embedded provenance to the given version. */
195
+ async function materializeInPlace(client, store, repo, path, versionId) {
196
+ // The content already equals the version; re-render from the authoritative
197
+ // remote version so intrinsics are exact. Keep mtime so a metadata-only
198
+ // stamp cannot win an Obsidian/iCloud race against unsynced typing.
199
+ const v = await client.docs.get_version(repo, versionId);
200
+ await store.write(path, renderMaterialized(v), { preserveMtime: true });
201
+ }
202
+ async function pushEdit(client, store, repo, path, prevVersionId) {
203
+ const { frontmatter_raw, body } = await readUserContent(store, path);
204
+ const v = await client.docs.put(repo, prevVersionId, path, { frontmatter_raw, body });
205
+ await store.write(path, renderMaterialized(v), { preserveMtime: true });
206
+ }
207
+ async function pushMove(client, store, repo, path, prevVersionId) {
208
+ const { frontmatter_raw, body } = await readUserContent(store, path);
209
+ // A put whose path differs from prev's path is a move preserving identity.
210
+ const v = await client.docs.put(repo, prevVersionId, path, { frontmatter_raw, body });
211
+ await store.write(path, renderMaterialized(v), { preserveMtime: true });
212
+ }
213
+ async function pushCreate(client, store, repo, path) {
214
+ const { frontmatter_raw, body } = await readUserContent(store, path);
215
+ try {
216
+ const v = await client.docs.create(repo, path, { frontmatter_raw, body });
217
+ await store.write(path, renderMaterialized(v), { preserveMtime: true });
218
+ }
219
+ catch (err) {
220
+ if (err instanceof KernelError && err.code === "create_conflict") {
221
+ // A doc appeared at this path since the index scan; treat the occupied
222
+ // path as a conflict rather than clobbering it.
223
+ const current = err.data.current_version_id;
224
+ if (current)
225
+ await parkConflict(client, store, repo, path, current);
226
+ return;
227
+ }
228
+ throw err;
229
+ }
230
+ }
231
+ /**
232
+ * Park a conflict (§4.8): keep the local file's bytes and path untouched;
233
+ * materialize the remote current beside it as `<name>-<version_id>.md` with
234
+ * `$sync: ignore`. Collision-safe (version ids are unique), so replay never
235
+ * sprays duplicates.
236
+ */
237
+ async function parkConflict(client, store, repo, path, remoteVersionId) {
238
+ const v = await client.docs.get_version(repo, remoteVersionId);
239
+ const siblingPath = withVersionSuffix(path, remoteVersionId);
240
+ await store.write(siblingPath, renderIgnoredSibling(v));
241
+ }
242
+ /** Conflict park keyed off the doc's *current* remote version (move race). */
243
+ async function parkConflictForCurrent(client, store, repo, path, embeddedVersionId) {
244
+ // Resolve the document's current version from the embedded (now-superseded)
245
+ // one, then park it. get_version gives us the doc; docs.get by its path finds
246
+ // the live current.
247
+ const superseded = await client.docs.get_version(repo, embeddedVersionId);
248
+ const current = await client.docs.get(repo, superseded.path);
249
+ const siblingPath = withVersionSuffix(path, current.version_id);
250
+ await store.write(siblingPath, renderIgnoredSibling(current));
251
+ }
252
+ //# sourceMappingURL=reconcile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconcile.js","sourceRoot":"","sources":["../../src/sync/reconcile.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EAAE,uBAAuB,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EAEL,OAAO,EACP,SAAS,EACT,kBAAkB,EAClB,oBAAoB,EACpB,kBAAkB,GACnB,MAAM,iBAAiB,CAAC;AA+CzB;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAoB,EACpB,KAAgB,EAChB,KAAkB,EAClB,IAAsB;IAEtB,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;IAEnC,8EAA8E;IAC9E,MAAM,YAAY,GAAG,IAAI,GAAG,EAAqB,CAAC;IAClD,IAAI,OAA2B,CAAC;IAChC,IAAI,KAAyB,CAAC;IAC9B,SAAS,CAAC;QACR,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC;YACtC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,eAAe,EAAE,OAAO;YACxB,aAAa,EAAE,KAAK;SACrB,CAAC,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC;QAC/B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;gBAAE,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAClE,CAAC;QACD,IAAI,IAAI,CAAC,kBAAkB,KAAK,SAAS;YAAE,MAAM;QACjD,KAAK,GAAG,IAAI,CAAC,kBAAkB,CAAC;IAClC,CAAC;IACD,MAAM,CAAC,GAAG,OAAO,IAAI,EAAE,CAAC;IAExB,4EAA4E;IAC5E,MAAM,eAAe,GAAG,IAAI,GAAG,EAAqB,CAAC;IACrD,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,MAAM,EAAE;QAAE,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAErF,8EAA8E;IAC9E,MAAM,UAAU,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IACxE,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAC;IAErC,KAAK,MAAM,IAAI,IAAI,UAAU,EAAE,CAAC;QAC9B,MAAM,IAAI,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,IAAI,KAAK,IAAI;YAAE,SAAS,CAAC,wCAAwC;QACrE,MAAM,IAAI,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YACpB,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAC;YAC3C,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,MAAM;YAAE,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE;YACjE,IAAI;YACJ,IAAI;YACJ,MAAM;YACN,eAAe;SAChB,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC;IAED,2EAA2E;IAC3E,2DAA2D;IAC3D,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,YAAY,EAAE,CAAC;QACxC,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QACnC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;YACpE,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;QACjD,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,2BAA2B,EAAE,CAAC,CAAC;IACtF,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,MAAM,EAAE,CAAC;YAClD,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrE,CAAC;IACH,CAAC;IACD,OAAO,EAAE,eAAe,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC;AACzC,CAAC;AAED,8EAA8E;AAC9E,KAAK,UAAU,gBAAgB,CAC7B,MAAoB,EACpB,KAAgB,EAChB,IAAsB,EACtB,MAAe,EACf,GAKC;IAED,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B,IAAI,MAAM,EAAE,CAAC;QACX,0CAA0C;QAC1C,IAAI,IAAI,CAAC,aAAa,KAAK,MAAM,CAAC,YAAY,EAAE,CAAC;YAC/C,0EAA0E;YAC1E,2EAA2E;YAC3E,oEAAoE;YACpE,gEAAgE;YAChE,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,CAAC,UAAU,IAAI,IAAI,CAAC,YAAY,KAAK,MAAM,CAAC,YAAY,EAAE,CAAC;gBACpF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;YACpC,CAAC;YACD,IAAI,CAAC,MAAM;gBAAE,MAAM,kBAAkB,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;YACzF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,6CAA6C,EAAE,CAAC;QAC3F,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,mEAAmE;YACnE,sEAAsE;YACtE,IAAI,CAAC,MAAM;gBAAE,MAAM,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;YACnF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,oCAAoC,EAAE,CAAC;QACrF,CAAC;QACD,IAAI,IAAI,CAAC,OAAO,KAAK,MAAM,CAAC,UAAU,EAAE,CAAC;YACvC,0CAA0C;YAC1C,IAAI,CAAC,KAAK;gBAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;YAC9C,mDAAmD;YACnD,IAAI,CAAC,MAAM;gBAAE,MAAM,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC;QACpE,CAAC;QACD,gDAAgD;QAChD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,qEAAqE;YACrE,IAAI,CAAC,MAAM;gBAAE,MAAM,kBAAkB,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;YACzF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,EAAE,gCAAgC,EAAE,CAAC;QACpF,CAAC;QACD,uDAAuD;QACvD,IAAI,CAAC,MAAM;YAAE,MAAM,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;QACnF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,+BAA+B,EAAE,CAAC;IAChF,CAAC;IAED,8BAA8B;IAC9B,MAAM,eAAe,GAAG,IAAI,CAAC,OAAO,CAAC;IACrC,MAAM,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACrF,IAAI,KAAK,IAAI,eAAe,EAAE,CAAC;QAC7B,yEAAyE;QACzE,4EAA4E;QAC5E,0EAA0E;QAC1E,+DAA+D;QAC/D,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,MAAM,QAAQ,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC;YAClE,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAI,GAAG,YAAY,WAAW,IAAI,GAAG,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBAC5D,MAAM,sBAAsB,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,eAAe,CAAC,CAAC;oBAC9E,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,0BAA0B,EAAE,CAAC;gBAC3E,CAAC;gBACD,MAAM,GAAG,CAAC;YACZ,CAAC;QACH,CAAC;QACD,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,KAAK,CAAC,IAAI,EAAE,EAAE,CAAC;IACtE,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QAClB,0EAA0E;QAC1E,IAAI,CAAC,MAAM;YAAE,MAAM,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC9D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,CAAC;IAC7D,CAAC;IAED,8EAA8E;IAC9E,0EAA0E;IAC1E,4EAA4E;IAC5E,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,IAAI,CAAC,MAAM;YAAE,MAAM,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACtC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,EAAE,6BAA6B,EAAE,CAAC;IAClF,CAAC;IACD,IAAI,CAAC,MAAM;QAAE,MAAM,UAAU,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9D,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,6BAA6B,EAAE,CAAC;AAC/E,CAAC;AAED,gFAAgF;AAEhF,KAAK,UAAU,eAAe,CAC5B,KAAgB,EAChB,IAAY;IAEZ,MAAM,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5C,OAAO,kBAAkB,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC;AAED,gFAAgF;AAChF,SAAS,kBAAkB,CAAC,IAAY;IACtC,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACvC,wEAAwE;IACxE,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC;IAC5C,OAAO,EAAE,eAAe,EAAE,uBAAuB,CAAC,eAAe,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC;AACjF,CAAC;AAED,KAAK,UAAU,kBAAkB,CAC/B,MAAoB,EACpB,KAAgB,EAChB,IAAY,EACZ,IAAY,EACZ,SAAiB;IAEjB,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACzD,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC;AAED,4EAA4E;AAC5E,KAAK,UAAU,kBAAkB,CAC/B,MAAoB,EACpB,KAAgB,EAChB,IAAY,EACZ,IAAY,EACZ,SAAiB;IAEjB,2EAA2E;IAC3E,wEAAwE;IACxE,oEAAoE;IACpE,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACzD,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,MAAoB,EACpB,KAAgB,EAChB,IAAY,EACZ,IAAY,EACZ,aAAqB;IAErB,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,GAAG,MAAM,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACrE,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;IACtF,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,KAAK,UAAU,QAAQ,CACrB,MAAoB,EACpB,KAAgB,EAChB,IAAY,EACZ,IAAY,EACZ,aAAqB;IAErB,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,GAAG,MAAM,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACrE,2EAA2E;IAC3E,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;IACtF,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED,KAAK,UAAU,UAAU,CACvB,MAAoB,EACpB,KAAgB,EAChB,IAAY,EACZ,IAAY;IAEZ,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,GAAG,MAAM,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IACrE,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1E,MAAM,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,kBAAkB,CAAC,CAAC,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,WAAW,IAAI,GAAG,CAAC,IAAI,KAAK,iBAAiB,EAAE,CAAC;YACjE,uEAAuE;YACvE,gDAAgD;YAChD,MAAM,OAAO,GAAI,GAAG,CAAC,IAAwC,CAAC,kBAAkB,CAAC;YACjF,IAAI,OAAO;gBAAE,MAAM,YAAY,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;YACpE,OAAO;QACT,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,KAAK,UAAU,YAAY,CACzB,MAAoB,EACpB,KAAgB,EAChB,IAAY,EACZ,IAAY,EACZ,eAAuB;IAEvB,MAAM,CAAC,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAC/D,MAAM,WAAW,GAAG,iBAAiB,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IAC7D,MAAM,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,8EAA8E;AAC9E,KAAK,UAAU,sBAAsB,CACnC,MAAoB,EACpB,KAAgB,EAChB,IAAY,EACZ,IAAY,EACZ,iBAAyB;IAEzB,4EAA4E;IAC5E,8EAA8E;IAC9E,oBAAoB;IACpB,MAAM,UAAU,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC;IAC1E,MAAM,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,CAAC;IAC7D,MAAM,WAAW,GAAG,iBAAiB,CAAC,IAAI,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IAChE,MAAM,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,oBAAoB,CAAC,OAAO,CAAC,CAAC,CAAC;AAChE,CAAC"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * `mrplex sync --once` orchestration (sync/history plan §4.9). Runs the full
3
+ * startup reconciliation, then applies the feed from R and advances the cursor.
4
+ * The daemon (M8) layers a watcher + poll loop over these same pieces.
5
+ */
6
+ import type { KernelClient } from "../client/kernel-client.js";
7
+ import { type ReconcileReport } from "./reconcile.js";
8
+ export type SyncOnceOptions = {
9
+ root: string;
10
+ repo: string;
11
+ server?: string;
12
+ database?: string;
13
+ include?: string[];
14
+ exclude?: string[];
15
+ dryRun?: boolean;
16
+ log?: (msg: string) => void;
17
+ };
18
+ export type SyncOnceReport = ReconcileReport & {
19
+ feed_applied: number;
20
+ };
21
+ /**
22
+ * The full once-pass: index reconciliation through R, then drain
23
+ * history.since(R) to catch anything that advanced during the scan, then
24
+ * persist the cursor. `--once` always performs the full reconciliation (§4.9),
25
+ * so it also restores offline deletes and propagates offline moves.
26
+ */
27
+ export declare function syncOnce(client: KernelClient, opts: SyncOnceOptions): Promise<SyncOnceReport>;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * `mrplex sync --once` orchestration (sync/history plan §4.9). Runs the full
3
+ * startup reconciliation, then applies the feed from R and advances the cursor.
4
+ * The daemon (M8) layers a watcher + poll loop over these same pieces.
5
+ */
6
+ import { readCursor, sourceFields, writeCursor } from "./cursor.js";
7
+ import { applyFeed } from "./feed.js";
8
+ import { createFsStore } from "./fs-store.js";
9
+ import { makeScopeFilter } from "./paths.js";
10
+ import { reconcileOnce } from "./reconcile.js";
11
+ /**
12
+ * The full once-pass: index reconciliation through R, then drain
13
+ * history.since(R) to catch anything that advanced during the scan, then
14
+ * persist the cursor. `--once` always performs the full reconciliation (§4.9),
15
+ * so it also restores offline deletes and propagates offline moves.
16
+ */
17
+ export async function syncOnce(client, opts) {
18
+ const store = createFsStore(opts.root);
19
+ const scope = makeScopeFilter({ include: opts.include, exclude: opts.exclude });
20
+ const report = await reconcileOnce(client, store, scope, {
21
+ repo: opts.repo,
22
+ dryRun: opts.dryRun,
23
+ log: opts.log,
24
+ });
25
+ if (opts.dryRun)
26
+ return { ...report, feed_applied: 0 };
27
+ // Apply the feed from R forward: documents that advanced mid-scan land here
28
+ // exactly once (§3.4 handoff invariant). The feed returns its final cursor.
29
+ const { cursor, applied } = await applyFeed(client, store, scope, {
30
+ repo: opts.repo,
31
+ since: report.through_version,
32
+ log: opts.log,
33
+ });
34
+ // Persist the cursor only after all filesystem effects complete (§4.3).
35
+ // Record the source as exactly one of server/database, falling back to
36
+ // whichever the existing marker carried so an incidental re-run doesn't drop
37
+ // it. server/database are mutually exclusive, so a set server wins outright.
38
+ const existing = await readCursor(opts.root);
39
+ await writeCursor(opts.root, {
40
+ ...sourceFields(opts.server, opts.database, existing),
41
+ repo: opts.repo,
42
+ last_synced_version_id: cursor,
43
+ });
44
+ return { ...report, feed_applied: applied };
45
+ }
46
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/sync/run.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAwB,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAerE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,MAAoB,EACpB,IAAqB;IAErB,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,KAAK,GAAG,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;IAEhF,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE;QACvD,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,GAAG,EAAE,IAAI,CAAC,GAAG;KACd,CAAC,CAAC;IAEH,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,GAAG,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC;IAEvD,4EAA4E;IAC5E,4EAA4E;IAC5E,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE;QAChE,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK,EAAE,MAAM,CAAC,eAAe;QAC7B,GAAG,EAAE,IAAI,CAAC,GAAG;KACd,CAAC,CAAC;IAEH,wEAAwE;IACxE,uEAAuE;IACvE,6EAA6E;IAC7E,6EAA6E;IAC7E,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,MAAM,WAAW,CAAC,IAAI,CAAC,IAAI,EAAE;QAC3B,GAAG,YAAY,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC;QACrD,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,sBAAsB,EAAE,MAAM;KAC/B,CAAC,CAAC;IAEH,OAAO,EAAE,GAAG,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,2 @@
1
+ /** Package version — single source for CLI and MCP server metadata. */
2
+ export declare const VERSION: string;
@@ -0,0 +1,5 @@
1
+ import { createRequire } from "node:module";
2
+ const require = createRequire(import.meta.url);
3
+ /** Package version — single source for CLI and MCP server metadata. */
4
+ export const VERSION = require("../package.json").version;
5
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAE/C,uEAAuE;AACvE,MAAM,CAAC,MAAM,OAAO,GAAW,OAAO,CAAC,iBAAiB,CAAC,CAAC,OAAiB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "mrplex",
3
+ "version": "0.0.1",
4
+ "description": "Markdown Repos, plexed. Turn Markdown folders into queryable, versioned, graph-aware knowledge stores.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Brendan Baldwin <brendan@usergenic.com>",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/usergenic/mrplex.git"
11
+ },
12
+ "homepage": "https://github.com/usergenic/mrplex#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/usergenic/mrplex/issues"
15
+ },
16
+ "keywords": [
17
+ "markdown",
18
+ "knowledge-base",
19
+ "notes",
20
+ "versioning",
21
+ "graph",
22
+ "backlinks",
23
+ "wikilinks",
24
+ "cel",
25
+ "mcp",
26
+ "semantic-search"
27
+ ],
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "bin": {
32
+ "mrplex": "./dist/cli/main.js"
33
+ },
34
+ "files": ["dist/"],
35
+ "scripts": {
36
+ "prepack": "npm run build",
37
+ "build": "tsc -p tsconfig.build.json && node scripts/copy-assets.mjs && node scripts/set-script-permissions.mjs",
38
+ "typecheck": "tsc --noEmit",
39
+ "lint": "biome check .",
40
+ "lint:fix": "biome check --write .",
41
+ "format": "biome format --write .",
42
+ "test": "vitest run",
43
+ "test:watch": "vitest",
44
+ "test:integration": "vitest run --config vitest.integration.config.ts",
45
+ "test:all": "vitest run && vitest run --config vitest.integration.config.ts",
46
+ "cli": "tsx src/cli/main.ts",
47
+ "seed": "tsx scripts/seed.ts",
48
+ "pg:up": "docker compose --profile postgres up -d",
49
+ "pg:down": "docker compose --profile postgres down",
50
+ "pg:reset": "docker compose --profile postgres down -v && docker compose --profile postgres up -d",
51
+ "pg:logs": "docker compose --profile postgres logs -f postgres"
52
+ },
53
+ "engines": {
54
+ "node": ">=20.11.0"
55
+ },
56
+ "dependencies": {
57
+ "@bufbuild/cel": "^0.6.0",
58
+ "@bufbuild/re2": "^0.6.0",
59
+ "@modelcontextprotocol/sdk": "^1.30.0",
60
+ "better-sqlite3": "^11.5.0",
61
+ "chokidar": "^5.0.0",
62
+ "commander": "^12.1.0",
63
+ "diff": "^9.0.0",
64
+ "jose": "^6.2.9",
65
+ "micromark": "^4.0.2",
66
+ "pg": "^8.23.0",
67
+ "sqlite-vec": "^0.1.9",
68
+ "yaml": "^2.6.0"
69
+ },
70
+ "devDependencies": {
71
+ "@biomejs/biome": "^1.9.4",
72
+ "@types/better-sqlite3": "^7.6.11",
73
+ "@types/diff": "^7.0.2",
74
+ "@types/node": "^22.9.0",
75
+ "@types/pg": "^8.21.0",
76
+ "tsx": "^4.19.2",
77
+ "typescript": "^5.6.3",
78
+ "vitest": "^4.1.10"
79
+ }
80
+ }