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,37 @@
1
+ /**
2
+ * Case & Unicode folding for path/slug IDENTITY — design §3.5.1 amendment
3
+ * (case-folding-plan.md WS1).
4
+ *
5
+ * `normalizeKey` computes the derived key that drives case-insensitive,
6
+ * Unicode-normalized uniqueness and by-key lookups. Storage stays
7
+ * case- and form-preserving (we store the author's exact bytes); this
8
+ * key is an index artifact, never surfaced on the wire (§3.3-style
9
+ * internal-only, decision 7).
10
+ *
11
+ * THE ONE AUTHORITY. Both storage adapters receive the pre-computed key
12
+ * from the kernel — neither calls SQL `lower()`, `COLLATE NOCASE`, or
13
+ * `citext`. That is deliberate: SQLite's `lower()` is ASCII-only without
14
+ * ICU, while Postgres's is locale-aware, so a functional index would
15
+ * silently diverge on non-ASCII input and break the §7.2 adapter-parity
16
+ * guarantee. Folding in JS, here, keeps the two engines identical.
17
+ *
18
+ * Strength (decision 4): **NFC + locale-invariant lowercase.** This folds
19
+ * all accented Latin/Greek/Cyrillic and the common case, and makes NFC/NFD
20
+ * spellings of the same text compare equal. It deliberately does NOT fold
21
+ * the German ß→ss, ligatures (fi→fi), or Greek final-sigma — those need the
22
+ * full Unicode default case-fold table, an additive upgrade later (the key
23
+ * is recomputed by a backfill, so strengthening it is non-breaking beyond a
24
+ * re-index). casefold.test.ts pins the exact boundary.
25
+ *
26
+ * `toLowerCase()` (NOT `toLocaleLowerCase()`) is used on purpose: a locale
27
+ * fold would map Turkish `I`→`ı`, making document identity depend on the
28
+ * server's locale. Identity must be locale-independent.
29
+ */
30
+ /**
31
+ * Fold a path or slug to its identity key. Idempotent, total, pure.
32
+ *
33
+ * normalizeKey("Alice.md") === "alice.md"
34
+ * normalizeKey("café.md" as NFD) === normalizeKey("café.md" as NFC)
35
+ * normalizeKey(normalizeKey(x)) === normalizeKey(x)
36
+ */
37
+ export declare function normalizeKey(s: string): string;
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Case & Unicode folding for path/slug IDENTITY — design §3.5.1 amendment
3
+ * (case-folding-plan.md WS1).
4
+ *
5
+ * `normalizeKey` computes the derived key that drives case-insensitive,
6
+ * Unicode-normalized uniqueness and by-key lookups. Storage stays
7
+ * case- and form-preserving (we store the author's exact bytes); this
8
+ * key is an index artifact, never surfaced on the wire (§3.3-style
9
+ * internal-only, decision 7).
10
+ *
11
+ * THE ONE AUTHORITY. Both storage adapters receive the pre-computed key
12
+ * from the kernel — neither calls SQL `lower()`, `COLLATE NOCASE`, or
13
+ * `citext`. That is deliberate: SQLite's `lower()` is ASCII-only without
14
+ * ICU, while Postgres's is locale-aware, so a functional index would
15
+ * silently diverge on non-ASCII input and break the §7.2 adapter-parity
16
+ * guarantee. Folding in JS, here, keeps the two engines identical.
17
+ *
18
+ * Strength (decision 4): **NFC + locale-invariant lowercase.** This folds
19
+ * all accented Latin/Greek/Cyrillic and the common case, and makes NFC/NFD
20
+ * spellings of the same text compare equal. It deliberately does NOT fold
21
+ * the German ß→ss, ligatures (fi→fi), or Greek final-sigma — those need the
22
+ * full Unicode default case-fold table, an additive upgrade later (the key
23
+ * is recomputed by a backfill, so strengthening it is non-breaking beyond a
24
+ * re-index). casefold.test.ts pins the exact boundary.
25
+ *
26
+ * `toLowerCase()` (NOT `toLocaleLowerCase()`) is used on purpose: a locale
27
+ * fold would map Turkish `I`→`ı`, making document identity depend on the
28
+ * server's locale. Identity must be locale-independent.
29
+ */
30
+ /**
31
+ * Fold a path or slug to its identity key. Idempotent, total, pure.
32
+ *
33
+ * normalizeKey("Alice.md") === "alice.md"
34
+ * normalizeKey("café.md" as NFD) === normalizeKey("café.md" as NFC)
35
+ * normalizeKey(normalizeKey(x)) === normalizeKey(x)
36
+ */
37
+ export function normalizeKey(s) {
38
+ // Fold case, then re-normalize: `toLowerCase()` can, for a few code
39
+ // points, emit a sequence that isn't NFC, which would break the
40
+ // idempotency contract (normalizeKey∘normalizeKey === normalizeKey).
41
+ // The trailing NFC pass makes the output a stable fixed point.
42
+ return s.normalize("NFC").toLowerCase().normalize("NFC");
43
+ }
44
+ //# sourceMappingURL=casefold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"casefold.js","sourceRoot":"","sources":["../../src/kernel/casefold.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,YAAY,CAAC,CAAS;IACpC,oEAAoE;IACpE,gEAAgE;IAChE,qEAAqE;IACrE,+DAA+D;IAC/D,OAAO,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Cross-cutting kernel constants. Kept small on purpose — this is not a
3
+ * grab-bag. Only things with more than one caller and no better home.
4
+ */
5
+ /**
6
+ * Intrinsic sigil — the leading character that marks an identifier as
7
+ * server-owned rather than user-authored. Single source of truth.
8
+ *
9
+ * Two surfaces share it:
10
+ *
11
+ * • Query filter syntax — `$path`, `$updated_at`, `$body`, and other
12
+ * intrinsics recognized by the CEL parser (see ../kernel/query/cel-parse.ts).
13
+ * • Frontmatter system properties — `$version` and (future) `$author`,
14
+ * `$updated_at`, etc., injected into GET responses and stripped on
15
+ * write (see ../markdown/frontmatter.ts).
16
+ *
17
+ * Not to be confused with `PathConfig.system_sigils` in wire.ts, which
18
+ * governs a different reservation entirely (path-segment prefixes like
19
+ * `.` / `:` gating hidden and deleted namespaces).
20
+ */
21
+ export declare const INTRINSIC_SIGIL = "$";
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Cross-cutting kernel constants. Kept small on purpose — this is not a
3
+ * grab-bag. Only things with more than one caller and no better home.
4
+ */
5
+ /**
6
+ * Intrinsic sigil — the leading character that marks an identifier as
7
+ * server-owned rather than user-authored. Single source of truth.
8
+ *
9
+ * Two surfaces share it:
10
+ *
11
+ * • Query filter syntax — `$path`, `$updated_at`, `$body`, and other
12
+ * intrinsics recognized by the CEL parser (see ../kernel/query/cel-parse.ts).
13
+ * • Frontmatter system properties — `$version` and (future) `$author`,
14
+ * `$updated_at`, etc., injected into GET responses and stripped on
15
+ * write (see ../markdown/frontmatter.ts).
16
+ *
17
+ * Not to be confused with `PathConfig.system_sigils` in wire.ts, which
18
+ * governs a different reservation entirely (path-segment prefixes like
19
+ * `.` / `:` gating hidden and deleted namespaces).
20
+ */
21
+ export const INTRINSIC_SIGIL = "$";
22
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/kernel/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * CallContext — the uniform first parameter to every kernel op (design §8,
3
+ * noauth plan §1).
4
+ *
5
+ * mrplex is a full-trust kernel: any caller that can reach it can do anything.
6
+ * There is no resolved identity, no token, no admin bit. What a caller supplies
7
+ * per call is:
8
+ *
9
+ * • `author` — an opaque string stamped on the versions it writes. The engine
10
+ * attaches no semantics (the `Full Name <email>` convention is caller-side).
11
+ * Defaults to "mrplex". Sanity-validated only (non-empty, no control chars,
12
+ * length-capped) — never parsed.
13
+ * • `scope` — optional read-visibility narrowing. Absent = everything visible.
14
+ * Present = the call sees only what the claims grant (silent filtering on
15
+ * `query`; `forbidden` on a targeted read outside the claim). This is the
16
+ * one enforcement seam a fronting shell cannot replicate from outside, so
17
+ * it stays in the engine — exposed as a plain input, not derived from a
18
+ * token.
19
+ */
20
+ /**
21
+ * A territory claim. `repo` is a slug, glob, or "*" — evaluated against the
22
+ * repos existing at call time, every call (no issuance snapshot, no id
23
+ * binding). `paths` is a gitignore-style path glob list (§8.2 semantics).
24
+ *
25
+ * Deliberately direction-neutral: a claim names repos/paths, not a direction.
26
+ * Meaning comes from where it sits — `ctx.scope` is read visibility; the
27
+ * auth-shell reuses the same type for its shell-enforced write matcher.
28
+ */
29
+ export type ScopeClaim = {
30
+ repo: string | string[];
31
+ paths?: string | string[];
32
+ };
33
+ export type CallContext = {
34
+ /** Writes: opaque author string. Default "mrplex". */
35
+ author?: string;
36
+ /** Reads: visibility claims. Absent = everything visible. */
37
+ scope?: ScopeClaim[];
38
+ };
39
+ /** Identity stamped on a write when the caller supplies no author. */
40
+ export declare const DEFAULT_AUTHOR = "mrplex";
41
+ /**
42
+ * Structurally validate an already-parsed value as `ScopeClaim[]`. This is the
43
+ * single validation path shared by every surface that accepts a scope — the
44
+ * `X-Mrplex-Scope` header (via [[parseScopeClaims]]), the `POST /query` body
45
+ * `scope` field, the MCP query tool-arg, and the CLI `--scope` flag. Routing
46
+ * all of them here means a claim missing `repo` (or with wrong types) is a loud
47
+ * `filter_invalid`, not a silent `deny_all` empty result (see the note in
48
+ * kernel/auth/scope.ts on how `normalizeClaims` treats a repo-less claim).
49
+ *
50
+ * Throws `KernelError("filter_invalid")` on bad input so surfaces map it to a
51
+ * 4xx uniformly rather than a 500.
52
+ */
53
+ export declare function validateScopeClaims(parsed: unknown): ScopeClaim[];
54
+ /**
55
+ * Parse a JSON string into `ScopeClaim[]`. Used to decode the `X-Mrplex-Scope`
56
+ * header and the CLI `--scope` flag. Throws `KernelError("filter_invalid")` on
57
+ * malformed input so a bad claim is a loud client error, not a silent
58
+ * full-access fallback.
59
+ */
60
+ export declare function parseScopeClaims(json: string): ScopeClaim[];
61
+ /**
62
+ * Resolve + validate the author for a write. Opaque: we sanity-check only
63
+ * (non-empty, no control characters, length-capped) and never parse the value.
64
+ * An empty/absent author yields the default "mrplex".
65
+ *
66
+ * Throws `KernelError("filter_invalid")` on bad input — the author is reachable
67
+ * verbatim from the `X-Mrplex-Author` header, so a control-char or over-length
68
+ * value is a client mistake and must stay in the 4xx band, not surface as a 500.
69
+ */
70
+ export declare function resolveAuthor(ctx: CallContext): string;
@@ -0,0 +1,114 @@
1
+ /**
2
+ * CallContext — the uniform first parameter to every kernel op (design §8,
3
+ * noauth plan §1).
4
+ *
5
+ * mrplex is a full-trust kernel: any caller that can reach it can do anything.
6
+ * There is no resolved identity, no token, no admin bit. What a caller supplies
7
+ * per call is:
8
+ *
9
+ * • `author` — an opaque string stamped on the versions it writes. The engine
10
+ * attaches no semantics (the `Full Name <email>` convention is caller-side).
11
+ * Defaults to "mrplex". Sanity-validated only (non-empty, no control chars,
12
+ * length-capped) — never parsed.
13
+ * • `scope` — optional read-visibility narrowing. Absent = everything visible.
14
+ * Present = the call sees only what the claims grant (silent filtering on
15
+ * `query`; `forbidden` on a targeted read outside the claim). This is the
16
+ * one enforcement seam a fronting shell cannot replicate from outside, so
17
+ * it stays in the engine — exposed as a plain input, not derived from a
18
+ * token.
19
+ */
20
+ import { KernelError } from "./errors.js";
21
+ /** Identity stamped on a write when the caller supplies no author. */
22
+ export const DEFAULT_AUTHOR = "mrplex";
23
+ const MAX_AUTHOR_LENGTH = 512;
24
+ /** True if `s` contains any C0/C1 control character (incl. tab/newline). */
25
+ function hasControlChar(s) {
26
+ for (let i = 0; i < s.length; i++) {
27
+ const c = s.charCodeAt(i);
28
+ if (c <= 0x1f || (c >= 0x7f && c <= 0x9f))
29
+ return true;
30
+ }
31
+ return false;
32
+ }
33
+ /**
34
+ * Structurally validate an already-parsed value as `ScopeClaim[]`. This is the
35
+ * single validation path shared by every surface that accepts a scope — the
36
+ * `X-Mrplex-Scope` header (via [[parseScopeClaims]]), the `POST /query` body
37
+ * `scope` field, the MCP query tool-arg, and the CLI `--scope` flag. Routing
38
+ * all of them here means a claim missing `repo` (or with wrong types) is a loud
39
+ * `filter_invalid`, not a silent `deny_all` empty result (see the note in
40
+ * kernel/auth/scope.ts on how `normalizeClaims` treats a repo-less claim).
41
+ *
42
+ * Throws `KernelError("filter_invalid")` on bad input so surfaces map it to a
43
+ * 4xx uniformly rather than a 500.
44
+ */
45
+ export function validateScopeClaims(parsed) {
46
+ if (!Array.isArray(parsed)) {
47
+ throw new KernelError("filter_invalid", { reason: "scope must be an array of claims" });
48
+ }
49
+ const isStrOrStrList = (v) => typeof v === "string" || (Array.isArray(v) && v.every((x) => typeof x === "string"));
50
+ for (const entry of parsed) {
51
+ if (typeof entry !== "object" || entry === null) {
52
+ throw new KernelError("filter_invalid", { reason: "scope claim must be an object" });
53
+ }
54
+ const e = entry;
55
+ if (!isStrOrStrList(e.repo)) {
56
+ throw new KernelError("filter_invalid", {
57
+ reason: "scope claim `repo` must be a string or string[]",
58
+ });
59
+ }
60
+ if (e.paths !== undefined && !isStrOrStrList(e.paths)) {
61
+ throw new KernelError("filter_invalid", {
62
+ reason: "scope claim `paths` must be a string or string[]",
63
+ });
64
+ }
65
+ }
66
+ return parsed;
67
+ }
68
+ /**
69
+ * Parse a JSON string into `ScopeClaim[]`. Used to decode the `X-Mrplex-Scope`
70
+ * header and the CLI `--scope` flag. Throws `KernelError("filter_invalid")` on
71
+ * malformed input so a bad claim is a loud client error, not a silent
72
+ * full-access fallback.
73
+ */
74
+ export function parseScopeClaims(json) {
75
+ let parsed;
76
+ try {
77
+ parsed = JSON.parse(json);
78
+ }
79
+ catch {
80
+ throw new KernelError("filter_invalid", {
81
+ reason: "scope must be valid JSON (a ScopeClaim array)",
82
+ });
83
+ }
84
+ return validateScopeClaims(parsed);
85
+ }
86
+ /**
87
+ * Resolve + validate the author for a write. Opaque: we sanity-check only
88
+ * (non-empty, no control characters, length-capped) and never parse the value.
89
+ * An empty/absent author yields the default "mrplex".
90
+ *
91
+ * Throws `KernelError("filter_invalid")` on bad input — the author is reachable
92
+ * verbatim from the `X-Mrplex-Author` header, so a control-char or over-length
93
+ * value is a client mistake and must stay in the 4xx band, not surface as a 500.
94
+ */
95
+ export function resolveAuthor(ctx) {
96
+ const raw = ctx.author;
97
+ if (raw === undefined || raw === "")
98
+ return DEFAULT_AUTHOR;
99
+ if (typeof raw !== "string") {
100
+ throw new KernelError("filter_invalid", { reason: "author must be a string" });
101
+ }
102
+ if (raw.length > MAX_AUTHOR_LENGTH) {
103
+ throw new KernelError("filter_invalid", {
104
+ reason: `author exceeds ${MAX_AUTHOR_LENGTH} characters`,
105
+ });
106
+ }
107
+ if (hasControlChar(raw)) {
108
+ throw new KernelError("filter_invalid", {
109
+ reason: "author must not contain control characters",
110
+ });
111
+ }
112
+ return raw;
113
+ }
114
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/kernel/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Deletion path builder — design §3.4.
3
+ *
4
+ * path/to/document.md @ v45129 → :deleted/path/to/document-v45129.md
5
+ *
6
+ * The version-id suffix goes before the file extension so type detection,
7
+ * syntax highlighting, and globs like `**\/*.md` keep working on trashed docs.
8
+ * The extension is "everything from the final segment's last '.'" — with the
9
+ * key caveat that a leading dot doesn't count. So:
10
+ *
11
+ * README → README-v45129
12
+ * .gitignore → .gitignore-v45129
13
+ * notes/foo.tar.gz → notes/foo.tar-v45129.gz
14
+ * notes/a-v42.md → notes/a-v42-v45129.md (uniqueness still holds:
15
+ * version_ids are unique
16
+ * and the suffix is
17
+ * always appended)
18
+ */
19
+ /**
20
+ * Split the final segment of a path into `(basename, extension)` per the
21
+ * "final dot, but not a leading dot" rule from §3.4.
22
+ *
23
+ * Returned extension includes its leading dot (e.g. `.md`), or is `""` when
24
+ * there is no extension.
25
+ */
26
+ export declare function splitExtension(finalSegment: string): {
27
+ basename: string;
28
+ extension: string;
29
+ };
30
+ /**
31
+ * Insert a version-id suffix before the extension of the final path segment.
32
+ * Does NOT prepend the deletion sigil — that's `deletionPath`'s job.
33
+ */
34
+ export declare function withVersionSuffix(path: string, versionIdString: string): string;
35
+ /**
36
+ * The kernel-emitted path for a deletion move. `<systemSigil>` is the
37
+ * canonical (first-entry) system sigil from the effective path config
38
+ * (design §3.5.4 — set for input, first for output).
39
+ *
40
+ * Example:
41
+ * deletionPath(":", "notes/foo.md", "v45129") = ":deleted/notes/foo-v45129.md"
42
+ */
43
+ export declare function deletionPath(systemSigil: string, originalPath: string, versionIdString: string): string;
44
+ /**
45
+ * Rough classifier used by `docs.delete` idempotency (§4.1 rule 4): true if
46
+ * ANY segment of the path starts with one of the accepted system sigils.
47
+ * (The design-wide primitive lives in validation.pathHasSigilSegment; this
48
+ * shim keeps the naming intent-facing at the call site.)
49
+ */
50
+ export declare function pathIsInSystemNamespace(path: string, systemSigils: readonly string[]): boolean;
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Deletion path builder — design §3.4.
3
+ *
4
+ * path/to/document.md @ v45129 → :deleted/path/to/document-v45129.md
5
+ *
6
+ * The version-id suffix goes before the file extension so type detection,
7
+ * syntax highlighting, and globs like `**\/*.md` keep working on trashed docs.
8
+ * The extension is "everything from the final segment's last '.'" — with the
9
+ * key caveat that a leading dot doesn't count. So:
10
+ *
11
+ * README → README-v45129
12
+ * .gitignore → .gitignore-v45129
13
+ * notes/foo.tar.gz → notes/foo.tar-v45129.gz
14
+ * notes/a-v42.md → notes/a-v42-v45129.md (uniqueness still holds:
15
+ * version_ids are unique
16
+ * and the suffix is
17
+ * always appended)
18
+ */
19
+ import { PATH_SEPARATOR } from "./validation.js";
20
+ /**
21
+ * Split the final segment of a path into `(basename, extension)` per the
22
+ * "final dot, but not a leading dot" rule from §3.4.
23
+ *
24
+ * Returned extension includes its leading dot (e.g. `.md`), or is `""` when
25
+ * there is no extension.
26
+ */
27
+ export function splitExtension(finalSegment) {
28
+ // A leading dot doesn't count as an extension separator — .gitignore is
29
+ // basename `.gitignore`, extension "".
30
+ const searchFrom = finalSegment.startsWith(".") ? 1 : 0;
31
+ const dot = finalSegment.lastIndexOf(".");
32
+ if (dot < searchFrom || dot === finalSegment.length - 1) {
33
+ // Either no dot at all (dot === -1 < searchFrom), or the only dot is the
34
+ // leading one, or the dot is trailing (bare "foo." would be basename
35
+ // "foo." — but §3.5 disallows most weird chars anyway).
36
+ if (dot === -1 || dot < searchFrom) {
37
+ return { basename: finalSegment, extension: "" };
38
+ }
39
+ return { basename: finalSegment.slice(0, dot), extension: finalSegment.slice(dot) };
40
+ }
41
+ return { basename: finalSegment.slice(0, dot), extension: finalSegment.slice(dot) };
42
+ }
43
+ /**
44
+ * Insert a version-id suffix before the extension of the final path segment.
45
+ * Does NOT prepend the deletion sigil — that's `deletionPath`'s job.
46
+ */
47
+ export function withVersionSuffix(path, versionIdString) {
48
+ const segments = path.split(PATH_SEPARATOR);
49
+ const last = segments[segments.length - 1] ?? "";
50
+ const { basename, extension } = splitExtension(last);
51
+ segments[segments.length - 1] = `${basename}-${versionIdString}${extension}`;
52
+ return segments.join(PATH_SEPARATOR);
53
+ }
54
+ /**
55
+ * The kernel-emitted path for a deletion move. `<systemSigil>` is the
56
+ * canonical (first-entry) system sigil from the effective path config
57
+ * (design §3.5.4 — set for input, first for output).
58
+ *
59
+ * Example:
60
+ * deletionPath(":", "notes/foo.md", "v45129") = ":deleted/notes/foo-v45129.md"
61
+ */
62
+ export function deletionPath(systemSigil, originalPath, versionIdString) {
63
+ return `${systemSigil}deleted/${withVersionSuffix(originalPath, versionIdString)}`;
64
+ }
65
+ /**
66
+ * Rough classifier used by `docs.delete` idempotency (§4.1 rule 4): true if
67
+ * ANY segment of the path starts with one of the accepted system sigils.
68
+ * (The design-wide primitive lives in validation.pathHasSigilSegment; this
69
+ * shim keeps the naming intent-facing at the call site.)
70
+ */
71
+ export function pathIsInSystemNamespace(path, systemSigils) {
72
+ if (path === "")
73
+ return false;
74
+ const segments = path.split(PATH_SEPARATOR);
75
+ for (const segment of segments) {
76
+ for (const sigil of systemSigils) {
77
+ if (segment.startsWith(sigil))
78
+ return true;
79
+ }
80
+ }
81
+ return false;
82
+ }
83
+ //# sourceMappingURL=deletion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deletion.js","sourceRoot":"","sources":["../../src/kernel/deletion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAAC,YAAoB;IAIjD,wEAAwE;IACxE,uCAAuC;IACvC,MAAM,UAAU,GAAG,YAAY,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxD,MAAM,GAAG,GAAG,YAAY,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,GAAG,GAAG,UAAU,IAAI,GAAG,KAAK,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACxD,yEAAyE;QACzE,qEAAqE;QACrE,wDAAwD;QACxD,IAAI,GAAG,KAAK,CAAC,CAAC,IAAI,GAAG,GAAG,UAAU,EAAE,CAAC;YACnC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,EAAE,EAAE,CAAC;QACnD,CAAC;QACD,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;IACtF,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;AACtF,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY,EAAE,eAAuB;IACrE,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACjD,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACrD,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,GAAG,QAAQ,IAAI,eAAe,GAAG,SAAS,EAAE,CAAC;IAC7E,OAAO,QAAQ,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,YAAY,CAC1B,WAAmB,EACnB,YAAoB,EACpB,eAAuB;IAEvB,OAAO,GAAG,WAAW,WAAW,iBAAiB,CAAC,YAAY,EAAE,eAAe,CAAC,EAAE,CAAC;AACrF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,IAAY,EAAE,YAA+B;IACnF,IAAI,IAAI,KAAK,EAAE;QAAE,OAAO,KAAK,CAAC;IAC9B,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IAC5C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;YACjC,IAAI,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC;gBAAE,OAAO,IAAI,CAAC;QAC7C,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * docs.diff — the one v1 read primitive deferred from M3 (m4-plan WS5).
3
+ *
4
+ * Produces a unified diff over the byte-exact serialized documents (§3.2
5
+ * — one canonical representation via frontmatter.join). Both versions
6
+ * must belong to the same document at `(repo, path)`; otherwise the
7
+ * `version_not_in_document` error we reserved back in M1 finally fires.
8
+ *
9
+ * Read scope is checked on the lookup path AND both version paths
10
+ * (m4-plan §5 decision 10) — a doc renamed out of the caller's scope
11
+ * doesn't leak history through diff.
12
+ */
13
+ import type { Storage } from "../storage/types.js";
14
+ import { KernelError } from "./errors.js";
15
+ export type UnifiedDiff = {
16
+ repo: string;
17
+ path: string;
18
+ from_version_id: string;
19
+ to_version_id: string;
20
+ patch: string;
21
+ };
22
+ export type DiffDeps = {
23
+ storage: Storage;
24
+ resolveReadRepo: (slug: string) => Promise<{
25
+ id: number;
26
+ slug: string;
27
+ }>;
28
+ authorizeReadPath: (repoSlug: string, path: string) => void;
29
+ };
30
+ export declare function runDiff(input: {
31
+ repo: string;
32
+ path: string;
33
+ from_version_id: string;
34
+ to_version_id: string;
35
+ }, deps: DiffDeps): Promise<UnifiedDiff>;
36
+ export { KernelError };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * docs.diff — the one v1 read primitive deferred from M3 (m4-plan WS5).
3
+ *
4
+ * Produces a unified diff over the byte-exact serialized documents (§3.2
5
+ * — one canonical representation via frontmatter.join). Both versions
6
+ * must belong to the same document at `(repo, path)`; otherwise the
7
+ * `version_not_in_document` error we reserved back in M1 finally fires.
8
+ *
9
+ * Read scope is checked on the lookup path AND both version paths
10
+ * (m4-plan §5 decision 10) — a doc renamed out of the caller's scope
11
+ * doesn't leak history through diff.
12
+ */
13
+ import { createTwoFilesPatch } from "diff";
14
+ import { join as joinFrontmatter } from "../markdown/frontmatter.js";
15
+ import { KernelError, docNotFound, versionNotFound, versionNotInDocument } from "./errors.js";
16
+ import { decodeVersionId } from "./version-id.js";
17
+ export async function runDiff(input, deps) {
18
+ const repo = await deps.resolveReadRepo(input.repo);
19
+ deps.authorizeReadPath(repo.slug, input.path);
20
+ const current = await deps.storage.version_current(repo.id, input.path);
21
+ if (!current)
22
+ throw docNotFound(input.repo, input.path);
23
+ const documentId = current.document_id;
24
+ const from = await decodeAndFetch(deps.storage, input.from_version_id);
25
+ const to = await decodeAndFetch(deps.storage, input.to_version_id);
26
+ if (from.document_id !== documentId) {
27
+ throw versionNotInDocument(input.from_version_id, input.repo, input.path);
28
+ }
29
+ if (to.document_id !== documentId) {
30
+ throw versionNotInDocument(input.to_version_id, input.repo, input.path);
31
+ }
32
+ if (from.repo_id !== repo.id || to.repo_id !== repo.id) {
33
+ throw versionNotInDocument(input.from_version_id, input.repo, input.path);
34
+ }
35
+ deps.authorizeReadPath(repo.slug, from.path);
36
+ deps.authorizeReadPath(repo.slug, to.path);
37
+ const fromText = serializeVersion(from);
38
+ const toText = serializeVersion(to);
39
+ const patch = createTwoFilesPatch(`${from.path}@${input.from_version_id}`, `${to.path}@${input.to_version_id}`, fromText, toText);
40
+ return {
41
+ repo: input.repo,
42
+ path: input.path,
43
+ from_version_id: input.from_version_id,
44
+ to_version_id: input.to_version_id,
45
+ patch,
46
+ };
47
+ }
48
+ async function decodeAndFetch(storage, versionId) {
49
+ const id = decodeVersionId(versionId);
50
+ if (id === null)
51
+ throw versionNotFound(versionId);
52
+ const row = await storage.version_by_id(id);
53
+ if (!row)
54
+ throw versionNotFound(versionId);
55
+ return row;
56
+ }
57
+ function serializeVersion(v) {
58
+ return joinFrontmatter({ frontmatter_raw: v.frontmatter_raw, body: v.body });
59
+ }
60
+ export { KernelError };
61
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../src/kernel/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Kernel error catalog. Every kernel-emitted error has a stable `code` and
3
+ * a JSON-serializable `data` payload — design §4.3.
4
+ *
5
+ * M0 surfaces only the read-time subset; writes and auth land in M1.
6
+ */
7
+ export type KernelErrorCode = "repo_not_found" | "doc_not_found" | "version_not_found" | "version_not_in_document" | "slug_invalid" | "path_invalid" | "frontmatter_invalid" | "filter_invalid" | "link_config_invalid" | "stale_prev" | "create_conflict" | "path_taken" | "slug_taken" | "forbidden" | "precondition_required" | "payload_too_large" | "semantic_unavailable";
8
+ export declare class KernelError<D = Record<string, unknown>> extends Error {
9
+ readonly code: KernelErrorCode;
10
+ readonly data: D;
11
+ constructor(code: KernelErrorCode, data: D, message?: string);
12
+ }
13
+ /**
14
+ * Runtime set matching KernelErrorCode. Used by the remote MCP client to
15
+ * validate an incoming `code` string before rehydrating a KernelError —
16
+ * otherwise a rogue server could inject unknown codes and break clients
17
+ * that switch exhaustively.
18
+ */
19
+ export declare const KERNEL_ERROR_CODES: ReadonlySet<KernelErrorCode>;
20
+ /** Type guard — check whether an arbitrary string is a known catalog code. */
21
+ export declare function isKernelErrorCode(code: string): code is KernelErrorCode;
22
+ export declare const repoNotFound: (slug: string) => KernelError<{
23
+ slug: string;
24
+ }>;
25
+ export declare const docNotFound: (repo: string, path: string) => KernelError<{
26
+ repo: string;
27
+ path: string;
28
+ }>;
29
+ export declare const versionNotFound: (versionId: string) => KernelError<{
30
+ version_id: string;
31
+ }>;
32
+ export declare const versionNotInDocument: (versionId: string, repo: string, path: string) => KernelError<{
33
+ version_id: string;
34
+ repo: string;
35
+ path: string;
36
+ }>;
37
+ export declare const forbidden: () => KernelError<{}>;