@hawkeyexl/manni 4.3.0 → 4.4.0
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.
- package/README.md +9 -1
- package/dist/batch-DFRCLY77.js +36 -0
- package/dist/build-Q5C6SX5J.js +31 -0
- package/dist/calibrate-XQILKXS3.js +31 -0
- package/dist/capture-JQMOC3BW.js +32 -0
- package/dist/check-HYNGXYJV.js +18 -0
- package/dist/check-HYNGXYJV.js.map +1 -0
- package/dist/check-NFZQLJKN.js +27 -0
- package/dist/check-NFZQLJKN.js.map +1 -0
- package/dist/check-U54XV6BP.js +40 -0
- package/dist/check-U54XV6BP.js.map +1 -0
- package/dist/chunk-252LNOEG.js +622 -0
- package/dist/chunk-252LNOEG.js.map +1 -0
- package/dist/chunk-2H7UOFLK.js +11 -0
- package/dist/chunk-2H7UOFLK.js.map +1 -0
- package/dist/chunk-2U3ORT6D.js +230 -0
- package/dist/chunk-2U3ORT6D.js.map +1 -0
- package/dist/chunk-3AFUD75K.js +23 -0
- package/dist/chunk-3AFUD75K.js.map +1 -0
- package/dist/{chunk-3R23C5DT.js → chunk-4TSWU2SU.js} +2 -14
- package/dist/chunk-4TSWU2SU.js.map +1 -0
- package/dist/chunk-5KHIFVD2.js +1192 -0
- package/dist/chunk-5KHIFVD2.js.map +1 -0
- package/dist/chunk-5YXBLLAC.js +2165 -0
- package/dist/chunk-5YXBLLAC.js.map +1 -0
- package/dist/chunk-644JVKJ4.js +3872 -0
- package/dist/chunk-644JVKJ4.js.map +1 -0
- package/dist/chunk-6OYEI2VV.js +88 -0
- package/dist/chunk-6OYEI2VV.js.map +1 -0
- package/dist/chunk-77AINBYM.js +19 -0
- package/dist/chunk-77AINBYM.js.map +1 -0
- package/dist/chunk-77HX34KD.js +1287 -0
- package/dist/chunk-77HX34KD.js.map +1 -0
- package/dist/{chunk-MOQXWXSG.js → chunk-7QMCHA4N.js} +32 -240
- package/dist/chunk-7QMCHA4N.js.map +1 -0
- package/dist/chunk-BUXDLRDT.js +455 -0
- package/dist/chunk-BUXDLRDT.js.map +1 -0
- package/dist/chunk-C6OH6CNF.js +388 -0
- package/dist/chunk-C6OH6CNF.js.map +1 -0
- package/dist/chunk-CK7SKVHR.js +1042 -0
- package/dist/chunk-CK7SKVHR.js.map +1 -0
- package/dist/chunk-CYWHFSRT.js +6737 -0
- package/dist/chunk-CYWHFSRT.js.map +1 -0
- package/dist/chunk-ERMSO34F.js +17 -0
- package/dist/chunk-ERMSO34F.js.map +1 -0
- package/dist/{chunk-IOYXPBCL.js → chunk-G3T47CFV.js} +1 -7
- package/dist/{chunk-IOYXPBCL.js.map → chunk-G3T47CFV.js.map} +1 -1
- package/dist/chunk-G7NJSREW.js +979 -0
- package/dist/chunk-G7NJSREW.js.map +1 -0
- package/dist/chunk-GLP5PSXB.js +72 -0
- package/dist/chunk-GLP5PSXB.js.map +1 -0
- package/dist/chunk-H2DLH2JI.js +198 -0
- package/dist/chunk-H2DLH2JI.js.map +1 -0
- package/dist/chunk-H6FZ66XR.js +634 -0
- package/dist/chunk-H6FZ66XR.js.map +1 -0
- package/dist/{chunk-CI2GOU3A.js → chunk-IEQHSCZG.js} +56 -137
- package/dist/chunk-IEQHSCZG.js.map +1 -0
- package/dist/chunk-IKEWBMCN.js +98 -0
- package/dist/chunk-IKEWBMCN.js.map +1 -0
- package/dist/chunk-JOHKIAVH.js +5440 -0
- package/dist/chunk-JOHKIAVH.js.map +1 -0
- package/dist/chunk-JVTNMVYU.js +10921 -0
- package/dist/chunk-JVTNMVYU.js.map +1 -0
- package/dist/chunk-K3D6FPV6.js +164 -0
- package/dist/chunk-K3D6FPV6.js.map +1 -0
- package/dist/{chunk-MFDD3YGU.js → chunk-KCGV52AM.js} +69 -48
- package/dist/{chunk-MFDD3YGU.js.map → chunk-KCGV52AM.js.map} +1 -1
- package/dist/chunk-LAKAWRV5.js +1651 -0
- package/dist/chunk-LAKAWRV5.js.map +1 -0
- package/dist/chunk-LJ2RDH3F.js +49 -0
- package/dist/chunk-LJ2RDH3F.js.map +1 -0
- package/dist/chunk-M2JCK5F6.js +805 -0
- package/dist/chunk-M2JCK5F6.js.map +1 -0
- package/dist/chunk-MNH7QO4Z.js +15 -0
- package/dist/chunk-MNH7QO4Z.js.map +1 -0
- package/dist/{chunk-RVVCA4WL.js → chunk-MYC3O5EJ.js} +4 -4
- package/dist/chunk-MYMBCTDE.js +387 -0
- package/dist/chunk-MYMBCTDE.js.map +1 -0
- package/dist/chunk-NCPWXHDO.js +683 -0
- package/dist/chunk-NCPWXHDO.js.map +1 -0
- package/dist/chunk-NWZ2SLYL.js +2957 -0
- package/dist/chunk-NWZ2SLYL.js.map +1 -0
- package/dist/chunk-OBFENF3U.js +934 -0
- package/dist/chunk-OBFENF3U.js.map +1 -0
- package/dist/chunk-OWBRDNRZ.js +16 -0
- package/dist/chunk-OWBRDNRZ.js.map +1 -0
- package/dist/{chunk-KTSJ2ZHA.js → chunk-PAU352SV.js} +5 -3
- package/dist/{chunk-KTSJ2ZHA.js.map → chunk-PAU352SV.js.map} +1 -1
- package/dist/chunk-PCE7QHXJ.js +68 -0
- package/dist/chunk-PCE7QHXJ.js.map +1 -0
- package/dist/chunk-PCHZY2I7.js +299 -0
- package/dist/chunk-PCHZY2I7.js.map +1 -0
- package/dist/chunk-PHF3D7ER.js +1042 -0
- package/dist/chunk-PHF3D7ER.js.map +1 -0
- package/dist/chunk-Q35YIDBV.js +1202 -0
- package/dist/chunk-Q35YIDBV.js.map +1 -0
- package/dist/chunk-RLR4TKUZ.js +4398 -0
- package/dist/chunk-RLR4TKUZ.js.map +1 -0
- package/dist/chunk-RNVYGWIC.js +30 -0
- package/dist/chunk-RNVYGWIC.js.map +1 -0
- package/dist/chunk-SE4JN5XN.js +19 -0
- package/dist/chunk-SE4JN5XN.js.map +1 -0
- package/dist/chunk-TIUTIOFB.js +25 -0
- package/dist/chunk-TIUTIOFB.js.map +1 -0
- package/dist/chunk-TU2WUBVZ.js +2 -0
- package/dist/chunk-TU2WUBVZ.js.map +1 -0
- package/dist/chunk-TZOYZK2E.js +98 -0
- package/dist/chunk-TZOYZK2E.js.map +1 -0
- package/dist/chunk-UKZNLVJW.js +17 -0
- package/dist/chunk-UKZNLVJW.js.map +1 -0
- package/dist/chunk-UZC7LDAQ.js +178 -0
- package/dist/chunk-UZC7LDAQ.js.map +1 -0
- package/dist/chunk-V46OILVC.js +3090 -0
- package/dist/chunk-V46OILVC.js.map +1 -0
- package/dist/chunk-WQE54PNH.js +1975 -0
- package/dist/chunk-WQE54PNH.js.map +1 -0
- package/dist/chunk-X3BPBDGQ.js +52 -0
- package/dist/chunk-X3BPBDGQ.js.map +1 -0
- package/dist/chunk-XSLV76YK.js +54 -0
- package/dist/chunk-XSLV76YK.js.map +1 -0
- package/dist/{chunk-QROCFW5S.js → chunk-XYLUCIKQ.js} +3 -3
- package/dist/chunk-YEUYKR62.js +72 -0
- package/dist/chunk-YEUYKR62.js.map +1 -0
- package/dist/{chunk-ESJ5W7EV.js → chunk-YFQBFNQS.js} +8 -94
- package/dist/chunk-YFQBFNQS.js.map +1 -0
- package/dist/chunk-YIL4XLLJ.js +1661 -0
- package/dist/chunk-YIL4XLLJ.js.map +1 -0
- package/dist/chunk-YNHZHSSM.js +41 -0
- package/dist/chunk-YNHZHSSM.js.map +1 -0
- package/dist/chunk-YTCZRLTU.js +96 -0
- package/dist/chunk-YTCZRLTU.js.map +1 -0
- package/dist/chunk-YYBFZLAJ.js +374 -0
- package/dist/chunk-YYBFZLAJ.js.map +1 -0
- package/dist/chunk-ZXRAE55H.js +31 -0
- package/dist/chunk-ZXRAE55H.js.map +1 -0
- package/dist/cli-2QPR2OZG.js +232 -0
- package/dist/cli-2QPR2OZG.js.map +1 -0
- package/dist/cli-4IOPGZHR.js +1203 -0
- package/dist/cli-4IOPGZHR.js.map +1 -0
- package/dist/cli-5FL73WHA.js +346 -0
- package/dist/cli-5FL73WHA.js.map +1 -0
- package/dist/cli-C262QOWM.js +739 -0
- package/dist/cli-C262QOWM.js.map +1 -0
- package/dist/cli-LJLLIQB2.js +423 -0
- package/dist/cli-LJLLIQB2.js.map +1 -0
- package/dist/cli-OFPZ5MAS.js +626 -0
- package/dist/cli-OFPZ5MAS.js.map +1 -0
- package/dist/cli-SHSMSRQY.js +28 -0
- package/dist/cli-SHSMSRQY.js.map +1 -0
- package/dist/cli-SRHFUZHA.js +473 -0
- package/dist/cli-SRHFUZHA.js.map +1 -0
- package/dist/cli-URZQXL4K.js +552 -0
- package/dist/cli-URZQXL4K.js.map +1 -0
- package/dist/cli.d.ts +12 -2
- package/dist/cli.js +109 -7651
- package/dist/cli.js.map +1 -1
- package/dist/docmeta.js +15 -3
- package/dist/docmeta.js.map +1 -1
- package/dist/github-FE6KCNYJ.js +27 -0
- package/dist/github-FE6KCNYJ.js.map +1 -0
- package/dist/github-QXL3VMK2.js +32 -0
- package/dist/github-QXL3VMK2.js.map +1 -0
- package/dist/index.d.ts +65 -3
- package/dist/index.js +407 -337
- package/dist/index.js.map +1 -1
- package/dist/json-7WV7KL6H.js +17 -0
- package/dist/json-7WV7KL6H.js.map +1 -0
- package/dist/json-SGZ6ZRFD.js +35 -0
- package/dist/json-SGZ6ZRFD.js.map +1 -0
- package/dist/lint-DL4LJRAY.js +28 -0
- package/dist/lint-DL4LJRAY.js.map +1 -0
- package/dist/list-6BAXTZUM.js +29 -0
- package/dist/list-6BAXTZUM.js.map +1 -0
- package/dist/list-7BKNYPSB.js +31 -0
- package/dist/list-7BKNYPSB.js.map +1 -0
- package/dist/page-3U2GCFNE.js +41 -0
- package/dist/page-3U2GCFNE.js.map +1 -0
- package/dist/picker-3XF36MJF.js +14 -0
- package/dist/picker-3XF36MJF.js.map +1 -0
- package/dist/pretty-2H57QVTY.js +43 -0
- package/dist/pretty-2H57QVTY.js.map +1 -0
- package/dist/pretty-N6DO4OOL.js +37 -0
- package/dist/pretty-N6DO4OOL.js.map +1 -0
- package/dist/reporters-M6LJ2IYU.js +21 -0
- package/dist/reporters-M6LJ2IYU.js.map +1 -0
- package/dist/reporters-N6GHXSS7.js +42 -0
- package/dist/reporters-N6GHXSS7.js.map +1 -0
- package/dist/reporters-UCNEV7PH.js +71 -0
- package/dist/reporters-UCNEV7PH.js.map +1 -0
- package/dist/run-XZDAREJE.js +33 -0
- package/dist/run-XZDAREJE.js.map +1 -0
- package/dist/term-5ICGKPC3.js +1592 -0
- package/dist/term-5ICGKPC3.js.map +1 -0
- package/dist/types-Y6TXHM7M.js +10 -0
- package/dist/types-Y6TXHM7M.js.map +1 -0
- package/dist/validate-GQRM77YN.js +16 -0
- package/dist/validate-GQRM77YN.js.map +1 -0
- package/package.json +1 -1
- package/plugin/manni/.claude-plugin/plugin.json +9 -0
- package/plugin/manni/hooks/hooks.json +52 -0
- package/plugin/manni/skills/check/SKILL.md +20 -0
- package/plugin/manni/skills/evals/SKILL.md +27 -0
- package/plugin/manni/skills/fix/SKILL.md +56 -0
- package/plugin/manni/skills/setup/SKILL.md +41 -0
- package/dist/batch-7JJWXWSF.js +0 -18
- package/dist/calibrate-IA2ARFMH.js +0 -13
- package/dist/capture-C32JXIFN.js +0 -15
- package/dist/chunk-3R23C5DT.js.map +0 -1
- package/dist/chunk-CI2GOU3A.js.map +0 -1
- package/dist/chunk-DP2ZA3WH.js +0 -26518
- package/dist/chunk-DP2ZA3WH.js.map +0 -1
- package/dist/chunk-ESJ5W7EV.js.map +0 -1
- package/dist/chunk-MOQXWXSG.js.map +0 -1
- package/dist/chunk-O6RVQKK6.js +0 -27170
- package/dist/chunk-O6RVQKK6.js.map +0 -1
- package/dist/picker-6HRMETE7.js +0 -12
- package/plugin/tracevals/.claude-plugin/plugin.json +0 -9
- package/plugin/tracevals/hooks/hooks.json +0 -17
- /package/dist/{batch-7JJWXWSF.js.map → batch-DFRCLY77.js.map} +0 -0
- /package/dist/{calibrate-IA2ARFMH.js.map → build-Q5C6SX5J.js.map} +0 -0
- /package/dist/{capture-C32JXIFN.js.map → calibrate-XQILKXS3.js.map} +0 -0
- /package/dist/{picker-6HRMETE7.js.map → capture-JQMOC3BW.js.map} +0 -0
- /package/dist/{chunk-RVVCA4WL.js.map → chunk-MYC3O5EJ.js.map} +0 -0
- /package/dist/{chunk-QROCFW5S.js.map → chunk-XYLUCIKQ.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,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/shared/program-name.ts
|
|
4
|
+
var name = "manni";
|
|
5
|
+
function programName() {
|
|
6
|
+
return name;
|
|
7
|
+
}
|
|
8
|
+
function setProgramName(value) {
|
|
9
|
+
name = value;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
programName,
|
|
14
|
+
setProgramName
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=chunk-OWBRDNRZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared/program-name.ts"],"sourcesContent":["/**\n * The name the running bin was invoked as, for stderr prefixes.\n *\n * One package ships two bins: `manni`, and `docmeta` for the scripts written\n * before the rename. A diagnostic should name the command the user typed, so\n * the prefix is settled once by whichever entry point ran (`runProgram`) and\n * read by whoever writes to stderr. Library callers never set it, and get the\n * primary bin's name.\n */\nlet name = \"manni\";\n\nexport function programName(): string {\n return name;\n}\n\nexport function setProgramName(value: string): void {\n name = value;\n}\n"],"mappings":";;;AASA,IAAI,OAAO;AAEJ,SAAS,cAAsB;AACpC,SAAO;AACT;AAEO,SAAS,eAAe,OAAqB;AAClD,SAAO;AACT;","names":[]}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
TracevalsError,
|
|
4
3
|
discoverTraces
|
|
5
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-4TSWU2SU.js";
|
|
5
|
+
import {
|
|
6
|
+
TracevalsError
|
|
7
|
+
} from "./chunk-UKZNLVJW.js";
|
|
6
8
|
|
|
7
9
|
// src/tracevals/trace/picker.ts
|
|
8
10
|
async function inquirerPrompt(params) {
|
|
@@ -37,4 +39,4 @@ export {
|
|
|
37
39
|
choiceFor,
|
|
38
40
|
pickTrace
|
|
39
41
|
};
|
|
40
|
-
//# sourceMappingURL=chunk-
|
|
42
|
+
//# sourceMappingURL=chunk-PAU352SV.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/tracevals/trace/picker.ts"],"sourcesContent":["/**\n * Interactive trace picker (TTY only). The prompt function is injectable so\n * tests never touch a real terminal.\n */\nimport { TracevalsError } from \"../types.js\";\nimport {\n discoverTraces,\n type DiscoverOptions,\n type TraceListing,\n} from \"./discover.js\";\n\nexport interface PickerChoice {\n name: string;\n value: string;\n description?: string;\n}\n\nexport type PromptFn = (params: {\n message: string;\n choices: PickerChoice[];\n}) => Promise<string>;\n\nasync function inquirerPrompt(params: {\n message: string;\n choices: PickerChoice[];\n}): Promise<string> {\n const { select } = await import(\"@inquirer/prompts\");\n return select<string>(params);\n}\n\nexport function choiceFor(listing: TraceListing): PickerChoice {\n const when = new Date(listing.mtimeMs)\n .toISOString()\n .slice(0, 16)\n .replace(\"T\", \" \");\n return {\n name: `${when} ${listing.firstPrompt ?? \"(no prompt)\"}`,\n value: listing.file,\n description: `${listing.project ?? \"unknown project\"} · ${listing.sessionId ?? \"?\"}`,\n };\n}\n\nexport async function pickTrace(\n options: DiscoverOptions = {},\n prompt: PromptFn = inquirerPrompt,\n): Promise<string> {\n let listings = await discoverTraces({ limit: 25, ...options });\n if (listings.length === 0 && !options.allProjects) {\n // Nothing for this project — offer everything rather than a dead end.\n listings = await discoverTraces({ limit: 25, ...options, allProjects: true });\n }\n if (listings.length === 0) {\n throw new TracevalsError(\n \"no traces found in the session store; pass a trace file instead\",\n );\n }\n return prompt({\n message: \"Pick a trace to evaluate\",\n choices: listings.map(choiceFor),\n });\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../src/tracevals/trace/picker.ts"],"sourcesContent":["/**\n * Interactive trace picker (TTY only). The prompt function is injectable so\n * tests never touch a real terminal.\n */\nimport { TracevalsError } from \"../types.js\";\nimport {\n discoverTraces,\n type DiscoverOptions,\n type TraceListing,\n} from \"./discover.js\";\n\nexport interface PickerChoice {\n name: string;\n value: string;\n description?: string;\n}\n\nexport type PromptFn = (params: {\n message: string;\n choices: PickerChoice[];\n}) => Promise<string>;\n\nasync function inquirerPrompt(params: {\n message: string;\n choices: PickerChoice[];\n}): Promise<string> {\n const { select } = await import(\"@inquirer/prompts\");\n return select<string>(params);\n}\n\nexport function choiceFor(listing: TraceListing): PickerChoice {\n const when = new Date(listing.mtimeMs)\n .toISOString()\n .slice(0, 16)\n .replace(\"T\", \" \");\n return {\n name: `${when} ${listing.firstPrompt ?? \"(no prompt)\"}`,\n value: listing.file,\n description: `${listing.project ?? \"unknown project\"} · ${listing.sessionId ?? \"?\"}`,\n };\n}\n\nexport async function pickTrace(\n options: DiscoverOptions = {},\n prompt: PromptFn = inquirerPrompt,\n): Promise<string> {\n let listings = await discoverTraces({ limit: 25, ...options });\n if (listings.length === 0 && !options.allProjects) {\n // Nothing for this project — offer everything rather than a dead end.\n listings = await discoverTraces({ limit: 25, ...options, allProjects: true });\n }\n if (listings.length === 0) {\n throw new TracevalsError(\n \"no traces found in the session store; pass a trace file instead\",\n );\n }\n return prompt({\n message: \"Pick a trace to evaluate\",\n choices: listings.map(choiceFor),\n });\n}\n"],"mappings":";;;;;;;;;AAsBA,eAAe,eAAe,QAGV;AAClB,QAAM,EAAE,OAAO,IAAI,MAAM,OAAO,mBAAmB;AACnD,SAAO,OAAe,MAAM;AAC9B;AAEO,SAAS,UAAU,SAAqC;AAC7D,QAAM,OAAO,IAAI,KAAK,QAAQ,OAAO,EAClC,YAAY,EACZ,MAAM,GAAG,EAAE,EACX,QAAQ,KAAK,GAAG;AACnB,SAAO;AAAA,IACL,MAAM,GAAG,IAAI,KAAK,QAAQ,eAAe,aAAa;AAAA,IACtD,OAAO,QAAQ;AAAA,IACf,aAAa,GAAG,QAAQ,WAAW,iBAAiB,SAAM,QAAQ,aAAa,GAAG;AAAA,EACpF;AACF;AAEA,eAAsB,UACpB,UAA2B,CAAC,GAC5B,SAAmB,gBACF;AACjB,MAAI,WAAW,MAAM,eAAe,EAAE,OAAO,IAAI,GAAG,QAAQ,CAAC;AAC7D,MAAI,SAAS,WAAW,KAAK,CAAC,QAAQ,aAAa;AAEjD,eAAW,MAAM,eAAe,EAAE,OAAO,IAAI,GAAG,SAAS,aAAa,KAAK,CAAC;AAAA,EAC9E;AACA,MAAI,SAAS,WAAW,GAAG;AACzB,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO,OAAO;AAAA,IACZ,SAAS;AAAA,IACT,SAAS,SAAS,IAAI,SAAS;AAAA,EACjC,CAAC;AACH;","names":[]}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cite/reporters/json.ts
|
|
4
|
+
function publicCitation(result) {
|
|
5
|
+
const origin = {
|
|
6
|
+
kind: result.origin.kind,
|
|
7
|
+
file: result.origin.file
|
|
8
|
+
};
|
|
9
|
+
if (result.origin.line !== void 0) origin.line = result.origin.line;
|
|
10
|
+
const source = { src: result.source.src, status: result.source.status };
|
|
11
|
+
if (result.source.newLines !== void 0) source.newLines = result.source.newLines;
|
|
12
|
+
if (result.source.newSrc !== void 0) source.newSrc = result.source.newSrc;
|
|
13
|
+
if (result.source.candidates !== void 0) source.candidates = result.source.candidates;
|
|
14
|
+
if (result.source.commitSha !== void 0) source.commitSha = result.source.commitSha;
|
|
15
|
+
if (result.source.historyAvailable !== void 0) {
|
|
16
|
+
source.historyAvailable = result.source.historyAvailable;
|
|
17
|
+
}
|
|
18
|
+
if (result.source.truncatedSearch !== void 0) {
|
|
19
|
+
source.truncatedSearch = result.source.truncatedSearch;
|
|
20
|
+
}
|
|
21
|
+
let claim = null;
|
|
22
|
+
if (result.claim !== null) {
|
|
23
|
+
claim = { status: result.claim.status };
|
|
24
|
+
if (result.claim.lines !== void 0) claim.lines = result.claim.lines;
|
|
25
|
+
if (result.claim.fileLines !== void 0) claim.fileLines = result.claim.fileLines;
|
|
26
|
+
if (result.claim.newLines !== void 0) claim.newLines = result.claim.newLines;
|
|
27
|
+
if (result.claim.candidates !== void 0) claim.candidates = result.claim.candidates;
|
|
28
|
+
if (result.claim.commitSha !== void 0) claim.commitSha = result.claim.commitSha;
|
|
29
|
+
if (result.claim.historyAvailable !== void 0) {
|
|
30
|
+
claim.historyAvailable = result.claim.historyAvailable;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
...result.citation.id === void 0 ? {} : { id: result.citation.id },
|
|
35
|
+
origin,
|
|
36
|
+
anchor: result.anchor,
|
|
37
|
+
...result.marker === void 0 ? {} : { marker: result.marker },
|
|
38
|
+
claim,
|
|
39
|
+
source
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function publicPage(page) {
|
|
43
|
+
return { ...page, citations: page.citations.map(publicCitation) };
|
|
44
|
+
}
|
|
45
|
+
function renderCheckJson(run) {
|
|
46
|
+
return JSON.stringify({ summary: run.summary, pages: run.pages.map(publicPage) }, null, 2);
|
|
47
|
+
}
|
|
48
|
+
function renderRemoveJson(run) {
|
|
49
|
+
return JSON.stringify(run, null, 2);
|
|
50
|
+
}
|
|
51
|
+
function renderUpdateJson(run) {
|
|
52
|
+
const strip = (rows) => rows.map(({ markerLine: _pretty, ...rewrite }) => rewrite);
|
|
53
|
+
const pages = run.pages.map((page) => ({
|
|
54
|
+
...page,
|
|
55
|
+
rewritten: strip(page.rewritten),
|
|
56
|
+
refused: strip(page.refused)
|
|
57
|
+
}));
|
|
58
|
+
return JSON.stringify({ ...run, pages }, null, 2);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export {
|
|
62
|
+
publicCitation,
|
|
63
|
+
publicPage,
|
|
64
|
+
renderCheckJson,
|
|
65
|
+
renderRemoveJson,
|
|
66
|
+
renderUpdateJson
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=chunk-PCE7QHXJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cite/reporters/json.ts"],"sourcesContent":["/**\n * JSON output. `{ summary, pages }` for check; the run itself for update and\n * remove.\n *\n * A citation prints its two ends and how they are anchored. `resolvedPath`,\n * `diff`, `commitsSince` and a changed claim's current lines are left out of\n * every citation: output never says more than the page did. It is an\n * allowlist rather than a strip, so a field added to the result stays private\n * until someone decides here that it is safe to print.\n */\nimport type {\n CheckRun,\n CitationAnchor,\n CitationResult,\n MarkerEnd,\n OriginKind,\n PageCitationReport,\n RemoveRun,\n UpdateRewrite,\n UpdateRun,\n} from \"../types.js\";\n\nexport interface PublicClaimEnd {\n lines?: string;\n fileLines?: string;\n status: string;\n newLines?: string;\n candidates?: string[];\n /** The baseline the claim was read against: the page's own history says it. */\n commitSha?: string;\n historyAvailable?: boolean;\n}\n\nexport interface PublicSourceEnd {\n src: string;\n status: string;\n newLines?: string;\n newSrc?: string;\n candidates?: string[];\n commitSha?: string;\n historyAvailable?: boolean;\n truncatedSearch?: boolean;\n}\n\nexport interface PublicCitationResult {\n id?: string;\n origin: { kind: OriginKind; file: string; line?: number };\n anchor: CitationAnchor;\n /** The marker that names the entry: its line, and its misplacement when it has one. */\n marker?: MarkerEnd;\n claim: PublicClaimEnd | null;\n source: PublicSourceEnd;\n}\n\nexport function publicCitation(result: CitationResult): PublicCitationResult {\n const origin: PublicCitationResult[\"origin\"] = {\n kind: result.origin.kind,\n file: result.origin.file,\n };\n if (result.origin.line !== undefined) origin.line = result.origin.line;\n\n const source: PublicSourceEnd = { src: result.source.src, status: result.source.status };\n if (result.source.newLines !== undefined) source.newLines = result.source.newLines;\n if (result.source.newSrc !== undefined) source.newSrc = result.source.newSrc;\n if (result.source.candidates !== undefined) source.candidates = result.source.candidates;\n if (result.source.commitSha !== undefined) source.commitSha = result.source.commitSha;\n if (result.source.historyAvailable !== undefined) {\n source.historyAvailable = result.source.historyAvailable;\n }\n if (result.source.truncatedSearch !== undefined) {\n source.truncatedSearch = result.source.truncatedSearch;\n }\n\n let claim: PublicClaimEnd | null = null;\n if (result.claim !== null) {\n claim = { status: result.claim.status };\n if (result.claim.lines !== undefined) claim.lines = result.claim.lines;\n if (result.claim.fileLines !== undefined) claim.fileLines = result.claim.fileLines;\n if (result.claim.newLines !== undefined) claim.newLines = result.claim.newLines;\n if (result.claim.candidates !== undefined) claim.candidates = result.claim.candidates;\n if (result.claim.commitSha !== undefined) claim.commitSha = result.claim.commitSha;\n if (result.claim.historyAvailable !== undefined) {\n claim.historyAvailable = result.claim.historyAvailable;\n }\n }\n\n // Key order is the order the plan spells a citation in: what it is called,\n // where it is kept, what anchors it, then its two ends.\n return {\n ...(result.citation.id === undefined ? {} : { id: result.citation.id }),\n origin,\n anchor: result.anchor,\n ...(result.marker === undefined ? {} : { marker: result.marker }),\n claim,\n source,\n };\n}\n\nexport interface PublicPageReport extends Omit<PageCitationReport, \"citations\"> {\n citations: PublicCitationResult[];\n}\n\nexport function publicPage(page: PageCitationReport): PublicPageReport {\n return { ...page, citations: page.citations.map(publicCitation) };\n}\n\nexport function renderCheckJson(run: CheckRun): string {\n return JSON.stringify({ summary: run.summary, pages: run.pages.map(publicPage) }, null, 2);\n}\n\nexport function renderRemoveJson(run: RemoveRun): string {\n // The whole run, with nothing stripped: `RemoveRun` carries no\n // pretty-only field, as `UpdateRewrite.markerLine` is below. A field added\n // to it for the terminal alone is stripped here, as that one is.\n return JSON.stringify(run, null, 2);\n}\n\nexport function renderUpdateJson(run: UpdateRun): string {\n // `markerLine` is the pretty report's line for a marker-anchored claim.\n // `at` is the claim's own first file line, which is what data says.\n const strip = (rows: readonly UpdateRewrite[]): Omit<UpdateRewrite, \"markerLine\">[] =>\n rows.map(({ markerLine: _pretty, ...rewrite }) => rewrite);\n const pages = run.pages.map((page) => ({\n ...page,\n rewritten: strip(page.rewritten),\n refused: strip(page.refused),\n }));\n return JSON.stringify({ ...run, pages }, null, 2);\n}\n"],"mappings":";;;AAsDO,SAAS,eAAe,QAA8C;AAC3E,QAAM,SAAyC;AAAA,IAC7C,MAAM,OAAO,OAAO;AAAA,IACpB,MAAM,OAAO,OAAO;AAAA,EACtB;AACA,MAAI,OAAO,OAAO,SAAS,OAAW,QAAO,OAAO,OAAO,OAAO;AAElE,QAAM,SAA0B,EAAE,KAAK,OAAO,OAAO,KAAK,QAAQ,OAAO,OAAO,OAAO;AACvF,MAAI,OAAO,OAAO,aAAa,OAAW,QAAO,WAAW,OAAO,OAAO;AAC1E,MAAI,OAAO,OAAO,WAAW,OAAW,QAAO,SAAS,OAAO,OAAO;AACtE,MAAI,OAAO,OAAO,eAAe,OAAW,QAAO,aAAa,OAAO,OAAO;AAC9E,MAAI,OAAO,OAAO,cAAc,OAAW,QAAO,YAAY,OAAO,OAAO;AAC5E,MAAI,OAAO,OAAO,qBAAqB,QAAW;AAChD,WAAO,mBAAmB,OAAO,OAAO;AAAA,EAC1C;AACA,MAAI,OAAO,OAAO,oBAAoB,QAAW;AAC/C,WAAO,kBAAkB,OAAO,OAAO;AAAA,EACzC;AAEA,MAAI,QAA+B;AACnC,MAAI,OAAO,UAAU,MAAM;AACzB,YAAQ,EAAE,QAAQ,OAAO,MAAM,OAAO;AACtC,QAAI,OAAO,MAAM,UAAU,OAAW,OAAM,QAAQ,OAAO,MAAM;AACjE,QAAI,OAAO,MAAM,cAAc,OAAW,OAAM,YAAY,OAAO,MAAM;AACzE,QAAI,OAAO,MAAM,aAAa,OAAW,OAAM,WAAW,OAAO,MAAM;AACvE,QAAI,OAAO,MAAM,eAAe,OAAW,OAAM,aAAa,OAAO,MAAM;AAC3E,QAAI,OAAO,MAAM,cAAc,OAAW,OAAM,YAAY,OAAO,MAAM;AACzE,QAAI,OAAO,MAAM,qBAAqB,QAAW;AAC/C,YAAM,mBAAmB,OAAO,MAAM;AAAA,IACxC;AAAA,EACF;AAIA,SAAO;AAAA,IACL,GAAI,OAAO,SAAS,OAAO,SAAY,CAAC,IAAI,EAAE,IAAI,OAAO,SAAS,GAAG;AAAA,IACrE;AAAA,IACA,QAAQ,OAAO;AAAA,IACf,GAAI,OAAO,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,OAAO,OAAO;AAAA,IAC/D;AAAA,IACA;AAAA,EACF;AACF;AAMO,SAAS,WAAW,MAA4C;AACrE,SAAO,EAAE,GAAG,MAAM,WAAW,KAAK,UAAU,IAAI,cAAc,EAAE;AAClE;AAEO,SAAS,gBAAgB,KAAuB;AACrD,SAAO,KAAK,UAAU,EAAE,SAAS,IAAI,SAAS,OAAO,IAAI,MAAM,IAAI,UAAU,EAAE,GAAG,MAAM,CAAC;AAC3F;AAEO,SAAS,iBAAiB,KAAwB;AAIvD,SAAO,KAAK,UAAU,KAAK,MAAM,CAAC;AACpC;AAEO,SAAS,iBAAiB,KAAwB;AAGvD,QAAM,QAAQ,CAAC,SACb,KAAK,IAAI,CAAC,EAAE,YAAY,SAAS,GAAG,QAAQ,MAAM,OAAO;AAC3D,QAAM,QAAQ,IAAI,MAAM,IAAI,CAAC,UAAU;AAAA,IACrC,GAAG;AAAA,IACH,WAAW,MAAM,KAAK,SAAS;AAAA,IAC/B,SAAS,MAAM,KAAK,OAAO;AAAA,EAC7B,EAAE;AACF,SAAO,KAAK,UAAU,EAAE,GAAG,KAAK,MAAM,GAAG,MAAM,CAAC;AAClD;","names":[]}
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
LINT_JOBS,
|
|
4
|
+
listBuiltins,
|
|
5
|
+
loadTemplateFile,
|
|
6
|
+
parserByName,
|
|
7
|
+
parserForExtension,
|
|
8
|
+
resolveLintRun,
|
|
9
|
+
resolveStructureTool,
|
|
10
|
+
supportedExtensions
|
|
11
|
+
} from "./chunk-JOHKIAVH.js";
|
|
12
|
+
import {
|
|
13
|
+
BLOCK_KINDS,
|
|
14
|
+
BLOCK_KIND_NODE,
|
|
15
|
+
LintError
|
|
16
|
+
} from "./chunk-CK7SKVHR.js";
|
|
17
|
+
import {
|
|
18
|
+
writeTextAtomic
|
|
19
|
+
} from "./chunk-RLR4TKUZ.js";
|
|
20
|
+
import {
|
|
21
|
+
ToolError,
|
|
22
|
+
errorMessage
|
|
23
|
+
} from "./chunk-G3T47CFV.js";
|
|
24
|
+
|
|
25
|
+
// src/lint/core/infer.ts
|
|
26
|
+
import { stringify as stringifyYaml } from "yaml";
|
|
27
|
+
var INFER_FORMATS = ["yaml", "json"];
|
|
28
|
+
function isInferFormat(value) {
|
|
29
|
+
return INFER_FORMATS.includes(value);
|
|
30
|
+
}
|
|
31
|
+
var TEMPLATE_NAME = /^[A-Za-z][A-Za-z0-9\-_]*$/;
|
|
32
|
+
var KIND_KEY = new Map(
|
|
33
|
+
BLOCK_KINDS.map((key) => [BLOCK_KIND_NODE[key], key])
|
|
34
|
+
);
|
|
35
|
+
function origin() {
|
|
36
|
+
return {
|
|
37
|
+
start: { line: 1, column: 1, offset: 0 },
|
|
38
|
+
end: { line: 1, column: 1, offset: 0 }
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
function span(sections) {
|
|
42
|
+
const first = sections[0];
|
|
43
|
+
const last = sections[sections.length - 1];
|
|
44
|
+
if (!first || !last) return origin();
|
|
45
|
+
return { start: { ...first.position.start }, end: { ...last.position.end } };
|
|
46
|
+
}
|
|
47
|
+
function pageSection(tree) {
|
|
48
|
+
const [only] = tree.sections;
|
|
49
|
+
if (tree.sections.length === 1 && only && only.level <= 1) return only;
|
|
50
|
+
return {
|
|
51
|
+
slug: "",
|
|
52
|
+
title: "",
|
|
53
|
+
level: 0,
|
|
54
|
+
order: 0,
|
|
55
|
+
parentSlug: null,
|
|
56
|
+
titlePosition: null,
|
|
57
|
+
position: span(tree.sections),
|
|
58
|
+
children: [],
|
|
59
|
+
sections: tree.sections
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function headerCells(table) {
|
|
63
|
+
const header = table.children.find((row) => row.header);
|
|
64
|
+
return header ? header.children.map((cell) => cell.text) : [];
|
|
65
|
+
}
|
|
66
|
+
function columnsOf(tables) {
|
|
67
|
+
const headers = tables.map(headerCells);
|
|
68
|
+
const [first] = headers;
|
|
69
|
+
if (first === void 0 || first.length === 0) return {};
|
|
70
|
+
const same = (cells) => cells.length === first.length && cells.every((c, i) => c === first[i]);
|
|
71
|
+
return headers.every(same) ? { columns: [...first] } : {};
|
|
72
|
+
}
|
|
73
|
+
function languageOf(blocks) {
|
|
74
|
+
const declared = [];
|
|
75
|
+
for (const block of blocks) {
|
|
76
|
+
if (block.language === void 0 || block.language.length === 0) return {};
|
|
77
|
+
declared.push(block.language);
|
|
78
|
+
}
|
|
79
|
+
const distinct = [...new Set(declared)];
|
|
80
|
+
const [only] = distinct;
|
|
81
|
+
if (only === void 0) return {};
|
|
82
|
+
return { language: distinct.length === 1 ? only : distinct };
|
|
83
|
+
}
|
|
84
|
+
function inferContains(children) {
|
|
85
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
86
|
+
for (const node of children) {
|
|
87
|
+
const key = KIND_KEY.get(node.kind);
|
|
88
|
+
if (key === void 0) continue;
|
|
89
|
+
const bucket = byKey.get(key);
|
|
90
|
+
if (bucket) bucket.push(node);
|
|
91
|
+
else byKey.set(key, [node]);
|
|
92
|
+
}
|
|
93
|
+
const rule = {};
|
|
94
|
+
let any = false;
|
|
95
|
+
for (const key of BLOCK_KINDS) {
|
|
96
|
+
const nodes = byKey.get(key);
|
|
97
|
+
if (nodes === void 0) continue;
|
|
98
|
+
any = true;
|
|
99
|
+
if (key === "tables") {
|
|
100
|
+
rule.tables = { min: 1, ...columnsOf(nodes) };
|
|
101
|
+
} else if (key === "codeBlocks") {
|
|
102
|
+
rule.codeBlocks = { min: 1, ...languageOf(nodes) };
|
|
103
|
+
} else {
|
|
104
|
+
Object.assign(rule, { [key]: { min: 1 } });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return any ? rule : void 0;
|
|
108
|
+
}
|
|
109
|
+
function inferHeading(section) {
|
|
110
|
+
if (section.titlePosition === null) return false;
|
|
111
|
+
return section.title.length > 0 ? section.title : void 0;
|
|
112
|
+
}
|
|
113
|
+
function inferRule(section) {
|
|
114
|
+
const rule = {};
|
|
115
|
+
const heading = inferHeading(section);
|
|
116
|
+
if (heading !== void 0) rule.heading = heading;
|
|
117
|
+
const contains = inferContains(section.children);
|
|
118
|
+
if (contains) rule.contains = contains;
|
|
119
|
+
if (section.sections.length > 0) {
|
|
120
|
+
rule.sections = section.sections.map(inferRule);
|
|
121
|
+
}
|
|
122
|
+
return rule;
|
|
123
|
+
}
|
|
124
|
+
function inferTemplate(tree) {
|
|
125
|
+
return inferRule(pageSection(tree));
|
|
126
|
+
}
|
|
127
|
+
function assertTemplateName(name) {
|
|
128
|
+
if (TEMPLATE_NAME.test(name)) return name;
|
|
129
|
+
throw new LintError(
|
|
130
|
+
`"${name}" is not a usable template name. A name starts with a letter and holds only letters, digits, "-" and "_". Pass --name <name>.`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
function inferTemplateFile(tree, name) {
|
|
134
|
+
return { templates: { [assertTemplateName(name)]: inferTemplate(tree) } };
|
|
135
|
+
}
|
|
136
|
+
function renderTemplateFile(file, format) {
|
|
137
|
+
const text = format === "json" ? JSON.stringify(file, null, 2) : stringifyYaml(file, { lineWidth: 0 });
|
|
138
|
+
return text.endsWith("\n") ? text : `${text}
|
|
139
|
+
`;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/lint/commands/templates.ts
|
|
143
|
+
import { existsSync } from "node:fs";
|
|
144
|
+
import { mkdir, readFile } from "node:fs/promises";
|
|
145
|
+
import { basename, dirname, extname, resolve } from "node:path";
|
|
146
|
+
var BUILTIN_SOURCE = "builtin";
|
|
147
|
+
async function runTemplates(opts = {}) {
|
|
148
|
+
const templates = listBuiltins().map((builtin) => ({
|
|
149
|
+
id: builtin.id,
|
|
150
|
+
title: builtin.title,
|
|
151
|
+
types: builtin.types,
|
|
152
|
+
source: BUILTIN_SOURCE
|
|
153
|
+
}));
|
|
154
|
+
const paths = opts.templates == null ? [] : Array.isArray(opts.templates) ? opts.templates : [opts.templates];
|
|
155
|
+
for (const path of paths) {
|
|
156
|
+
const file = await loadTemplateFile(path);
|
|
157
|
+
for (const [id, template] of Object.entries(file.templates ?? {})) {
|
|
158
|
+
templates.push({
|
|
159
|
+
id,
|
|
160
|
+
title: "",
|
|
161
|
+
types: template.types ?? [],
|
|
162
|
+
source: path
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return { templates };
|
|
167
|
+
}
|
|
168
|
+
var STDIN = "-";
|
|
169
|
+
var STDIN_NAME = "stdin";
|
|
170
|
+
function parserFor(page, as) {
|
|
171
|
+
if (as !== void 0) {
|
|
172
|
+
const forced = parserByName(as);
|
|
173
|
+
if (forced) return forced;
|
|
174
|
+
throw new LintError(
|
|
175
|
+
`Unknown format "${as}". Run "manni lint tools" to see the formats manni lint reads.`
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
if (page === STDIN) {
|
|
179
|
+
throw new LintError(
|
|
180
|
+
"Reading from stdin (-) requires --as <format> to choose a parser."
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
const ext = extname(page);
|
|
184
|
+
const parser = parserForExtension(ext);
|
|
185
|
+
if (parser) return parser;
|
|
186
|
+
throw new LintError(
|
|
187
|
+
`no parser is registered for "${ext || page}". Supported extensions: ${supportedExtensions().join(", ")}. Use --as to override.`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
function defaultName(tree, page) {
|
|
191
|
+
const declared = tree.frontmatter?.["type"];
|
|
192
|
+
if (typeof declared === "string" && declared.trim().length > 0) {
|
|
193
|
+
return declared.trim();
|
|
194
|
+
}
|
|
195
|
+
if (page === STDIN) return STDIN_NAME;
|
|
196
|
+
return basename(page, extname(page)) || STDIN_NAME;
|
|
197
|
+
}
|
|
198
|
+
async function runTemplatesInfer(opts) {
|
|
199
|
+
const format = opts.format ?? "yaml";
|
|
200
|
+
if (!isInferFormat(format)) {
|
|
201
|
+
throw new LintError(
|
|
202
|
+
`Unknown --format "${String(format)}". Use yaml or json.`
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
const run = await resolveLintRun({
|
|
206
|
+
cwd: opts.cwd ?? process.cwd(),
|
|
207
|
+
...opts.configPath === void 0 ? {} : { configPath: opts.configPath },
|
|
208
|
+
...opts.noConfig === void 0 ? {} : { noConfig: opts.noConfig },
|
|
209
|
+
inputs: [opts.page],
|
|
210
|
+
...opts.onConfigLoaded === void 0 ? {} : { onConfigLoaded: opts.onConfigLoaded }
|
|
211
|
+
});
|
|
212
|
+
const cwd = run.base;
|
|
213
|
+
const parser = parserFor(opts.page, opts.as);
|
|
214
|
+
if (opts.name !== void 0) assertTemplateName(opts.name);
|
|
215
|
+
let absOut;
|
|
216
|
+
if (opts.out !== void 0) {
|
|
217
|
+
absOut = resolve(cwd, opts.out);
|
|
218
|
+
if (opts.force !== true && existsSync(absOut)) {
|
|
219
|
+
throw new LintError(`${opts.out} exists. Pass --force to overwrite it.`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
let content;
|
|
223
|
+
if (opts.page === STDIN) {
|
|
224
|
+
content = opts.stdinContent ?? "";
|
|
225
|
+
} else {
|
|
226
|
+
try {
|
|
227
|
+
content = await readFile(resolve(cwd, opts.page), "utf8");
|
|
228
|
+
} catch (err) {
|
|
229
|
+
throw new LintError(
|
|
230
|
+
`"${opts.page}" could not be read: ${errorMessage(err)}`
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
let tree;
|
|
235
|
+
try {
|
|
236
|
+
tree = parser.parse(content, opts.page === STDIN ? "<stdin>" : opts.page);
|
|
237
|
+
} catch (err) {
|
|
238
|
+
if (err instanceof ToolError) throw new LintError(err.message);
|
|
239
|
+
throw err;
|
|
240
|
+
}
|
|
241
|
+
const name = opts.name ?? defaultName(tree, opts.page);
|
|
242
|
+
const file = inferTemplateFile(tree, name);
|
|
243
|
+
const text = renderTemplateFile(file, format);
|
|
244
|
+
if (absOut === void 0) return { name, file, text };
|
|
245
|
+
await mkdir(dirname(absOut), { recursive: true });
|
|
246
|
+
await writeTextAtomic(absOut, text);
|
|
247
|
+
return { name, file, text, written: opts.out };
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// src/lint/commands/tools.ts
|
|
251
|
+
var REPORTABLE_KINDS = new Set(Object.values(BLOCK_KIND_NODE));
|
|
252
|
+
var BUILT_IN_DEFAULTS = "built-in defaults";
|
|
253
|
+
function isConfigured(job, config) {
|
|
254
|
+
if (config[job] !== void 0) return true;
|
|
255
|
+
return config.templates !== void 0 || config.template !== void 0 || config.types !== void 0 || config.overrides !== void 0;
|
|
256
|
+
}
|
|
257
|
+
async function runTools(opts = {}) {
|
|
258
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
259
|
+
const run = await resolveLintRun({
|
|
260
|
+
cwd,
|
|
261
|
+
configPath: opts.configPath,
|
|
262
|
+
noConfig: opts.noConfig,
|
|
263
|
+
inputs: []
|
|
264
|
+
});
|
|
265
|
+
return await Promise.all(
|
|
266
|
+
LINT_JOBS.map(async (job) => {
|
|
267
|
+
const tool = run.config[job]?.tool ?? "manni";
|
|
268
|
+
const descriptor = resolveStructureTool(tool);
|
|
269
|
+
const probed = await descriptor.probe({
|
|
270
|
+
cwd,
|
|
271
|
+
tools: run.tools,
|
|
272
|
+
...run.configDir === void 0 ? {} : { configDir: run.configDir }
|
|
273
|
+
});
|
|
274
|
+
return {
|
|
275
|
+
job,
|
|
276
|
+
tool,
|
|
277
|
+
configured: isConfigured(job, run.config),
|
|
278
|
+
available: probed.available,
|
|
279
|
+
version: probed.version,
|
|
280
|
+
config: run.configSource ?? BUILT_IN_DEFAULTS,
|
|
281
|
+
formats: descriptor.formats().map((format) => ({
|
|
282
|
+
...format,
|
|
283
|
+
kinds: format.kinds.filter((kind) => REPORTABLE_KINDS.has(kind))
|
|
284
|
+
}))
|
|
285
|
+
};
|
|
286
|
+
})
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export {
|
|
291
|
+
INFER_FORMATS,
|
|
292
|
+
isInferFormat,
|
|
293
|
+
BUILTIN_SOURCE,
|
|
294
|
+
runTemplates,
|
|
295
|
+
runTemplatesInfer,
|
|
296
|
+
BUILT_IN_DEFAULTS,
|
|
297
|
+
runTools
|
|
298
|
+
};
|
|
299
|
+
//# sourceMappingURL=chunk-PCHZY2I7.js.map
|