@hawkeyexl/manni 4.3.1 → 4.4.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 (225) hide show
  1. package/README.md +9 -1
  2. package/dist/batch-GFNLTGOH.js +36 -0
  3. package/dist/build-COYIQ25L.js +31 -0
  4. package/dist/calibrate-MDBLJKEE.js +31 -0
  5. package/dist/capture-LRML2PKV.js +32 -0
  6. package/dist/check-ASPIHA6B.js +40 -0
  7. package/dist/check-ASPIHA6B.js.map +1 -0
  8. package/dist/check-EDLBYL5N.js +27 -0
  9. package/dist/check-EDLBYL5N.js.map +1 -0
  10. package/dist/check-HYNGXYJV.js +18 -0
  11. package/dist/check-HYNGXYJV.js.map +1 -0
  12. package/dist/chunk-2B7ZNTPV.js +230 -0
  13. package/dist/chunk-2B7ZNTPV.js.map +1 -0
  14. package/dist/chunk-2H7UOFLK.js +11 -0
  15. package/dist/chunk-2H7UOFLK.js.map +1 -0
  16. package/dist/chunk-37LP5HMZ.js +1042 -0
  17. package/dist/chunk-37LP5HMZ.js.map +1 -0
  18. package/dist/chunk-3VK37OR2.js +2957 -0
  19. package/dist/chunk-3VK37OR2.js.map +1 -0
  20. package/dist/chunk-4IUC2MNL.js +2165 -0
  21. package/dist/chunk-4IUC2MNL.js.map +1 -0
  22. package/dist/{chunk-3R23C5DT.js → chunk-4TSWU2SU.js} +2 -14
  23. package/dist/chunk-4TSWU2SU.js.map +1 -0
  24. package/dist/chunk-57NEQRVO.js +10921 -0
  25. package/dist/chunk-57NEQRVO.js.map +1 -0
  26. package/dist/chunk-6JSSEWBG.js +6737 -0
  27. package/dist/chunk-6JSSEWBG.js.map +1 -0
  28. package/dist/chunk-6OYEI2VV.js +88 -0
  29. package/dist/chunk-6OYEI2VV.js.map +1 -0
  30. package/dist/chunk-77AINBYM.js +19 -0
  31. package/dist/chunk-77AINBYM.js.map +1 -0
  32. package/dist/chunk-7UKO3ASZ.js +54 -0
  33. package/dist/chunk-7UKO3ASZ.js.map +1 -0
  34. package/dist/chunk-A5ULMVHQ.js +164 -0
  35. package/dist/chunk-A5ULMVHQ.js.map +1 -0
  36. package/dist/chunk-C4SQM22E.js +299 -0
  37. package/dist/chunk-C4SQM22E.js.map +1 -0
  38. package/dist/chunk-CK7SKVHR.js +1042 -0
  39. package/dist/chunk-CK7SKVHR.js.map +1 -0
  40. package/dist/{chunk-G5CM2VGQ.js → chunk-DXNZS72W.js} +8 -94
  41. package/dist/chunk-DXNZS72W.js.map +1 -0
  42. package/dist/chunk-EPH54CAY.js +374 -0
  43. package/dist/chunk-EPH54CAY.js.map +1 -0
  44. package/dist/{chunk-KJR7OVDX.js → chunk-FBEQCK47.js} +56 -137
  45. package/dist/chunk-FBEQCK47.js.map +1 -0
  46. package/dist/{chunk-IOYXPBCL.js → chunk-G3T47CFV.js} +1 -7
  47. package/dist/{chunk-IOYXPBCL.js.map → chunk-G3T47CFV.js.map} +1 -1
  48. package/dist/chunk-GCQRPUSB.js +1287 -0
  49. package/dist/chunk-GCQRPUSB.js.map +1 -0
  50. package/dist/chunk-GLP5PSXB.js +72 -0
  51. package/dist/chunk-GLP5PSXB.js.map +1 -0
  52. package/dist/chunk-I2AH3CJJ.js +1192 -0
  53. package/dist/chunk-I2AH3CJJ.js.map +1 -0
  54. package/dist/chunk-IDV6HJCB.js +388 -0
  55. package/dist/chunk-IDV6HJCB.js.map +1 -0
  56. package/dist/chunk-IKEWBMCN.js +98 -0
  57. package/dist/chunk-IKEWBMCN.js.map +1 -0
  58. package/dist/chunk-JCDXE76J.js +52 -0
  59. package/dist/chunk-JCDXE76J.js.map +1 -0
  60. package/dist/chunk-JXLTXMJ7.js +455 -0
  61. package/dist/chunk-JXLTXMJ7.js.map +1 -0
  62. package/dist/chunk-LJ2RDH3F.js +49 -0
  63. package/dist/chunk-LJ2RDH3F.js.map +1 -0
  64. package/dist/chunk-M2JCK5F6.js +805 -0
  65. package/dist/chunk-M2JCK5F6.js.map +1 -0
  66. package/dist/chunk-M3W7J6MU.js +4398 -0
  67. package/dist/chunk-M3W7J6MU.js.map +1 -0
  68. package/dist/chunk-MMTSSTG7.js +23 -0
  69. package/dist/chunk-MMTSSTG7.js.map +1 -0
  70. package/dist/chunk-MNH7QO4Z.js +15 -0
  71. package/dist/chunk-MNH7QO4Z.js.map +1 -0
  72. package/dist/chunk-MWJLZMBL.js +934 -0
  73. package/dist/chunk-MWJLZMBL.js.map +1 -0
  74. package/dist/chunk-MYMBCTDE.js +387 -0
  75. package/dist/chunk-MYMBCTDE.js.map +1 -0
  76. package/dist/chunk-NCPWXHDO.js +683 -0
  77. package/dist/chunk-NCPWXHDO.js.map +1 -0
  78. package/dist/chunk-NLXTXE5Y.js +1661 -0
  79. package/dist/chunk-NLXTXE5Y.js.map +1 -0
  80. package/dist/{chunk-CFDUZRM2.js → chunk-NXV7WE2D.js} +32 -240
  81. package/dist/chunk-NXV7WE2D.js.map +1 -0
  82. package/dist/chunk-OWBRDNRZ.js +16 -0
  83. package/dist/chunk-OWBRDNRZ.js.map +1 -0
  84. package/dist/{chunk-KTSJ2ZHA.js → chunk-PAU352SV.js} +5 -3
  85. package/dist/{chunk-KTSJ2ZHA.js.map → chunk-PAU352SV.js.map} +1 -1
  86. package/dist/chunk-PCE7QHXJ.js +68 -0
  87. package/dist/chunk-PCE7QHXJ.js.map +1 -0
  88. package/dist/chunk-PIKOVN6W.js +1651 -0
  89. package/dist/chunk-PIKOVN6W.js.map +1 -0
  90. package/dist/chunk-PNPQTHBT.js +17 -0
  91. package/dist/chunk-PNPQTHBT.js.map +1 -0
  92. package/dist/chunk-PU6DFJMY.js +1975 -0
  93. package/dist/chunk-PU6DFJMY.js.map +1 -0
  94. package/dist/chunk-Q35YIDBV.js +1202 -0
  95. package/dist/chunk-Q35YIDBV.js.map +1 -0
  96. package/dist/{chunk-5HNHEUD5.js → chunk-QQUKGCAJ.js} +3 -3
  97. package/dist/chunk-QRWGPQKO.js +198 -0
  98. package/dist/chunk-QRWGPQKO.js.map +1 -0
  99. package/dist/{chunk-UBMMXS2Y.js → chunk-QZ6LRSNV.js} +69 -48
  100. package/dist/{chunk-UBMMXS2Y.js.map → chunk-QZ6LRSNV.js.map} +1 -1
  101. package/dist/chunk-RL5XWQOL.js +3872 -0
  102. package/dist/chunk-RL5XWQOL.js.map +1 -0
  103. package/dist/chunk-RNVYGWIC.js +30 -0
  104. package/dist/chunk-RNVYGWIC.js.map +1 -0
  105. package/dist/chunk-SE4JN5XN.js +19 -0
  106. package/dist/chunk-SE4JN5XN.js.map +1 -0
  107. package/dist/chunk-SKSDRUUK.js +622 -0
  108. package/dist/chunk-SKSDRUUK.js.map +1 -0
  109. package/dist/chunk-TIUTIOFB.js +25 -0
  110. package/dist/chunk-TIUTIOFB.js.map +1 -0
  111. package/dist/chunk-TK3FC4RF.js +3090 -0
  112. package/dist/chunk-TK3FC4RF.js.map +1 -0
  113. package/dist/chunk-TU2WUBVZ.js +2 -0
  114. package/dist/chunk-TU2WUBVZ.js.map +1 -0
  115. package/dist/chunk-TZOYZK2E.js +98 -0
  116. package/dist/chunk-TZOYZK2E.js.map +1 -0
  117. package/dist/chunk-UJCVAWP7.js +178 -0
  118. package/dist/chunk-UJCVAWP7.js.map +1 -0
  119. package/dist/chunk-UKZNLVJW.js +17 -0
  120. package/dist/chunk-UKZNLVJW.js.map +1 -0
  121. package/dist/{chunk-HAPTXWU2.js → chunk-UQISLDAV.js} +4 -4
  122. package/dist/chunk-WB3QM6PP.js +5440 -0
  123. package/dist/chunk-WB3QM6PP.js.map +1 -0
  124. package/dist/chunk-YB4IBW3M.js +96 -0
  125. package/dist/chunk-YB4IBW3M.js.map +1 -0
  126. package/dist/chunk-YEUYKR62.js +72 -0
  127. package/dist/chunk-YEUYKR62.js.map +1 -0
  128. package/dist/chunk-YJOGUXGP.js +634 -0
  129. package/dist/chunk-YJOGUXGP.js.map +1 -0
  130. package/dist/chunk-YNHZHSSM.js +41 -0
  131. package/dist/chunk-YNHZHSSM.js.map +1 -0
  132. package/dist/chunk-YTURO7SI.js +979 -0
  133. package/dist/chunk-YTURO7SI.js.map +1 -0
  134. package/dist/chunk-ZXRAE55H.js +31 -0
  135. package/dist/chunk-ZXRAE55H.js.map +1 -0
  136. package/dist/cli-3BIBYHFK.js +473 -0
  137. package/dist/cli-3BIBYHFK.js.map +1 -0
  138. package/dist/cli-673OTRGE.js +28 -0
  139. package/dist/cli-673OTRGE.js.map +1 -0
  140. package/dist/cli-6HIDIFVT.js +1203 -0
  141. package/dist/cli-6HIDIFVT.js.map +1 -0
  142. package/dist/cli-6UB5N6CU.js +232 -0
  143. package/dist/cli-6UB5N6CU.js.map +1 -0
  144. package/dist/cli-LFP5ZGYS.js +346 -0
  145. package/dist/cli-LFP5ZGYS.js.map +1 -0
  146. package/dist/cli-MN7PYMBI.js +552 -0
  147. package/dist/cli-MN7PYMBI.js.map +1 -0
  148. package/dist/cli-PYPX6O6E.js +739 -0
  149. package/dist/cli-PYPX6O6E.js.map +1 -0
  150. package/dist/cli-RPM5PELX.js +626 -0
  151. package/dist/cli-RPM5PELX.js.map +1 -0
  152. package/dist/cli-VI7VHWNZ.js +423 -0
  153. package/dist/cli-VI7VHWNZ.js.map +1 -0
  154. package/dist/cli.d.ts +12 -2
  155. package/dist/cli.js +109 -7661
  156. package/dist/cli.js.map +1 -1
  157. package/dist/docmeta.js +15 -3
  158. package/dist/docmeta.js.map +1 -1
  159. package/dist/github-6QMYOHC3.js +27 -0
  160. package/dist/github-6QMYOHC3.js.map +1 -0
  161. package/dist/github-SXPGP5DB.js +32 -0
  162. package/dist/github-SXPGP5DB.js.map +1 -0
  163. package/dist/index.d.ts +65 -3
  164. package/dist/index.js +407 -337
  165. package/dist/index.js.map +1 -1
  166. package/dist/json-7WV7KL6H.js +17 -0
  167. package/dist/json-7WV7KL6H.js.map +1 -0
  168. package/dist/json-SY7KLNC7.js +35 -0
  169. package/dist/json-SY7KLNC7.js.map +1 -0
  170. package/dist/lint-ASMJLLPA.js +28 -0
  171. package/dist/lint-ASMJLLPA.js.map +1 -0
  172. package/dist/list-KZNVTNVC.js +31 -0
  173. package/dist/list-KZNVTNVC.js.map +1 -0
  174. package/dist/list-Q57YTFUQ.js +29 -0
  175. package/dist/list-Q57YTFUQ.js.map +1 -0
  176. package/dist/page-KSGV5RD4.js +41 -0
  177. package/dist/page-KSGV5RD4.js.map +1 -0
  178. package/dist/picker-3XF36MJF.js +14 -0
  179. package/dist/picker-3XF36MJF.js.map +1 -0
  180. package/dist/pretty-A5EGTN35.js +37 -0
  181. package/dist/pretty-A5EGTN35.js.map +1 -0
  182. package/dist/pretty-CXSDXNAS.js +43 -0
  183. package/dist/pretty-CXSDXNAS.js.map +1 -0
  184. package/dist/reporters-HUY7UXFS.js +42 -0
  185. package/dist/reporters-HUY7UXFS.js.map +1 -0
  186. package/dist/reporters-K2VUKSAK.js +71 -0
  187. package/dist/reporters-K2VUKSAK.js.map +1 -0
  188. package/dist/reporters-M6LJ2IYU.js +21 -0
  189. package/dist/reporters-M6LJ2IYU.js.map +1 -0
  190. package/dist/run-3DYJNRIG.js +33 -0
  191. package/dist/run-3DYJNRIG.js.map +1 -0
  192. package/dist/term-BIQUPMOR.js +1592 -0
  193. package/dist/term-BIQUPMOR.js.map +1 -0
  194. package/dist/types-Y6TXHM7M.js +10 -0
  195. package/dist/types-Y6TXHM7M.js.map +1 -0
  196. package/dist/validate-53RKM2XG.js +16 -0
  197. package/dist/validate-53RKM2XG.js.map +1 -0
  198. package/package.json +1 -1
  199. package/plugin/manni/.claude-plugin/plugin.json +9 -0
  200. package/plugin/manni/hooks/hooks.json +69 -0
  201. package/plugin/manni/hooks/manni.mjs +157 -0
  202. package/plugin/manni/skills/check/SKILL.md +20 -0
  203. package/plugin/manni/skills/evals/SKILL.md +27 -0
  204. package/plugin/manni/skills/fix/SKILL.md +56 -0
  205. package/plugin/manni/skills/setup/SKILL.md +41 -0
  206. package/dist/batch-A5HZKYIW.js +0 -18
  207. package/dist/calibrate-S5K6QHUY.js +0 -13
  208. package/dist/capture-OZEZDABQ.js +0 -15
  209. package/dist/chunk-3R23C5DT.js.map +0 -1
  210. package/dist/chunk-CFDUZRM2.js.map +0 -1
  211. package/dist/chunk-G5CM2VGQ.js.map +0 -1
  212. package/dist/chunk-KJR7OVDX.js.map +0 -1
  213. package/dist/chunk-V4KUVE47.js +0 -27170
  214. package/dist/chunk-V4KUVE47.js.map +0 -1
  215. package/dist/chunk-ZQBTK3DO.js +0 -26518
  216. package/dist/chunk-ZQBTK3DO.js.map +0 -1
  217. package/dist/picker-6HRMETE7.js +0 -12
  218. package/plugin/tracevals/.claude-plugin/plugin.json +0 -9
  219. package/plugin/tracevals/hooks/hooks.json +0 -17
  220. /package/dist/{batch-A5HZKYIW.js.map → batch-GFNLTGOH.js.map} +0 -0
  221. /package/dist/{calibrate-S5K6QHUY.js.map → build-COYIQ25L.js.map} +0 -0
  222. /package/dist/{capture-OZEZDABQ.js.map → calibrate-MDBLJKEE.js.map} +0 -0
  223. /package/dist/{picker-6HRMETE7.js.map → capture-LRML2PKV.js.map} +0 -0
  224. /package/dist/{chunk-5HNHEUD5.js.map → chunk-QQUKGCAJ.js.map} +0 -0
  225. /package/dist/{chunk-HAPTXWU2.js.map → chunk-UQISLDAV.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cite/index.ts","../src/cite/core/reencrypt.ts","../src/key/errors.ts","../src/key/commands/rotate.ts","../src/key/core/config.ts","../src/key/commands/set.ts"],"sourcesContent":["/**\n * The citation tool's programmatic API, exported from the package as the\n * `cite` namespace: `import { cite } from \"@hawkeyexl/manni\"`.\n */\nexport * from \"./types.js\";\nexport { CiteError } from \"./errors.js\";\nexport { DEFAULT_SEVERITY, RULE_ID_PREFIX, isCiteRule, resolveSeverity, ruleId } from \"./core/severity.js\";\nexport {\n FILE_PATTERN,\n SRC_PATTERN,\n formatSrc,\n lineSpec,\n parseLines,\n parseSrc,\n rangeLines,\n sourceRange,\n spellLines,\n spellSource,\n} from \"./core/range.js\";\nexport { hashLines, hashRange, isKeyedPin, normalizeText, sliceLines, splitLines } from \"./core/hash.js\";\nexport { shortCommit, shortLine, shortPin, shortSrc, spellAt } from \"./core/spell.js\";\nexport { buildSourceIndex, readSource } from \"./core/sources.js\";\nexport type { BuildIndexOptions, ReadSourceResult } from \"./core/sources.js\";\nexport {\n isUnitText,\n markerClaimEnd,\n markerRunAt,\n misplacedMarkerAt,\n misplacedMarkers,\n movedUnit,\n pre43Span,\n splitUnit,\n unitText,\n} from \"./core/reanchor.js\";\nexport type { MisplacedMarker } from \"./core/reanchor.js\";\nexport {\n anchoredLines,\n detectEol,\n fenceSpanAt,\n fencedBlockAfter,\n fencedBlockAt,\n fencedBlocks,\n formatStatement,\n insideFence,\n isBoundLine,\n isTableRow,\n lineAt,\n offsetOfLine,\n paragraphAfter,\n parseStatements,\n statementForms,\n} from \"./core/statements.js\";\nexport type { StatementForm } from \"./core/statements.js\";\nexport {\n blockMatches,\n claimEnd,\n claimLine,\n markerUnit,\n noUnitAt,\n normalizeWhitespace,\n pinOfLines,\n toBodyLines,\n toFileLines,\n unitAt,\n} from \"./core/claims.js\";\nexport type { ClaimUnit, NoUnit } from \"./core/claims.js\";\nexport {\n GIT_UNAVAILABLE_COMMIT,\n GIT_UNAVAILABLE_HISTORY,\n PAGE_HISTORY_UNAVAILABLE,\n gitClient,\n noGit,\n} from \"./core/git.js\";\nexport {\n MAX_PAGE_COMMITS,\n claimDiff,\n claimHistory,\n claimWords,\n holdsWords,\n refineClaim,\n runsHolding,\n sentencesOf,\n sharesSentence,\n stripMarkers,\n} from \"./core/history.js\";\nexport type { ClaimHistory, ClaimHistoryInput, RefineClaimInput } from \"./core/history.js\";\nexport { MAX_RANGE_LINES, MOVE_BUDGET_BYTES, MOVE_WINDOW_LINES, classifyCitation, findWindows, historyOf } from \"./core/classify.js\";\nexport type { ClassifyOptions, FindWindowsOptions, History } from \"./core/classify.js\";\nexport {\n MARKER_JSON,\n MAX_MARKERS_PER_PAGE,\n bodyLineOf,\n citationInputs,\n ownedMessage,\n pickExtractor,\n readPage,\n validateEntry,\n} from \"./core/page.js\";\nexport { shiftedEntries, withClaimLines } from \"./core/shift.js\";\nexport type { ShiftOptions, Shifted } from \"./core/shift.js\";\nexport {\n CITATIONS_KEY,\n duplicateJoinRefusal,\n loadCitationSidecars,\n orphanRefusal,\n sidecarsFor,\n twoManifestsRefusal,\n urlManifestRefusal,\n} from \"./core/sidecar.js\";\nexport type {\n CitationManifest,\n CitationSidecars,\n LoadSidecarOptions,\n PageSidecar,\n} from \"./core/sidecar.js\";\nexport { ManifestSet, itemLine, splice } from \"./core/manifest.js\";\nexport type { HeldManifest } from \"./core/manifest.js\";\nexport type { ReadPageOptions } from \"./core/page.js\";\nexport { checkCitations } from \"./core/check-page.js\";\nexport {\n claimMessageFor,\n errorSite,\n findingsFor,\n messageFor,\n misplacedMessageFor,\n toValidationResult,\n} from \"./core/adapt.js\";\nexport {\n appendFrontmatterCitation,\n entryObject,\n insertStatementBefore,\n removeFrontmatterCitations,\n removeLine,\n spliceEntryField,\n unifiedDiff,\n} from \"./core/write.js\";\nexport type { EntryPath } from \"./core/write.js\";\nexport { mintCitation } from \"./core/mint.js\";\nexport { CITE_SECTION, DEFAULT_CITE_BASELINE_PATH, loadCiteConfig, parseCiteConfig, readCiteConfigFile, resolveCiteRun } from \"./core/config.js\";\nexport type { CiteRunOptions } from \"./core/config.js\";\n\nexport { runCheck } from \"./commands/check.js\";\nexport { runAdd } from \"./commands/add.js\";\nexport { runRemove } from \"./commands/remove.js\";\nexport { runUpdate } from \"./commands/update.js\";\nexport { reencryptCitationEntries, reencryptCitations } from \"./core/reencrypt.js\";\nexport type { ReencryptEntriesResult, ReencryptOptions } from \"./core/reencrypt.js\";\nexport {\n refusalLine,\n removalLine,\n renderCheckPretty,\n renderRemovePretty,\n renderUpdatePretty,\n rewriteLine,\n} from \"./reporters/pretty.js\";\nexport type { PrettyOptions } from \"./reporters/pretty.js\";\nexport { renderCheckJson, renderRemoveJson, renderUpdateJson } from \"./reporters/json.js\";\nexport { renderCheckGithub } from \"./reporters/github.js\";\n","/**\n * `reencryptCitations`: re-encrypt one page's encrypted citations under a new\n * key, for `manni key rotate` (proposal 0045). It reads sources and never\n * writes: the caller gets the rewritten page back, and writes it only once\n * every page in the run could be re-encrypted.\n *\n * A citation counts as done only when its `source.file` decrypts under the\n * new key *and* its pin holds under the new key. Either alone is a half\n * rotation, and a rerun has to finish it rather than declare it done. Meta's\n * walker cannot leave one today, because it skips the whole `citations` key\n * and cite encrypts in its own `cite-src` context; an interrupted run, a hand\n * edit, or a second writer of the same manifest can.\n *\n * The path must be tracked, and the pin must hold under the old key, over the\n * lines as they are today or, with git, as they were at the entry's\n * `commit-sha` (the classifier's history search). Then `file` becomes the\n * path's ciphertext under the new key, its lines kept, and `integrity` the\n * keyed pin under it, so a `changed` citation stays exactly as changed. A pin\n * that holds nowhere is skipped, with `update --accept` named as the repair.\n * No message names a path.\n */\nimport type {\n Citation,\n CitationInput,\n CitationOrigin,\n GitClient,\n ReencryptCitationsResult,\n ReencryptedCitation,\n SourceIndex,\n SourceRange,\n} from \"../types.js\";\nimport { historyOf } from \"./classify.js\";\nimport { gitClient } from \"./git.js\";\nimport { hashLines, sliceLines, splitLines } from \"./hash.js\";\nimport { readPage } from \"./page.js\";\nimport { formatSrc, sourceRange, spellSource } from \"./range.js\";\nimport { buildSourceIndex, decryptSourcePath, encryptSourcePath, readSource } from \"./sources.js\";\nimport { spliceEntryField } from \"./write.js\";\n\nconst UNDECRYPTABLE = \"does not decrypt under the current key\";\nconst MISSING = \"missing (no tracked file matches)\";\nconst CHANGED = \"changed; run `manni cite update --accept` before rotating\";\n\ntype Where = Pick<ReencryptedCitation, \"id\" | \"index\" | \"line\">;\n\n/** The fields a report row carries to name the entry: its id, or where it sits. */\nfunction whereOf(citation: Citation, origin: CitationOrigin): Where {\n const where: Where = { index: origin.index };\n if (citation.id !== undefined) where.id = citation.id;\n if (origin.line !== undefined) where.line = origin.line;\n return where;\n}\n\ninterface Context {\n root: string;\n index: SourceIndex;\n git: GitClient;\n}\n\n/**\n * The lines the pin was taken over, joined: today's when the pin holds there\n * under `key`, else the lines at the entry's commit when git can show them;\n * else why neither.\n */\nasync function pinnedLines(\n ctx: Context,\n citation: Citation,\n range: SourceRange,\n path: string,\n key: string,\n): Promise<{ joined: string } | { skip: string }> {\n const source = await readSource(ctx.root, ctx.index, { ...range, path, encrypted: false });\n if (source.kind === \"missing\") return { skip: MISSING };\n const pin = citation.source.integrity;\n let joined: string | undefined;\n try {\n joined = sliceLines(splitLines(source.text), range);\n } catch {\n // The range runs past the end of the file as it is now.\n joined = undefined;\n }\n if (joined !== undefined && hashLines(joined, key) === pin) return { joined };\n\n const commit = citation.source[\"commit-sha\"];\n if (commit !== undefined && (await ctx.git.available())) {\n const history = await historyOf(ctx.git, commit, path, range, pin, key, undefined);\n if (history.kind === \"original\") return { joined: history.lines.join(\"\\n\") };\n }\n return { skip: CHANGED };\n}\n\n/** What one citation needs: nothing, a new pair of values, or a reason it cannot be done. */\ntype Verdict =\n | { kind: \"done\" }\n | { kind: \"skip\"; message: string }\n | { kind: \"write\"; file: string; integrity: string; to: string };\n\n/** Options every re-encryption takes, whichever channel the entry lives in. */\nexport interface ReencryptOptions {\n root: string;\n fromKey: string;\n toKey: string;\n /** History and the source index are read through it; defaults to one over the root. */\n gitClient?: GitClient;\n sourceIndex?: SourceIndex;\n}\n\n/**\n * One citation's verdict: whether it is already under the new key, what its\n * `source.file` and `source.integrity` become, or why neither. The rule is\n * the same wherever the entry is kept, so the page splicer and the manifest\n * writer both go through here.\n */\nasync function verdictFor(\n ctx: Context,\n citation: Citation,\n opts: Pick<ReencryptOptions, \"fromKey\" | \"toKey\">,\n): Promise<Verdict> {\n const range = sourceRange(citation.source);\n const underNew = decryptSourcePath(range.path, opts.toKey);\n // Done only when both halves are under the new key; a file that is and a\n // pin that is not is the half rotation this finishes.\n if (underNew !== undefined) {\n const held = await pinnedLines(ctx, citation, range, underNew, opts.toKey);\n if (\"joined\" in held) return { kind: \"done\" };\n }\n const path = underNew ?? decryptSourcePath(range.path, opts.fromKey);\n if (path === undefined) return { kind: \"skip\", message: UNDECRYPTABLE };\n const lines = await pinnedLines(ctx, citation, range, path, opts.fromKey);\n if (\"skip\" in lines) return { kind: \"skip\", message: lines.skip };\n const file = underNew === undefined ? encryptSourcePath(path, opts.toKey) : range.path;\n return {\n kind: \"write\",\n file,\n integrity: hashLines(lines.joined, opts.toKey),\n to: formatSrc({ ...range, path: file }),\n };\n}\n\n/** The git client and source index a run shares, built once per page at most. */\nasync function contextFor(opts: ReencryptOptions): Promise<Context> {\n const git = opts.gitClient ?? gitClient(opts.root);\n const index = opts.sourceIndex ?? (await buildSourceIndex(opts.root, { gitClient: git }));\n return { root: opts.root, index, git };\n}\n\nexport async function reencryptCitations(\n page: { file: string; content: string; format?: string },\n opts: ReencryptOptions,\n): Promise<ReencryptCitationsResult> {\n const read = readPage(page.file, page.content, page.format === undefined ? undefined : { format: page.format });\n const result: ReencryptCitationsResult = { content: page.content, rewritten: [], skipped: [] };\n const encrypted = read.citations.filter(({ citation }) => sourceRange(citation.source).encrypted);\n // A page with nothing encrypted costs no index and no git.\n if (encrypted.length === 0) return result;\n\n const ctx = await contextFor(opts);\n let after = page.content;\n for (const { citation, origin } of encrypted) {\n const range = sourceRange(citation.source);\n const where = whereOf(citation, origin);\n const verdict = await verdictFor(ctx, citation, opts);\n if (verdict.kind === \"done\") continue;\n if (verdict.kind === \"skip\") {\n result.skipped.push({ ...where, message: verdict.message });\n continue;\n }\n if (verdict.file !== range.path) {\n after = spliceEntryField(after, read.format, origin.index, [\"source\", \"file\"], verdict.file);\n }\n after = spliceEntryField(\n after,\n read.format,\n origin.index,\n [\"source\", \"integrity\"],\n verdict.integrity,\n );\n result.rewritten.push({ ...where, from: spellSource(citation.source), to: verdict.to });\n }\n result.content = after;\n return result;\n}\n\n/** What `reencryptCitationEntries` did to one page's manifest entries. */\nexport interface ReencryptEntriesResult {\n /** The entries as they should now be written, a copy of what came in. */\n entries: unknown[];\n /** Whether any of them changed. */\n changed: boolean;\n rewritten: ReencryptedCitation[];\n skipped: { id?: string; index?: number; line?: number; message: string }[];\n}\n\n/**\n * The same rotation, for a page whose citations live in a manifest.\n *\n * The entries come from meta's merge, so they are plain values; each one is\n * validated as `readPage` validates a frontmatter entry, and an encrypted\n * source's `file` and `integrity` are rewritten in place. The caller writes\n * the whole list back with one splice, once every page of the run could be\n * re-encrypted.\n */\nexport async function reencryptCitationEntries(\n page: { file: string; content: string; format?: string; citations: readonly CitationInput[] },\n opts: ReencryptOptions,\n): Promise<ReencryptEntriesResult> {\n const entries: unknown[] = JSON.parse(\n JSON.stringify(page.citations.map((input) => input.entry)),\n ) as unknown[];\n const out: ReencryptEntriesResult = { entries, changed: false, rewritten: [], skipped: [] };\n\n const read = readPage(page.file, page.content, {\n ...(page.format === undefined ? {} : { format: page.format }),\n citations: page.citations,\n });\n const encrypted = read.citations.filter(({ citation }) => sourceRange(citation.source).encrypted);\n if (encrypted.length === 0) return out;\n\n const ctx = await contextFor(opts);\n for (const { citation, origin } of encrypted) {\n const where = whereOf(citation, origin);\n const verdict = await verdictFor(ctx, citation, opts);\n if (verdict.kind === \"done\") continue;\n if (verdict.kind === \"skip\") {\n out.skipped.push({ ...where, message: verdict.message });\n continue;\n }\n const entry: unknown = entries[origin.index];\n const source =\n typeof entry === \"object\" && entry !== null && !Array.isArray(entry)\n ? (entry as Record<string, unknown>).source\n : undefined;\n if (typeof source !== \"object\" || source === null || Array.isArray(source)) {\n out.skipped.push({ ...where, message: UNDECRYPTABLE });\n continue;\n }\n const fields = source as Record<string, unknown>;\n fields.file = verdict.file;\n fields.integrity = verdict.integrity;\n out.changed = true;\n out.rewritten.push({ ...where, from: spellSource(citation.source), to: verdict.to });\n }\n return out;\n}\n","import { ToolError } from \"../shared/errors.js\";\n\n/** An operational or usage error in the key domain: exit 2. */\nexport class KeyError extends ToolError {\n constructor(message: string) {\n super(message);\n this.name = \"KeyError\";\n }\n}\n","/**\n * `manni key rotate [paths...]`: re-encrypt every encrypted value under a new\n * key, then write the key (proposal 0045).\n *\n * Values are found by their ciphertext, never through schema marks: meta's\n * `reencryptMetadata` takes every string of the ciphertext shape in a page's\n * metadata, and cite's `reencryptCitations` every encrypted `source.file` with its\n * keyed pin. A value already under the new key counts as done, so a run can\n * always be repeated.\n *\n * A value does not have to sit in a page. An external-metadata manifest\n * (proposal 0037) holds the private half of the same documents, which is\n * where an encrypted value most often lives, so the local manifests of the\n * collections a run covers are re-encrypted with the pages. See\n * `planManifests`.\n *\n * Input resolution is `cite check`'s: positional paths from `cwd`, else the\n * selected collections' `paths:` from the config's directory, `--exclude`\n * added to a collection's own `exclude:`, and zero files an error unless\n * `--allow-empty`.\n *\n * Every page and manifest is re-encrypted in memory first. One skip and\n * nothing is written (exit 1). Otherwise a whole run whose key comes from the\n * config writes in three steps, so that an interruption at any point leaves\n * every value readable by the next run:\n *\n * 1. the config: `encryptionKey:` the new key, `encryptionKeyPrevious:` the\n * old one, in one atomic write;\n * 2. the pages, then the manifests;\n * 3. the config again, without `encryptionKeyPrevious:`.\n *\n * A run that finds `encryptionKeyPrevious:` finishes that rotation: from the\n * previous key to the current one. A narrowed run (paths or `--collection`)\n * and a run whose key comes from `MANNI_ENCRYPTION_KEY` write pages and\n * manifests and never the config. `--dry-run` writes nothing at all.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { isAbsolute, join, relative, resolve, sep } from \"node:path\";\nimport { parse as parseYaml } from \"yaml\";\nimport {\n DEFAULT_CITE_BASELINE_PATH,\n GIT_UNAVAILABLE_HISTORY,\n ManifestSet,\n buildSourceIndex,\n gitClient,\n loadCitationSidecars,\n parseCiteConfig,\n readPage,\n sourceRange,\n reencryptCitationEntries,\n reencryptCitations,\n type CiteConfig,\n type CitationSidecars,\n type GitClient,\n type ReencryptCitationsResult,\n type SourceIndex,\n} from \"../../cite/index.js\";\nimport {\n PATH_JOIN,\n classifyRef,\n externalMetadataJoin,\n loadExternalMetadata,\n reencryptMetadata,\n supportedExtensions,\n writeFileAtomic,\n type ExternalMetadataEntry,\n type ExternalMetadataIndex,\n type ExternalMetadataValue,\n} from \"../../meta/index.js\";\nimport {\n STDIN_TOKEN,\n assertNonEmpty,\n configMarks,\n extractorByName,\n gitignoreOptions,\n reencryptData,\n resolveTargetSet,\n spliceManifestValue,\n} from \"../../meta/internal.js\";\nimport { isMember, selectCollections, type CollectionConfig } from \"../../shared/collections.js\";\nimport type { ConfigFile } from \"../../shared/config-file.js\";\nimport { resolveEncryptionKey, writeEncryptionKey } from \"../../shared/encryption-key.js\";\nimport { generateEncryptionKey, isValidEncryptionKey } from \"../../shared/encryption.js\";\nimport { findGitRoot } from \"../../shared/git-root.js\";\nimport {\n findPageManifests,\n hasPagePlaceholder,\n pageManifestPath,\n} from \"../../shared/page-manifest.js\";\nimport { readRotateConfig, toKeyError, unfinishedRotation } from \"../core/config.js\";\nimport { KeyError } from \"../errors.js\";\nimport type {\n KeyRotateOptions,\n KeyRotateResult,\n RotateManifest,\n RotateOutcome,\n RotatePage,\n RotatedValue,\n SkippedValue,\n} from \"../types.js\";\n\nconst BAD_TO = \"--to must be at least 32 hex or base64url characters.\";\nconst NO_STDIN =\n \"key rotate reads and writes files, so it takes no stdin (`-`). Name the files instead.\";\nconst WITH_PATHS =\n \"--collection selects a configured collection; it cannot be combined with paths.\";\nconst NEEDS_CONFIG = \"--collection needs a config file to select from.\";\nconst NO_KEY =\n \"No encryption key is available, so nothing can be re-encrypted. Run `manni key set` first.\";\nconst ENV_NEEDS_TO =\n \"The key comes from MANNI_ENCRYPTION_KEY; pass --to <value>, re-encrypt with it, then update the secret. Nothing is written to config.\";\nconst NARROWED_NEEDS_TO = \"A run over part of the family needs --to, and never writes the key.\";\nconst NO_FILES =\n \"No files to re-encrypt. Pass paths/globs, or declare a collection under `collections:` in manni.config.yaml.\";\n\n/**\n * Any ciphertext at all. A page without one has nothing to rotate, so it costs\n * no parse; with one, the page is parsed and the tag decides.\n */\nconst ANY_CIPHERTEXT = /~[A-Za-z0-9_-]{82,}/;\n\n/** The `cite:` section of the file, for `root:` and `baseline:`; `{}` without one. */\nfunction citeSection(file: ConfigFile | null): CiteConfig {\n if (file === null) return {};\n const doc: unknown = parseYaml(file.text);\n if (typeof doc !== \"object\" || doc === null || !(\"cite\" in doc)) return {};\n return parseCiteConfig(doc.cite, file.source);\n}\n\n/**\n * Where cited sources resolve from, as `cite` resolves it: `--root` (cwd\n * relative) > `cite.root` (config relative) > the git root > `cwd`.\n */\nfunction rootFor(\n flag: string | undefined,\n cite: CiteConfig,\n file: ConfigFile | null,\n cwd: string,\n): { root: string; fellBack: boolean } {\n if (flag !== undefined) return { root: resolve(cwd, flag), fellBack: false };\n if (file !== null && cite.root !== undefined) {\n return { root: resolve(file.dir, cite.root), fellBack: false };\n }\n const gitRoot = findGitRoot(cwd);\n return gitRoot === null ? { root: cwd, fellBack: true } : { root: gitRoot, fellBack: false };\n}\n\nfunction isEnoent(error: unknown): boolean {\n return typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\";\n}\n\nasync function indexFor(root: string, client: GitClient): Promise<SourceIndex> {\n try {\n return await buildSourceIndex(root, { gitClient: client });\n } catch (error) {\n if (isEnoent(error)) throw new KeyError(`Root directory not found: ${root}.`);\n throw error;\n }\n}\n\n/**\n * The page's encrypted citations, the only ones a rotation reads sources\n * for: whether it has any, and whether one carries a commit (its own or the\n * page's), which is when history would be read.\n */\nfunction encryptedCitations(\n file: string,\n content: string,\n format: string | undefined,\n): { any: boolean; withCommit: boolean } {\n const read = readPage(file, content, format === undefined ? undefined : { format });\n const encrypted = read.citations.filter(({ citation }) => sourceRange(citation.source).encrypted);\n return {\n any: encrypted.length > 0,\n withCommit: encrypted.some(({ citation }) => citation.source[\"commit-sha\"] !== undefined),\n };\n}\n\ninterface Planned {\n page: RotatePage;\n path: string;\n content: string;\n changed: boolean;\n}\n\n/**\n * The citations of one page that a manifest owns (proposal 0044). They are\n * re-encrypted exactly as a page's own are — a citation counts as done only\n * when its `source.file` decrypts under the new key *and* its pin holds —\n * and written back as one value per page, each manifest written once.\n *\n * Kept in its own function, and reached from one place in the loop below, so\n * nothing about how *meta* values are rotated changes.\n */\nasync function rotateManifestCitations(\n sidecars: CitationSidecars | null,\n manifests: ManifestSet,\n page: { file: string; content: string; format?: string },\n opts: {\n root: string;\n fromKey: string;\n toKey: string;\n gitClient: GitClient;\n sourceIndex: () => Promise<SourceIndex>;\n },\n): Promise<{ rewritten: RotatedValue[]; skipped: SkippedValue[]; wantsHistory: boolean }> {\n const none = { rewritten: [], skipped: [], wantsHistory: false };\n if (sidecars === null) return none;\n const sidecar = await sidecars.forPage(page.file, page.content, page.format);\n const owner = sidecar.owner;\n if (owner === undefined || sidecar.citations === undefined) return none;\n // Only a manifest entry that actually holds a ciphertext costs an index.\n if (!sidecar.citations.some((input) => ANY_CIPHERTEXT.test(JSON.stringify(input.entry)))) {\n return none;\n }\n const result = await reencryptCitationEntries(\n { ...page, citations: sidecar.citations },\n {\n root: opts.root,\n fromKey: opts.fromKey,\n toKey: opts.toKey,\n gitClient: opts.gitClient,\n sourceIndex: await opts.sourceIndex(),\n },\n );\n if (result.changed && sidecar.entry !== undefined) {\n await manifests.write(owner, sidecar.entry, result.entries, 0);\n }\n return {\n rewritten: result.rewritten.map((r) => ({ kind: \"citation\" as const, ...r })),\n skipped: result.skipped.map((s) => ({ kind: \"citation\" as const, ...s })),\n // A pin that no longer holds is re-keyed from the lines at its commit.\n wantsHistory: sidecar.citations.some((input) =>\n /\"commit-sha\"\\s*:/.test(JSON.stringify(input.entry)),\n ),\n };\n}\n\ninterface PlannedManifest {\n manifest: RotateManifest;\n path: string;\n /** The manifest's text, with every rewritten value spliced into it. */\n text: string;\n changed: boolean;\n}\n\n/** How a run spells a manifest: relative to its base, like every file label. */\nfunction reportedPath(abs: string, base: string): string {\n const rel = relative(base, abs);\n return rel === \"\" ? \".\" : rel.split(sep).join(\"/\");\n}\n\n/**\n * The collections whose manifests this run covers. A run over every\n * collection, and one narrowed by `--collection`, covers the collections it\n * selected. A run over positional paths covers the collections those files\n * belong to, so the private half of a page a run re-encrypts moves with it.\n */\nfunction manifestCollections(\n collections: readonly CollectionConfig[],\n opts: {\n fromCollections: boolean;\n files: readonly string[];\n base: string;\n configDir: string;\n },\n): CollectionConfig[] {\n if (opts.fromCollections) return [...collections];\n const rels = opts.files.map((rel) =>\n reportedPath(resolve(opts.base, rel), opts.configDir),\n );\n return collections.filter((c) => rels.some((rel) => isMember(c, rel)));\n}\n\n/** The owned values one manifest entry supplies, or an empty map. */\nfunction valuesOf(\n index: ExternalMetadataIndex,\n entry: ExternalMetadataEntry,\n): ReadonlyMap<string, ExternalMetadataValue> {\n const empty = new Map<string, ExternalMetadataValue>();\n if (entry.join === PATH_JOIN) {\n return entry.abs === undefined ? empty : (index.byPath.get(entry.abs) ?? empty);\n }\n return index.byField.get(entry.join)?.get(entry.spelled) ?? empty;\n}\n\n/**\n * Re-encrypt the metadata values that live in the selected collections' local\n * manifests (proposals 0037, 0039 and 0041).\n *\n * A manifest is private by construction, so it is where an encrypted value is\n * most likely to sit. Rotation would otherwise leave it under the old key and\n * `meta validate` would report `encrypted:unreadable` on every page the\n * manifest feeds.\n *\n * Two things are left alone. A URL manifest is somebody else's file and\n * read-only (0038), so it is never loaded, and a rotation reaches no network.\n * The `citations` key is cite's: it re-keys a citation's source together with\n * its pin, under its own context, and re-encrypting the source alone would\n * break the pin. `reencryptData` skips it for the same reason\n * `reencryptMetadata` does on a page.\n *\n * Text in, text out. Each value is spliced into the manifest by\n * `spliceManifestValue`, which replaces that value's range and keeps every\n * other byte: the comments, the key order, the quoting and the line endings.\n * Nothing is written here; the caller writes when every value could be\n * re-encrypted.\n */\nasync function planManifests(opts: {\n collections: readonly CollectionConfig[];\n configDir: string;\n base: string;\n fromKey: string;\n toKey: string;\n /** The run's pages, as absolute paths, which a `{page}` manifest (0058) is read for. */\n pages: readonly string[];\n /** A run over the whole family: no paths and no `--collection`. */\n whole: boolean;\n}): Promise<PlannedManifest[]> {\n const local = opts.collections\n .map((c) => ({\n ...c,\n externalMetadata: c.externalMetadata.filter(\n (m) => classifyRef(m.file).kind !== \"url\",\n ),\n }))\n .filter((c) => c.externalMetadata.length > 0);\n if (local.length === 0) return [];\n\n // A `{page}` entry (proposal 0058) is one manifest per page, so its files\n // are enumerated rather than named: each page of the run resolves its own,\n // and a whole run adds every file the pattern's glob finds, so a manifest\n // whose page is gone is re-encrypted too (0058 stress test 12). The pages\n // those files name are handed to the loader like the run's own.\n const pages = new Set(opts.pages);\n if (opts.whole) {\n for (const c of local) {\n for (const m of c.externalMetadata) {\n if (!hasPagePlaceholder(m.file)) continue;\n for (const found of findPageManifests(m.file, opts.configDir, (rel) => isMember(c, rel))) {\n for (const entry of found.entries) pages.add(entry.pageAbs);\n }\n }\n }\n }\n\n const index = await loadExternalMetadata(local, {\n configDir: opts.configDir,\n base: opts.base,\n pages: [...pages],\n });\n if (index === null) return [];\n\n // One plan per manifest file, so a manifest two collections declare is read\n // once and spliced once. Its reported path and collection identify it the\n // way `index.entries` does. A plan is made when an entry first names its\n // file, and only a plan with a value to report is kept.\n const plans = new Map<string, PlannedManifest>();\n const located = new Map<string, { abs: string; collection: string }>();\n const locate = (collection: string, abs: string, join: string): void => {\n located.set(`${collection}\\u0000${reportedPath(abs, opts.base)}\\u0000${join}`, { abs, collection });\n };\n for (const c of local) {\n for (const m of c.externalMetadata) {\n const join = externalMetadataJoin(m);\n if (!hasPagePlaceholder(m.file)) {\n locate(c.name, isAbsolute(m.file) ? m.file : resolve(opts.configDir, m.file), join);\n continue;\n }\n for (const page of pages) {\n const resolved = pageManifestPath(m.file, opts.configDir, page);\n if (!(\"outside\" in resolved)) locate(c.name, resolved.abs, join);\n }\n }\n }\n const planFor = async (key: string): Promise<PlannedManifest | undefined> => {\n const where = located.get(key);\n if (where === undefined) return undefined;\n const known = plans.get(where.abs);\n if (known !== undefined) return known;\n const plan: PlannedManifest = {\n manifest: {\n file: reportedPath(where.abs, opts.base),\n collection: where.collection,\n rewritten: [],\n skipped: [],\n written: false,\n },\n path: where.abs,\n text: await readFile(where.abs, \"utf8\"),\n changed: false,\n };\n plans.set(where.abs, plan);\n return plan;\n };\n\n for (const entry of index.entries) {\n const plan = await planFor(`${entry.collection}\\u0000${entry.file}\\u0000${entry.join}`);\n if (plan === undefined) continue;\n const data: Record<string, unknown> = {};\n for (const [key, supplied] of valuesOf(index, entry)) {\n if (supplied.file === entry.file && supplied.collection === entry.collection) {\n data[key] = supplied.value;\n }\n }\n const done = reencryptData(data, { fromKey: opts.fromKey, toKey: opts.toKey });\n for (const r of done.rewritten) {\n plan.manifest.rewritten.push({ entry: entry.spelled, ...r });\n }\n for (const s of done.skipped) {\n plan.manifest.skipped.push({ entry: entry.spelled, ...s });\n }\n for (const key of done.keys) {\n plan.text = spliceManifestValue(plan.text, {\n entry: entry.spelled,\n key,\n value: done.data[key],\n join: entry.join,\n file: plan.manifest.file,\n }).text;\n plan.changed = true;\n }\n }\n\n return [...plans.values()].filter(\n (p) => p.manifest.rewritten.length > 0 || p.manifest.skipped.length > 0,\n );\n}\n\nexport async function runKeyRotate(opts: KeyRotateOptions): Promise<KeyRotateResult> {\n const cwd = resolve(opts.cwd ?? process.cwd());\n const env = opts.env ?? process.env;\n if (opts.to !== undefined && !isValidEncryptionKey(opts.to)) throw new KeyError(BAD_TO);\n if (opts.inputs.includes(STDIN_TOKEN)) throw new KeyError(NO_STDIN);\n const wanted = opts.collection ?? [];\n if (wanted.length > 0 && opts.inputs.length > 0) throw new KeyError(WITH_PATHS);\n\n const file = await readRotateConfig(opts.configPath, cwd);\n if (wanted.length > 0 && file === null) throw new KeyError(NEEDS_CONFIG);\n const { key: current, source: keySource } = resolveEncryptionKey({\n env,\n file,\n toError: toKeyError,\n });\n if (current === undefined) throw new KeyError(NO_KEY);\n const narrowed = opts.inputs.length > 0 || wanted.length > 0;\n\n // Only a key from the config has a config a rotation can be finished in.\n const keyFile = keySource === \"config\" ? file : null;\n const previous = keyFile?.encryptionKeyPrevious;\n if (\n keyFile !== null &&\n previous !== undefined &&\n (narrowed || (opts.to !== undefined && opts.to !== current))\n ) {\n throw new KeyError(unfinishedRotation(keyFile.source));\n }\n if (keySource === \"env\" && opts.to === undefined) throw new KeyError(ENV_NEEDS_TO);\n if (narrowed && opts.to === undefined) throw new KeyError(NARROWED_NEEDS_TO);\n\n // Finishing an interrupted rotation goes from the key it replaced to the one\n // the config already holds; otherwise from the current key to the new one.\n const fromKey = previous ?? current;\n const toKey = previous === undefined ? (opts.to ?? generateEncryptionKey()) : current;\n\n const collections =\n file === null ? [] : selectCollections(file.collections, wanted, file.source, toKeyError);\n const fromCollections = opts.inputs.length === 0;\n const inputs = fromCollections ? collections.flatMap((c) => c.paths) : opts.inputs;\n if (inputs.length === 0) throw new KeyError(NO_FILES);\n // One base per run, as in cite and meta: typed paths from cwd, a\n // collection's `paths:` from the config's directory.\n const base = fromCollections && file !== null ? file.dir : cwd;\n\n const forced = opts.as === undefined ? undefined : extractorByName(opts.as);\n if (opts.as !== undefined && forced === undefined) {\n throw new KeyError(\n `Unknown format \"${opts.as}\". Supported extensions: ${supportedExtensions().join(\", \")}.`,\n );\n }\n const format = forced?.name;\n const exts = opts.exts ?? forced?.extensions;\n const exclude = [\n ...new Set([\n ...(opts.exclude ?? []),\n ...(fromCollections ? collections.flatMap((c) => c.exclude) : []),\n ]),\n ];\n const { files, gitignoreSkipped } = await resolveTargetSet({\n inputs,\n exts,\n exclude,\n cwd: base,\n allowEmpty: opts.allowEmpty,\n ...gitignoreOptions({ flag: opts.respectGitignore, onNotice: opts.onNotice }),\n });\n assertNonEmpty({\n files,\n inputs,\n usingStdin: false,\n allowEmpty: opts.allowEmpty,\n exclude,\n exts,\n gitignoreSkipped,\n action: \"re-encrypted\",\n });\n\n const cite = citeSection(file);\n const { root, fellBack } = rootFor(opts.root, cite, file, cwd);\n const client = opts.gitClient ?? gitClient(root);\n // Built once, and only when a page cites an encrypted source.\n let index: Promise<SourceIndex> | undefined;\n const sourceIndex = (): Promise<SourceIndex> => {\n if (index === undefined) {\n if (fellBack) opts.onNotice?.(`No git root found; resolving src: paths from ${cwd}`);\n index = indexFor(root, client);\n }\n return index;\n };\n\n // The manifests that own `citations` (proposal 0044): a page whose entries\n // live in one carries no ciphertext of its own, so they are read for every\n // page of the run, not only the ones the shortcut below lets through.\n const sidecars =\n file === null\n ? null\n : await loadCitationSidecars({\n collections: file.collections,\n configDir: file.dir,\n base,\n configSource: file.source,\n key: current,\n toError: toKeyError,\n // A keyless manifest (proposal 0068) keeps what a page's schemas mark.\n marks: () => configMarks(file.path, file.dir),\n // A `{page}` manifest (0058) is read for exactly the pages rotated.\n pages: files.map((rel) => resolve(base, rel)),\n });\n const manifests = new ManifestSet();\n\n const planned: Planned[] = [];\n let wantsHistory = false;\n for (const rel of files) {\n const path = resolve(base, rel);\n const before = await readFile(path, \"utf8\");\n const page = { file: rel, content: before, ...(format === undefined ? {} : { format }) };\n // A page's own values first, then the entries its manifest holds.\n const sidecarWork = await rotateManifestCitations(sidecars, manifests, page, {\n root,\n fromKey,\n toKey,\n gitClient: client,\n sourceIndex,\n });\n if (sidecarWork.wantsHistory) wantsHistory = true;\n if (!ANY_CIPHERTEXT.test(before)) {\n if (sidecarWork.rewritten.length === 0 && sidecarWork.skipped.length === 0) continue;\n planned.push({\n page: { file: rel, rewritten: sidecarWork.rewritten, skipped: sidecarWork.skipped, written: false },\n path,\n content: before,\n changed: false,\n });\n continue;\n }\n const meta = reencryptMetadata(page, { fromKey, toKey });\n const encrypted = encryptedCitations(rel, meta.content, format);\n if (encrypted.withCommit) wantsHistory = true;\n const cited: ReencryptCitationsResult = encrypted.any\n ? await reencryptCitations(\n { ...page, content: meta.content },\n { root, fromKey, toKey, gitClient: client, sourceIndex: await sourceIndex() },\n )\n : { content: meta.content, rewritten: [], skipped: [] };\n const rewritten: RotatedValue[] = [\n ...meta.rewritten.map((r) => ({ kind: \"metadata\" as const, ...r })),\n ...cited.rewritten.map((r) => ({ kind: \"citation\" as const, ...r })),\n ...sidecarWork.rewritten,\n ];\n const skipped: SkippedValue[] = [\n ...meta.skipped.map((s) => ({ kind: \"metadata\" as const, ...s })),\n ...cited.skipped.map((s) => ({ kind: \"citation\" as const, ...s })),\n ...sidecarWork.skipped,\n ];\n if (rewritten.length === 0 && skipped.length === 0) continue;\n planned.push({\n page: { file: rel, rewritten, skipped, written: false },\n path,\n content: cited.content,\n changed: cited.content !== before,\n });\n }\n\n // A pin that no longer holds is re-keyed from the lines at its commit, so a\n // citation with one wants git. Where git is not there, said once.\n if (wantsHistory && !(await client.available())) opts.onNotice?.(GIT_UNAVAILABLE_HISTORY);\n\n // The private half of the same documents: every local manifest of the\n // collections this run covers. Planned in memory like the pages, and\n // counted with them, so one unreadable value anywhere stops the whole run.\n const valueManifests =\n file === null\n ? []\n : await planManifests({\n collections: manifestCollections(collections, {\n fromCollections,\n files,\n base,\n configDir: file.dir,\n }),\n configDir: file.dir,\n base,\n fromKey,\n toKey,\n pages: files.map((rel) => resolve(base, rel)),\n whole: !narrowed,\n });\n\n const reencrypted =\n planned.reduce((n, p) => n + p.page.rewritten.length, 0) +\n valueManifests.reduce((n, m) => n + m.manifest.rewritten.length, 0);\n const skipped =\n planned.reduce((n, p) => n + p.page.skipped.length, 0) +\n valueManifests.reduce((n, m) => n + m.manifest.skipped.length, 0);\n const writePage = opts.writePage ?? ((path: string, content: string) => writeFileAtomic(path, content));\n\n let outcome: RotateOutcome;\n if (skipped > 0) {\n // The new key is never written beside a value it cannot decrypt, and no\n // page is written without the key: nothing at all.\n outcome = \"skipped\";\n } else if (opts.dryRun === true) {\n outcome = \"dry-run\";\n } else {\n const writesKey = !narrowed && keyFile !== null;\n // (1) The new key, with the old one beside it. A rotation being finished\n // already has both.\n if (!narrowed && keyFile !== null && previous === undefined) {\n await writeEncryptionKey({ file: keyFile, key: toKey, previous: fromKey, cwd, toError: toKeyError });\n }\n // (2) The pages, then the manifests: the citations one owns, and the\n // encrypted values another holds. Each manifest is written once,\n // however many pages it keeps entries for.\n for (const p of planned) {\n if (!p.changed) continue;\n await writePage(p.path, p.content);\n p.page.written = true;\n }\n for (const changed of manifests.changed()) await writePage(changed.path, changed.text);\n for (const m of valueManifests) {\n if (!m.changed) continue;\n await writePage(m.path, m.text);\n m.manifest.written = true;\n }\n // (3) The old key goes, now that nothing is under it.\n if (!narrowed && keyFile !== null) {\n await writeEncryptionKey({ file: keyFile, key: toKey, previous: null, cwd, toError: toKeyError });\n }\n if (narrowed) outcome = \"narrowed\";\n else if (!writesKey) outcome = \"env\";\n else outcome = previous === undefined ? \"written\" : \"finished\";\n }\n\n const wrote = outcome !== \"skipped\" && outcome !== \"dry-run\";\n const baseline =\n file !== null && cite.baseline !== undefined\n ? resolve(file.dir, cite.baseline)\n : join(file?.dir ?? cwd, DEFAULT_CITE_BASELINE_PATH);\n\n return {\n pages: planned.map((p) => p.page),\n manifests: valueManifests.map((m) => m.manifest),\n reencrypted,\n skipped,\n keyWritten: outcome === \"written\" || outcome === \"finished\",\n outcome,\n ...(keyFile === null ? {} : { configSource: keyFile.source }),\n baselineStale: wrote && existsSync(baseline),\n exitCode: skipped > 0 ? 1 : 0,\n };\n}\n","/**\n * Which config file `manni key` reads and writes. `key` has no section of its\n * own (proposal 0045): the key it manages sits at the top of the family file,\n * beside `collections:`.\n *\n * - `set` writes the nearest family file whatever it carries, or the one `-c`\n * names, read as a family file (`findFamilyConfigFile`,\n * `readFamilyConfigFile`).\n * - `rotate` reads its key and collections from the file every sibling\n * without a section there would read them from: the nearest family file\n * carrying `collections:` or `encryptionKey:`. That is discovery with a\n * section name nothing uses.\n */\nimport {\n findConfigFile,\n findFamilyConfigFile,\n readConfigFile,\n readFamilyConfigFile,\n type ConfigFile,\n type ConfigFileOptions,\n} from \"../../shared/config-file.js\";\nimport { KeyError } from \"../errors.js\";\n\nexport const toKeyError = (message: string): KeyError => new KeyError(message);\n\nconst KEY_CONFIG: ConfigFileOptions = {\n section: \"key\",\n // The key never had a file of its own.\n legacyNames: [],\n toError: toKeyError,\n};\n\n/** The config `rotate` reads the current key and the collections from. */\nexport function readRotateConfig(\n configPath: string | undefined,\n cwd: string,\n): Promise<ConfigFile | null> {\n return configPath === undefined\n ? findConfigFile(cwd, KEY_CONFIG)\n : readConfigFile(configPath, cwd, KEY_CONFIG);\n}\n\n/** The config `set` writes to; `null` when discovery finds no family file. */\nexport function readSetConfig(\n configPath: string | undefined,\n cwd: string,\n): Promise<ConfigFile | null> {\n return configPath === undefined\n ? findFamilyConfigFile(cwd, toKeyError)\n : readFamilyConfigFile(configPath, cwd, toKeyError);\n}\n\n/** The refusal while `encryptionKeyPrevious:` says a rotation is unfinished. */\nexport const unfinishedRotation = (source: string): string =>\n `A rotation is unfinished in ${source}. Run \\`manni key rotate\\` with no --to to finish it.`;\n","/**\n * `manni key set [value]`: write the family encryption key (proposal 0045).\n *\n * Refusals, each exit 2 and none echoing a value: a value of the wrong shape;\n * `MANNI_ENCRYPTION_KEY` set, because it wins and the written key would never\n * be read; a rotation left unfinished; a key already configured, because\n * replacing one in place strands every value encrypted under it (`rotate` is\n * what replaces a key); and a new `manni.config.yaml` beside a legacy\n * `docmeta.config.yaml`, which the new file would hide from `manni meta`.\n *\n * It warns, and still writes, when git would publish the file.\n */\nimport { existsSync } from \"node:fs\";\nimport { basename, dirname, join, relative, resolve } from \"node:path\";\nimport { LEGACY_CONFIG_NAMES } from \"../../meta/internal.js\";\nimport {\n ENCRYPTION_KEY_ENV,\n committedKeyWarning,\n isIgnoredByGit,\n writeEncryptionKey,\n} from \"../../shared/encryption-key.js\";\nimport { generateEncryptionKey, isValidEncryptionKey } from \"../../shared/encryption.js\";\nimport { readSetConfig, toKeyError, unfinishedRotation } from \"../core/config.js\";\nimport { KeyError } from \"../errors.js\";\nimport type { KeySetOptions, KeySetResult } from \"../types.js\";\n\nconst BAD_VALUE =\n \"The key must be at least 32 hex or base64url characters. Run `manni key set` with no value to generate one.\";\nconst ENV_SET = `${ENCRYPTION_KEY_ENV} is set, so a key written to config would never be read. Unset it, or keep the key in the secret.`;\n\nconst alreadyConfigured = (source: string): string =>\n `An encryption key is already configured in ${source}. Run \\`manni key rotate\\` to replace it and re-encrypt every value.`;\n\n/**\n * A new family file beside a legacy per-tool file hides it: discovery reads\n * the family file first in a directory, and one holding only a key is every\n * tool's config, so `manni meta` would stop reading the options it had.\n */\nfunction refuseBesideLegacy(path: string, cwd: string): void {\n const dir = dirname(path);\n const name = basename(path);\n for (const legacy of LEGACY_CONFIG_NAMES) {\n const found = join(dir, legacy);\n if (!existsSync(found)) continue;\n const source = relative(cwd, found).replace(/\\\\/g, \"/\");\n throw new KeyError(\n `${source} is a single-tool config; a ${name} beside it would hide it. Move its keys under meta: in ${name} first.`,\n );\n }\n}\n\nexport async function runKeySet(opts: KeySetOptions): Promise<KeySetResult> {\n const cwd = resolve(opts.cwd ?? process.cwd());\n const env = opts.env ?? process.env;\n if (opts.value !== undefined && !isValidEncryptionKey(opts.value)) {\n throw new KeyError(BAD_VALUE);\n }\n // Empty counts as unset, as `resolveEncryptionKey` has it.\n const fromEnv = env[ENCRYPTION_KEY_ENV];\n if (fromEnv !== undefined && fromEnv !== \"\") throw new KeyError(ENV_SET);\n\n const file = await readSetConfig(opts.configPath, cwd);\n if (file?.encryptionKeyPrevious !== undefined) {\n throw new KeyError(unfinishedRotation(file.source));\n }\n if (file?.encryptionKey !== undefined) {\n throw new KeyError(alreadyConfigured(file.source));\n }\n\n const generated = opts.value === undefined;\n const key = opts.value ?? generateEncryptionKey();\n const dryRun = opts.dryRun === true;\n // Name the target before writing to it: the legacy check and the git\n // warning are both about the file the key is about to land in.\n const target = await writeEncryptionKey({ file, key, cwd, toError: toKeyError, dryRun: true });\n if (target.created) refuseBesideLegacy(target.path, cwd);\n if (isIgnoredByGit(target.path) === false) {\n opts.onNotice?.(committedKeyWarning(target.source));\n }\n if (!dryRun) await writeEncryptionKey({ file, key, cwd, toError: toKeyError });\n return { path: target.path, source: target.source, created: target.created, generated, dryRun };\n}\n"],"mappings":"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","names":["join","skipped","existsSync","join","relative","resolve","join","existsSync","relative","resolve"]}
@@ -0,0 +1,387 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ GraphError,
4
+ NS,
5
+ PREFIXES,
6
+ byCodeUnit
7
+ } from "./chunk-M2JCK5F6.js";
8
+ import {
9
+ packageRoot
10
+ } from "./chunk-TIUTIOFB.js";
11
+ import {
12
+ errorMessage
13
+ } from "./chunk-G3T47CFV.js";
14
+
15
+ // src/graph/core/load.ts
16
+ import { existsSync, readFileSync } from "node:fs";
17
+ import { Parser, Store } from "n3";
18
+ var XSD_STRING = `${NS.xsd}string`;
19
+ function loadGraph(ttlPath) {
20
+ if (!existsSync(ttlPath)) {
21
+ throw new GraphError(
22
+ `Graph not found: ${ttlPath} \u2014 run \`manni graph build\` first.`
23
+ );
24
+ }
25
+ return parseGraph(readFileSync(ttlPath, "utf8"), ttlPath);
26
+ }
27
+ function parseGraph(turtle, label) {
28
+ const parser = new Parser({ format: "text/turtle" });
29
+ let quads;
30
+ try {
31
+ quads = parser.parse(turtle);
32
+ } catch (e) {
33
+ throw new GraphError(
34
+ `Failed to parse ${label}: ${errorMessage(e)}`
35
+ );
36
+ }
37
+ return new Store(quads);
38
+ }
39
+ function storeToQuads(store) {
40
+ return store.getQuads(null, null, null, null).map((q) => {
41
+ const o = q.object;
42
+ let term;
43
+ if (o.termType === "Literal") {
44
+ const dt = o.datatype.value;
45
+ term = dt && dt !== XSD_STRING ? { kind: "literal", value: o.value, datatype: dt } : { kind: "literal", value: o.value };
46
+ } else {
47
+ term = { kind: "iri", value: o.value };
48
+ }
49
+ return { s: q.subject.value, p: q.predicate.value, o: term };
50
+ });
51
+ }
52
+ function expandTerm(input) {
53
+ const colon = input.indexOf(":");
54
+ if (colon > 0) {
55
+ const prefix = input.slice(0, colon);
56
+ const ns = NS[prefix];
57
+ if (ns) return `${ns}${input.slice(colon + 1)}`;
58
+ }
59
+ return input;
60
+ }
61
+ function compactIri(iri) {
62
+ for (const [prefix, ns] of PREFIXES) {
63
+ if (iri.startsWith(ns) && iri.length > ns.length) {
64
+ return `${prefix}:${iri.slice(ns.length)}`;
65
+ }
66
+ }
67
+ return iri;
68
+ }
69
+
70
+ // src/graph/core/pkg.ts
71
+ import { join } from "node:path";
72
+ function bundledShapesPath(moduleUrl) {
73
+ return join(packageRoot(moduleUrl), "shapes", "graph", "shapes-1.0.0.ttl");
74
+ }
75
+
76
+ // src/graph/core/shacl.ts
77
+ import { readFileSync as readFileSync2 } from "node:fs";
78
+ import { DataFactory, Parser as Parser2, Store as Store2 } from "n3";
79
+ import SHACLValidator from "rdf-validate-shacl";
80
+ var FAMILY_SEVERITY = {
81
+ violation: "error",
82
+ warning: "warning",
83
+ info: "notice"
84
+ };
85
+ function finding(shaclSeverity, rest) {
86
+ return { severity: FAMILY_SEVERITY[shaclSeverity], shaclSeverity, ...rest };
87
+ }
88
+ var SEVERITY_RANK = {
89
+ violation: 0,
90
+ warning: 1,
91
+ info: 2
92
+ };
93
+ function loadShapes(paths) {
94
+ const store = new Store2();
95
+ for (const path of paths) {
96
+ let text;
97
+ try {
98
+ text = readFileSync2(path, "utf8");
99
+ } catch {
100
+ throw new GraphError(`Shapes file not found: ${path}`);
101
+ }
102
+ try {
103
+ store.addQuads(new Parser2({ format: "text/turtle" }).parse(text));
104
+ } catch (e) {
105
+ throw new GraphError(
106
+ `Failed to parse shapes ${path}: ${errorMessage(e)}`
107
+ );
108
+ }
109
+ }
110
+ return store;
111
+ }
112
+ function blameDocs(store, focus) {
113
+ const pathPred = DataFactory.namedNode(`${NS.graph}path`);
114
+ const pathOf = (iri) => store.getQuads(DataFactory.namedNode(iri), pathPred, null, null)[0]?.object.value;
115
+ const found = /* @__PURE__ */ new Set();
116
+ const visited = /* @__PURE__ */ new Set();
117
+ const walk = (iri, depth) => {
118
+ if (visited.has(iri)) return;
119
+ visited.add(iri);
120
+ const own = pathOf(iri);
121
+ if (own !== void 0) {
122
+ found.add(own);
123
+ return;
124
+ }
125
+ const hash = iri.indexOf("#");
126
+ if (hash !== -1) {
127
+ const base = pathOf(iri.slice(0, hash));
128
+ if (base !== void 0) {
129
+ found.add(base);
130
+ return;
131
+ }
132
+ }
133
+ if (depth === 0) return;
134
+ for (const quad of store.getQuads(null, null, DataFactory.namedNode(iri), null)) {
135
+ if (quad.subject.termType === "NamedNode") {
136
+ walk(quad.subject.value, depth - 1);
137
+ }
138
+ }
139
+ };
140
+ walk(focus, 2);
141
+ return [...found].sort();
142
+ }
143
+ function broaderEdges(store) {
144
+ const edges = [];
145
+ for (const q of store.getQuads(
146
+ null,
147
+ DataFactory.namedNode(`${NS.skos}broader`),
148
+ null,
149
+ null
150
+ )) {
151
+ if (q.object.termType === "NamedNode") {
152
+ edges.push({ s: q.subject.value, o: q.object.value });
153
+ }
154
+ }
155
+ for (const q of store.getQuads(
156
+ null,
157
+ DataFactory.namedNode(`${NS.skos}narrower`),
158
+ null,
159
+ null
160
+ )) {
161
+ if (q.object.termType === "NamedNode") {
162
+ edges.push({ s: q.object.value, o: q.subject.value });
163
+ }
164
+ }
165
+ return edges;
166
+ }
167
+ function broaderCycles(store) {
168
+ const adjacency = /* @__PURE__ */ new Map();
169
+ const selfLoops = /* @__PURE__ */ new Set();
170
+ for (const { s, o } of broaderEdges(store)) {
171
+ if (s === o) selfLoops.add(s);
172
+ const list = adjacency.get(s);
173
+ if (list) list.push(o);
174
+ else adjacency.set(s, [o]);
175
+ if (!adjacency.has(o)) adjacency.set(o, []);
176
+ }
177
+ for (const list of adjacency.values()) list.sort();
178
+ const index = /* @__PURE__ */ new Map();
179
+ const lowlink = /* @__PURE__ */ new Map();
180
+ const onStack = /* @__PURE__ */ new Set();
181
+ const stack = [];
182
+ const components = [];
183
+ let counter = 0;
184
+ const numberOf = (map, node) => {
185
+ const value = map.get(node);
186
+ if (value === void 0) {
187
+ throw new GraphError(
188
+ `internal: ${node} was visited before it was numbered`
189
+ );
190
+ }
191
+ return value;
192
+ };
193
+ const nodes = [...adjacency.keys()].sort();
194
+ for (const root of nodes) {
195
+ if (index.has(root)) continue;
196
+ const frames = [[root, 0]];
197
+ for (let frame = frames.at(-1); frame !== void 0; frame = frames.at(-1)) {
198
+ const [node, childIdx] = frame;
199
+ if (childIdx === 0) {
200
+ index.set(node, counter);
201
+ lowlink.set(node, counter);
202
+ counter += 1;
203
+ stack.push(node);
204
+ onStack.add(node);
205
+ }
206
+ const children = adjacency.get(node) ?? [];
207
+ const child = children[childIdx];
208
+ if (child !== void 0) {
209
+ frame[1] += 1;
210
+ if (!index.has(child)) {
211
+ frames.push([child, 0]);
212
+ } else if (onStack.has(child)) {
213
+ lowlink.set(
214
+ node,
215
+ Math.min(numberOf(lowlink, node), numberOf(index, child))
216
+ );
217
+ }
218
+ } else {
219
+ if (lowlink.get(node) === index.get(node)) {
220
+ const component = [];
221
+ let member;
222
+ do {
223
+ member = stack.pop();
224
+ if (member === void 0) break;
225
+ onStack.delete(member);
226
+ component.push(member);
227
+ } while (member !== node);
228
+ if (component.length > 1 || selfLoops.has(node)) {
229
+ components.push(component.sort());
230
+ }
231
+ }
232
+ frames.pop();
233
+ const parent = frames.at(-1);
234
+ if (parent) {
235
+ lowlink.set(
236
+ parent[0],
237
+ Math.min(numberOf(lowlink, parent[0]), numberOf(lowlink, node))
238
+ );
239
+ }
240
+ }
241
+ }
242
+ }
243
+ return components.sort((a, b) => (a[0] ?? "") < (b[0] ?? "") ? -1 : 1);
244
+ }
245
+ function broaderClosure(edges, start) {
246
+ const adjacency = /* @__PURE__ */ new Map();
247
+ for (const { s, o } of edges) {
248
+ const list = adjacency.get(s);
249
+ if (list) list.push(o);
250
+ else adjacency.set(s, [o]);
251
+ }
252
+ const seen = /* @__PURE__ */ new Set();
253
+ const queue = [...adjacency.get(start) ?? []];
254
+ for (let node = queue.shift(); node !== void 0; node = queue.shift()) {
255
+ if (seen.has(node)) continue;
256
+ seen.add(node);
257
+ queue.push(...adjacency.get(node) ?? []);
258
+ }
259
+ return seen;
260
+ }
261
+ function relatedConflicts(store) {
262
+ const edges = broaderEdges(store);
263
+ const direct = /* @__PURE__ */ new Map();
264
+ for (const e of edges) {
265
+ const targets = direct.get(e.s);
266
+ if (targets) targets.add(e.o);
267
+ else direct.set(e.s, /* @__PURE__ */ new Set([e.o]));
268
+ }
269
+ const findings = [];
270
+ for (const q of store.getQuads(
271
+ null,
272
+ DataFactory.namedNode(`${NS.skos}related`),
273
+ null,
274
+ null
275
+ )) {
276
+ if (q.object.termType !== "NamedNode") continue;
277
+ const s = q.subject.value;
278
+ const o = q.object.value;
279
+ if (direct.get(s)?.has(o)) continue;
280
+ const conflict = broaderClosure(edges, s).has(o) || broaderClosure(edges, o).has(s);
281
+ if (!conflict) continue;
282
+ findings.push(
283
+ finding("violation", {
284
+ message: `skos:related conflicts with skos:broaderTransitive between ${compactIri(s)} and ${compactIri(o)} \u2014 a concept cannot be both related to and an ancestor/descendant of another`,
285
+ focusNode: s,
286
+ path: `${NS.skos}related`,
287
+ docs: blameDocs(store, s)
288
+ })
289
+ );
290
+ }
291
+ return findings;
292
+ }
293
+ function cycleFindings(store) {
294
+ return broaderCycles(store).map(
295
+ (members) => finding("violation", {
296
+ message: `skos:broader cycle through ${members.map((m) => compactIri(m)).join(
297
+ ", "
298
+ )} (${members.map((m) => m).join(" \u2192 ")}) \u2014 a concept cannot be its own ancestor`,
299
+ // `broaderCycles` returns only components of at least one member, so
300
+ // the first is there; `?? ""` says that without asserting it.
301
+ focusNode: members[0] ?? "",
302
+ path: `${NS.skos}broader`,
303
+ docs: [...new Set(members.flatMap((m) => blameDocs(store, m)))].sort()
304
+ })
305
+ );
306
+ }
307
+ var CURATED_FIELDS = /* @__PURE__ */ new Set(["sections", "revision-of", "derived-from"]);
308
+ var GRAPH_FILL_FRAGMENT = "#prov.graph-fill.";
309
+ function curatedFieldFindings(store) {
310
+ const filledField = `${NS.graph}filledField`;
311
+ const pathPred = DataFactory.namedNode(`${NS.graph}path`);
312
+ const findings = [];
313
+ for (const q of store.getQuads(null, DataFactory.namedNode(filledField), null, null)) {
314
+ if (q.object.termType !== "Literal") continue;
315
+ const field = q.object.value;
316
+ if (!CURATED_FIELDS.has(field)) continue;
317
+ const node = q.subject.value;
318
+ const at = node.indexOf(GRAPH_FILL_FRAGMENT);
319
+ const fieldAt = node.lastIndexOf(".field.");
320
+ if (at === -1 || fieldAt <= at) continue;
321
+ const activity = node.slice(0, fieldAt);
322
+ const model = node.slice(at + GRAPH_FILL_FRAGMENT.length, fieldAt);
323
+ const docIri = activity.slice(0, activity.indexOf("#"));
324
+ const path = store.getQuads(DataFactory.namedNode(docIri), pathPred, null, null)[0]?.object.value;
325
+ findings.push(
326
+ finding("violation", {
327
+ message: `meta-provenance attributes /graph/${field} to ${model} \u2014 ${field} is curated by hand, never filled by a machine`,
328
+ focusNode: activity,
329
+ path: filledField,
330
+ docs: path === void 0 ? blameDocs(store, activity) : [path]
331
+ })
332
+ );
333
+ }
334
+ return findings;
335
+ }
336
+ function severityOf(iri) {
337
+ if (iri === "http://www.w3.org/ns/shacl#Warning") return "warning";
338
+ if (iri === "http://www.w3.org/ns/shacl#Info") return "info";
339
+ return "violation";
340
+ }
341
+ async function validateGraph(store, shapesPaths) {
342
+ const shapes = loadShapes(shapesPaths);
343
+ const validator = new SHACLValidator(shapes);
344
+ let report;
345
+ try {
346
+ report = await validator.validate(store);
347
+ } catch (e) {
348
+ throw new GraphError(
349
+ `SHACL validation failed: ${errorMessage(e)}`
350
+ );
351
+ }
352
+ const findings = [];
353
+ for (const result of report.results) {
354
+ const focus = result.focusNode?.value ?? "";
355
+ const path = result.path?.value;
356
+ const messages = result.message.map((m) => m.value).filter((m) => m.length > 0);
357
+ const message = messages.length > 0 ? messages.join("; ") : `constraint violated${path ? ` on ${compactIri(path)}` : ""}`;
358
+ findings.push(
359
+ finding(severityOf(result.severity?.value), {
360
+ message,
361
+ focusNode: focus,
362
+ ...path !== void 0 ? { path } : {},
363
+ docs: blameDocs(store, focus)
364
+ })
365
+ );
366
+ }
367
+ findings.push(
368
+ ...cycleFindings(store),
369
+ ...relatedConflicts(store),
370
+ ...curatedFieldFindings(store)
371
+ );
372
+ findings.sort(
373
+ (a, b) => SEVERITY_RANK[a.shaclSeverity] - SEVERITY_RANK[b.shaclSeverity] || byCodeUnit(a.focusNode, b.focusNode) || byCodeUnit(a.path ?? "", b.path ?? "") || byCodeUnit(a.message, b.message)
374
+ );
375
+ return findings;
376
+ }
377
+
378
+ export {
379
+ loadGraph,
380
+ parseGraph,
381
+ storeToQuads,
382
+ expandTerm,
383
+ compactIri,
384
+ bundledShapesPath,
385
+ validateGraph
386
+ };
387
+ //# sourceMappingURL=chunk-MYMBCTDE.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/graph/core/load.ts","../src/graph/core/pkg.ts","../src/graph/core/shacl.ts"],"sourcesContent":["/** Load a built .ttl into an in-memory N3 store for query/stats. */\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { Parser, Store } from \"n3\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport { GraphError } from \"../types.js\";\nimport type { Quad, Term } from \"./derive.js\";\nimport { NS, PREFIXES } from \"./vocab.js\";\n\nconst XSD_STRING = `${NS.xsd}string`;\n\nexport function loadGraph(ttlPath: string): Store {\n if (!existsSync(ttlPath)) {\n throw new GraphError(\n `Graph not found: ${ttlPath} — run \\`manni graph build\\` first.`,\n );\n }\n return parseGraph(readFileSync(ttlPath, \"utf8\"), ttlPath);\n}\n\n/** Turtle already in memory into a store; `label` names it in an error. */\nexport function parseGraph(turtle: string, label: string): Store {\n const parser = new Parser({ format: \"text/turtle\" });\n let quads;\n try {\n quads = parser.parse(turtle);\n } catch (e) {\n throw new GraphError(\n `Failed to parse ${label}: ${errorMessage(e)}`,\n );\n }\n return new Store(quads);\n}\n\n/**\n * Convert an in-memory N3 store back to dockg's internal quad shape — the\n * bridge from the Turtle-reading Node side to the platform-neutral emitters and\n * runtime. A redundant `xsd:string` datatype is dropped so the result matches\n * what the JSON-LD path produces.\n */\nexport function storeToQuads(store: Store): Quad[] {\n return store.getQuads(null, null, null, null).map((q) => {\n const o = q.object;\n let term: Term;\n if (o.termType === \"Literal\") {\n const dt = o.datatype.value;\n term =\n dt && dt !== XSD_STRING\n ? { kind: \"literal\", value: o.value, datatype: dt }\n : { kind: \"literal\", value: o.value };\n } else {\n term = { kind: \"iri\", value: o.value };\n }\n return { s: q.subject.value, p: q.predicate.value, o: term };\n });\n}\n\n/** Expand `dcterms:references`-style prefixed names to full IRIs; pass through the rest. */\nexport function expandTerm(input: string): string {\n const colon = input.indexOf(\":\");\n if (colon > 0) {\n const prefix = input.slice(0, colon);\n const ns = (NS as Record<string, string>)[prefix];\n if (ns) return `${ns}${input.slice(colon + 1)}`;\n }\n return input;\n}\n\n/** Compact a full IRI back to a prefixed name when a known namespace matches. */\nexport function compactIri(iri: string): string {\n for (const [prefix, ns] of PREFIXES) {\n if (iri.startsWith(ns) && iri.length > ns.length) {\n return `${prefix}:${iri.slice(ns.length)}`;\n }\n }\n return iri;\n}\n","/**\n * The one asset that ships with the package and is read by path at runtime: the\n * SHACL shapes. They live under `shapes/graph/` at the package root, listed in\n * `files`, and are reached through the shared package-root walk, which holds\n * both in the source tree (`src/graph/core/`) and in the bundle (`dist/`).\n *\n * The frontmatter schema is no longer one of them. The `graph` page vocabulary\n * is proposal 0023's draft, imported by `src/graph/schema.ts` and inlined by the\n * build, so nothing under `schemas/` is read at run time and nothing under it\n * is published (proposal 0051 §4).\n */\nimport { join } from \"node:path\";\nimport { packageRoot } from \"../../shared/package-root.js\";\n\n/** Absolute path of the bundled SHACL shapes `manni graph check` defaults to. */\nexport function bundledShapesPath(moduleUrl: string): string {\n return join(packageRoot(moduleUrl), \"shapes\", \"graph\", \"shapes-1.0.0.ttl\");\n}\n","/**\n * Graph-level validation: run the published SHACL shapes over a built graph,\n * plus the two SKOS integrity checks core SHACL cannot express (broader\n * cycles, related⨯broaderTransitive disjointness). Every finding carries the\n * doc paths responsible, so writers get file names instead of bare IRIs.\n */\nimport { readFileSync } from \"node:fs\";\nimport { DataFactory, Parser, Store } from \"n3\";\nimport SHACLValidator from \"rdf-validate-shacl\";\nimport type { Term } from \"@rdfjs/types\";\nimport { errorMessage } from \"../../shared/errors.js\";\nimport type { Severity } from \"../../shared/severity.js\";\nimport { GraphError } from \"../types.js\";\nimport { compactIri } from \"./load.js\";\nimport { byCodeUnit } from \"./sort.js\";\nimport { NS } from \"./vocab.js\";\n\n/** SHACL's own scale, as `sh:severity` spells it. */\nexport type ShaclSeverity = \"violation\" | \"warning\" | \"info\";\n\nexport interface CheckFinding {\n /**\n * The family's scale (`src/shared/severity.ts`). SHACL's three levels map\n * onto it one for one — violation to error, warning to warning, info to\n * notice — and the source value stays in {@link shaclSeverity}, the way\n * a11y keeps axe's `impact` (proposal 0035, stress test 10).\n */\n severity: Severity;\n /** SHACL's own word for the same finding, kept for lookup. */\n shaclSeverity: ShaclSeverity;\n /** Human-readable description (IRIs compacted to prefixed names). */\n message: string;\n /** IRI of the node the finding is about. */\n focusNode: string;\n /** Predicate IRI involved, when the finding concerns one. */\n path?: string;\n /** graph:path of the docs responsible, sorted (empty when untraceable). */\n docs: string[];\n}\n\n/**\n * SHACL's scale onto the family's. The one place the translation happens, so\n * no caller re-derives it: a finding is built through {@link finding} and\n * carries both words from there on.\n */\nconst FAMILY_SEVERITY: Record<ShaclSeverity, Severity> = {\n violation: \"error\",\n warning: \"warning\",\n info: \"notice\",\n};\n\n/** A finding at `shaclSeverity`, carrying the family severity it maps to. */\nfunction finding(\n shaclSeverity: ShaclSeverity,\n rest: Omit<CheckFinding, \"severity\" | \"shaclSeverity\">,\n): CheckFinding {\n return { severity: FAMILY_SEVERITY[shaclSeverity], shaclSeverity, ...rest };\n}\n\nconst SEVERITY_RANK: Record<ShaclSeverity, number> = {\n violation: 0,\n warning: 1,\n info: 2,\n};\n\n/** Parse one or more shapes .ttl files into a single store. */\nexport function loadShapes(paths: string[]): Store {\n const store = new Store();\n for (const path of paths) {\n let text: string;\n try {\n text = readFileSync(path, \"utf8\");\n } catch {\n throw new GraphError(`Shapes file not found: ${path}`);\n }\n try {\n store.addQuads(new Parser({ format: \"text/turtle\" }).parse(text));\n } catch (e) {\n throw new GraphError(\n `Failed to parse shapes ${path}: ${errorMessage(e)}`,\n );\n }\n }\n return store;\n}\n\n/**\n * Trace a focus node back to the doc(s) responsible: its own graph:path,\n * the path of its fragment-stripped base (sections, provenance fragments),\n * or — for shared nodes like concepts and agents — the paths of docs that\n * point at it, up to two hops back. Sorted and deduplicated.\n */\nexport function blameDocs(store: Store, focus: string): string[] {\n const pathPred = DataFactory.namedNode(`${NS.graph}path`);\n const pathOf = (iri: string): string | undefined =>\n store.getQuads(DataFactory.namedNode(iri), pathPred, null, null)[0]?.object.value;\n\n const found = new Set<string>();\n const visited = new Set<string>();\n\n const walk = (iri: string, depth: number): void => {\n if (visited.has(iri)) return;\n visited.add(iri);\n\n const own = pathOf(iri);\n if (own !== undefined) {\n found.add(own);\n return;\n }\n const hash = iri.indexOf(\"#\");\n if (hash !== -1) {\n const base = pathOf(iri.slice(0, hash));\n if (base !== undefined) {\n found.add(base);\n return;\n }\n }\n if (depth === 0) return;\n for (const quad of store.getQuads(null, null, DataFactory.namedNode(iri), null)) {\n if (quad.subject.termType === \"NamedNode\") {\n walk(quad.subject.value, depth - 1);\n }\n }\n };\n\n walk(focus, 2);\n return [...found].sort();\n}\n\ninterface Edge {\n s: string;\n o: string;\n}\n\n/** skos:broader edges, folding narrower in as its inverse. */\nfunction broaderEdges(store: Store): Edge[] {\n const edges: Edge[] = [];\n for (const q of store.getQuads(\n null,\n DataFactory.namedNode(`${NS.skos}broader`),\n null,\n null,\n )) {\n if (q.object.termType === \"NamedNode\") {\n edges.push({ s: q.subject.value, o: q.object.value });\n }\n }\n for (const q of store.getQuads(\n null,\n DataFactory.namedNode(`${NS.skos}narrower`),\n null,\n null,\n )) {\n if (q.object.termType === \"NamedNode\") {\n edges.push({ s: q.object.value, o: q.subject.value });\n }\n }\n return edges;\n}\n\n/**\n * Strongly connected components of the broader graph (iterative Tarjan —\n * no recursion, taxonomy depth can't blow the stack). Returns only real\n * cycles: components of 2+ nodes, or single nodes with a self-loop.\n */\nexport function broaderCycles(store: Store): string[][] {\n const adjacency = new Map<string, string[]>();\n const selfLoops = new Set<string>();\n for (const { s, o } of broaderEdges(store)) {\n if (s === o) selfLoops.add(s);\n const list = adjacency.get(s);\n if (list) list.push(o);\n else adjacency.set(s, [o]);\n if (!adjacency.has(o)) adjacency.set(o, []);\n }\n for (const list of adjacency.values()) list.sort();\n\n const index = new Map<string, number>();\n const lowlink = new Map<string, number>();\n const onStack = new Set<string>();\n const stack: string[] = [];\n const components: string[][] = [];\n let counter = 0;\n\n /**\n * A node's Tarjan number. Every node is stamped into both maps on the frame\n * where `childIdx === 0`, before any edge out of it is followed, so a miss\n * here is not a missing value but a broken traversal — which is worth\n * saying rather than reading as `NaN` three lines later.\n */\n const numberOf = (map: Map<string, number>, node: string): number => {\n const value = map.get(node);\n if (value === undefined) {\n throw new GraphError(\n `internal: ${node} was visited before it was numbered`,\n );\n }\n return value;\n };\n\n const nodes = [...adjacency.keys()].sort();\n for (const root of nodes) {\n if (index.has(root)) continue;\n // Explicit work stack of [node, next-child-index] frames. The loop reads\n // the top frame as its condition, so the frame is proven present by the\n // same test that keeps the loop running.\n const frames: Array<[string, number]> = [[root, 0]];\n for (let frame = frames.at(-1); frame !== undefined; frame = frames.at(-1)) {\n const [node, childIdx] = frame;\n if (childIdx === 0) {\n index.set(node, counter);\n lowlink.set(node, counter);\n counter += 1;\n stack.push(node);\n onStack.add(node);\n }\n const children = adjacency.get(node) ?? [];\n // Reading the child *is* the bounds check: `adjacency` holds dense\n // arrays of strings, so a hit is a child and a miss is the end of them.\n const child = children[childIdx];\n if (child !== undefined) {\n frame[1] += 1;\n if (!index.has(child)) {\n frames.push([child, 0]);\n } else if (onStack.has(child)) {\n lowlink.set(\n node,\n Math.min(numberOf(lowlink, node), numberOf(index, child)),\n );\n }\n } else {\n if (lowlink.get(node) === index.get(node)) {\n const component: string[] = [];\n let member: string | undefined;\n do {\n member = stack.pop();\n if (member === undefined) break;\n onStack.delete(member);\n component.push(member);\n } while (member !== node);\n if (component.length > 1 || selfLoops.has(node)) {\n components.push(component.sort());\n }\n }\n frames.pop();\n const parent = frames.at(-1);\n if (parent) {\n lowlink.set(\n parent[0],\n Math.min(numberOf(lowlink, parent[0]), numberOf(lowlink, node)),\n );\n }\n }\n }\n }\n // A component always has a member — it is built by popping at least one —\n // so `?? \"\"` is a spelling of that, not a fallback anyone can reach.\n return components.sort((a, b) => ((a[0] ?? \"\") < (b[0] ?? \"\") ? -1 : 1));\n}\n\n/** Forward reachability over broader edges from each given start node. */\nfunction broaderClosure(edges: Edge[], start: string): Set<string> {\n const adjacency = new Map<string, string[]>();\n for (const { s, o } of edges) {\n const list = adjacency.get(s);\n if (list) list.push(o);\n else adjacency.set(s, [o]);\n }\n const seen = new Set<string>();\n const queue = [...(adjacency.get(start) ?? [])];\n // Shifting *is* the emptiness test, so the queue is never read past its end.\n for (let node = queue.shift(); node !== undefined; node = queue.shift()) {\n if (seen.has(node)) continue;\n seen.add(node);\n queue.push(...(adjacency.get(node) ?? []));\n }\n return seen;\n}\n\n/**\n * SKOS S27: skos:related is disjoint with skos:broaderTransitive. The\n * one-hop case is already a SHACL sh:disjoint violation — skip it here so\n * one mistake doesn't produce two findings.\n */\nfunction relatedConflicts(store: Store): CheckFinding[] {\n const edges = broaderEdges(store);\n // Direct edges indexed by subject — no composite string keys (a joined\n // key would need a separator character, and IRIs make any choice fragile).\n const direct = new Map<string, Set<string>>();\n for (const e of edges) {\n const targets = direct.get(e.s);\n if (targets) targets.add(e.o);\n else direct.set(e.s, new Set([e.o]));\n }\n const findings: CheckFinding[] = [];\n for (const q of store.getQuads(\n null,\n DataFactory.namedNode(`${NS.skos}related`),\n null,\n null,\n )) {\n if (q.object.termType !== \"NamedNode\") continue;\n const s = q.subject.value;\n const o = q.object.value;\n if (direct.get(s)?.has(o)) continue; // covered by sh:disjoint\n const conflict =\n broaderClosure(edges, s).has(o) || broaderClosure(edges, o).has(s);\n if (!conflict) continue;\n findings.push(\n finding(\"violation\", {\n message: `skos:related conflicts with skos:broaderTransitive between ${compactIri(s)} and ${compactIri(o)} — a concept cannot be both related to and an ancestor/descendant of another`,\n focusNode: s,\n path: `${NS.skos}related`,\n docs: blameDocs(store, s),\n }),\n );\n }\n return findings;\n}\n\nfunction cycleFindings(store: Store): CheckFinding[] {\n return broaderCycles(store).map((members) =>\n finding(\"violation\", {\n message: `skos:broader cycle through ${members\n .map((m) => compactIri(m))\n .join(\n \", \",\n )} (${members.map((m) => m).join(\" → \")}) — a concept cannot be its own ancestor`,\n // `broaderCycles` returns only components of at least one member, so\n // the first is there; `?? \"\"` says that without asserting it.\n focusNode: members[0] ?? \"\",\n path: `${NS.skos}broader`,\n docs: [...new Set(members.flatMap((m) => blameDocs(store, m)))].sort(),\n }),\n );\n}\n\n/**\n * The three `graph` fields a machine may never be attributed for. The old\n * `kg.provenance` schema enumerated the twelve *fillable* fields, which kept\n * these out; a free JSON Pointer cannot express that, so proposal 0046 stress\n * test 13 moved the guard into graph's harvest and, from there, to here.\n */\nconst CURATED_FIELDS = new Set([\"sections\", \"revision-of\", \"derived-from\"]);\n\n/** The fragment a `graph fill` activity's IRI carries, before its model slug. */\nconst GRAPH_FILL_FRAGMENT = \"#prov.graph-fill.\";\n\n/**\n * A machine attribution on a hand-curated field. `check` reads only the built\n * graph and `build` has no findings channel, so the store is where the fact is\n * read: the harvest has already put `graph:filledField \"sections\"` on a field\n * node under a `#prov.graph-fill.` activity.\n */\nfunction curatedFieldFindings(store: Store): CheckFinding[] {\n const filledField = `${NS.graph}filledField`;\n const pathPred = DataFactory.namedNode(`${NS.graph}path`);\n const findings: CheckFinding[] = [];\n for (const q of store.getQuads(null, DataFactory.namedNode(filledField), null, null)) {\n if (q.object.termType !== \"Literal\") continue;\n const field = q.object.value;\n if (!CURATED_FIELDS.has(field)) continue;\n const node = q.subject.value;\n const at = node.indexOf(GRAPH_FILL_FRAGMENT);\n const fieldAt = node.lastIndexOf(\".field.\");\n if (at === -1 || fieldAt <= at) continue;\n const activity = node.slice(0, fieldAt);\n // The model the activity is for, from its own fragment. Naming it beats\n // repeating the activity IRI, which the reporter already prints as the\n // focus node ahead of this message.\n const model = node.slice(at + GRAPH_FILL_FRAGMENT.length, fieldAt);\n // These activities hang off no document edge, so `blameDocs` cannot walk\n // back to one. The doc IRI is the activity's own, minus its fragment.\n const docIri = activity.slice(0, activity.indexOf(\"#\"));\n const path = store.getQuads(DataFactory.namedNode(docIri), pathPred, null, null)[0]\n ?.object.value;\n findings.push(\n finding(\"violation\", {\n message: `meta-provenance attributes /graph/${field} to ${model} — ${field} is curated by hand, never filled by a machine`,\n focusNode: activity,\n path: filledField,\n docs: path === undefined ? blameDocs(store, activity) : [path],\n }),\n );\n }\n return findings;\n}\n\n/**\n * One validation result, with the nullability its library documents in code\n * rather than in its `.d.ts`.\n *\n * `rdf-validate-shacl` declares `path`, `focusNode` and `severity` as `Term`,\n * and every one of them is `…out(ns.sh.resultPath).term || null` at runtime. A\n * result with no path is ordinary — a node-shape constraint has none — so the\n * guards at the read site are the real contract and the declaration is the\n * optimistic one. Saying so once here is what keeps them from reading as\n * checks that cannot fail.\n */\ninterface ShaclResult {\n message: Term[];\n path: Term | null;\n focusNode: Term | null;\n severity: Term | null;\n}\n\nfunction severityOf(iri: string | undefined): ShaclSeverity {\n if (iri === \"http://www.w3.org/ns/shacl#Warning\") return \"warning\";\n if (iri === \"http://www.w3.org/ns/shacl#Info\") return \"info\";\n return \"violation\";\n}\n\n/**\n * Validate a built graph against SHACL shapes files, merge in the TS-side\n * SKOS checks, and return deterministic, doc-blamed findings.\n */\nexport async function validateGraph(\n store: Store,\n shapesPaths: string[],\n): Promise<CheckFinding[]> {\n const shapes = loadShapes(shapesPaths);\n const validator = new SHACLValidator(shapes);\n let report;\n try {\n report = await validator.validate(store);\n } catch (e) {\n throw new GraphError(\n `SHACL validation failed: ${errorMessage(e)}`,\n );\n }\n\n const findings: CheckFinding[] = [];\n for (const result of report.results as ShaclResult[]) {\n const focus = result.focusNode?.value ?? \"\";\n const path = result.path?.value;\n const messages = result.message\n .map((m) => m.value)\n .filter((m) => m.length > 0);\n const message =\n messages.length > 0\n ? messages.join(\"; \")\n : `constraint violated${path ? ` on ${compactIri(path)}` : \"\"}`;\n findings.push(\n finding(severityOf(result.severity?.value), {\n message,\n focusNode: focus,\n ...(path !== undefined ? { path } : {}),\n docs: blameDocs(store, focus),\n }),\n );\n }\n\n findings.push(\n ...cycleFindings(store),\n ...relatedConflicts(store),\n ...curatedFieldFindings(store),\n );\n\n findings.sort(\n (a, b) =>\n SEVERITY_RANK[a.shaclSeverity] - SEVERITY_RANK[b.shaclSeverity] ||\n byCodeUnit(a.focusNode, b.focusNode) ||\n byCodeUnit(a.path ?? \"\", b.path ?? \"\") ||\n byCodeUnit(a.message, b.message),\n );\n return findings;\n}\n"],"mappings":"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","names":["readFileSync","Parser","Store","Store","readFileSync","Parser"]}