@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.
Files changed (224) hide show
  1. package/README.md +9 -1
  2. package/dist/batch-DFRCLY77.js +36 -0
  3. package/dist/build-Q5C6SX5J.js +31 -0
  4. package/dist/calibrate-XQILKXS3.js +31 -0
  5. package/dist/capture-JQMOC3BW.js +32 -0
  6. package/dist/check-HYNGXYJV.js +18 -0
  7. package/dist/check-HYNGXYJV.js.map +1 -0
  8. package/dist/check-NFZQLJKN.js +27 -0
  9. package/dist/check-NFZQLJKN.js.map +1 -0
  10. package/dist/check-U54XV6BP.js +40 -0
  11. package/dist/check-U54XV6BP.js.map +1 -0
  12. package/dist/chunk-252LNOEG.js +622 -0
  13. package/dist/chunk-252LNOEG.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-2U3ORT6D.js +230 -0
  17. package/dist/chunk-2U3ORT6D.js.map +1 -0
  18. package/dist/chunk-3AFUD75K.js +23 -0
  19. package/dist/chunk-3AFUD75K.js.map +1 -0
  20. package/dist/{chunk-3R23C5DT.js → chunk-4TSWU2SU.js} +2 -14
  21. package/dist/chunk-4TSWU2SU.js.map +1 -0
  22. package/dist/chunk-5KHIFVD2.js +1192 -0
  23. package/dist/chunk-5KHIFVD2.js.map +1 -0
  24. package/dist/chunk-5YXBLLAC.js +2165 -0
  25. package/dist/chunk-5YXBLLAC.js.map +1 -0
  26. package/dist/chunk-644JVKJ4.js +3872 -0
  27. package/dist/chunk-644JVKJ4.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-77HX34KD.js +1287 -0
  33. package/dist/chunk-77HX34KD.js.map +1 -0
  34. package/dist/{chunk-MOQXWXSG.js → chunk-7QMCHA4N.js} +32 -240
  35. package/dist/chunk-7QMCHA4N.js.map +1 -0
  36. package/dist/chunk-BUXDLRDT.js +455 -0
  37. package/dist/chunk-BUXDLRDT.js.map +1 -0
  38. package/dist/chunk-C6OH6CNF.js +388 -0
  39. package/dist/chunk-C6OH6CNF.js.map +1 -0
  40. package/dist/chunk-CK7SKVHR.js +1042 -0
  41. package/dist/chunk-CK7SKVHR.js.map +1 -0
  42. package/dist/chunk-CYWHFSRT.js +6737 -0
  43. package/dist/chunk-CYWHFSRT.js.map +1 -0
  44. package/dist/chunk-ERMSO34F.js +17 -0
  45. package/dist/chunk-ERMSO34F.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-G7NJSREW.js +979 -0
  49. package/dist/chunk-G7NJSREW.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-H2DLH2JI.js +198 -0
  53. package/dist/chunk-H2DLH2JI.js.map +1 -0
  54. package/dist/chunk-H6FZ66XR.js +634 -0
  55. package/dist/chunk-H6FZ66XR.js.map +1 -0
  56. package/dist/{chunk-CI2GOU3A.js → chunk-IEQHSCZG.js} +56 -137
  57. package/dist/chunk-IEQHSCZG.js.map +1 -0
  58. package/dist/chunk-IKEWBMCN.js +98 -0
  59. package/dist/chunk-IKEWBMCN.js.map +1 -0
  60. package/dist/chunk-JOHKIAVH.js +5440 -0
  61. package/dist/chunk-JOHKIAVH.js.map +1 -0
  62. package/dist/chunk-JVTNMVYU.js +10921 -0
  63. package/dist/chunk-JVTNMVYU.js.map +1 -0
  64. package/dist/chunk-K3D6FPV6.js +164 -0
  65. package/dist/chunk-K3D6FPV6.js.map +1 -0
  66. package/dist/{chunk-MFDD3YGU.js → chunk-KCGV52AM.js} +69 -48
  67. package/dist/{chunk-MFDD3YGU.js.map → chunk-KCGV52AM.js.map} +1 -1
  68. package/dist/chunk-LAKAWRV5.js +1651 -0
  69. package/dist/chunk-LAKAWRV5.js.map +1 -0
  70. package/dist/chunk-LJ2RDH3F.js +49 -0
  71. package/dist/chunk-LJ2RDH3F.js.map +1 -0
  72. package/dist/chunk-M2JCK5F6.js +805 -0
  73. package/dist/chunk-M2JCK5F6.js.map +1 -0
  74. package/dist/chunk-MNH7QO4Z.js +15 -0
  75. package/dist/chunk-MNH7QO4Z.js.map +1 -0
  76. package/dist/{chunk-RVVCA4WL.js → chunk-MYC3O5EJ.js} +4 -4
  77. package/dist/chunk-MYMBCTDE.js +387 -0
  78. package/dist/chunk-MYMBCTDE.js.map +1 -0
  79. package/dist/chunk-NCPWXHDO.js +683 -0
  80. package/dist/chunk-NCPWXHDO.js.map +1 -0
  81. package/dist/chunk-NWZ2SLYL.js +2957 -0
  82. package/dist/chunk-NWZ2SLYL.js.map +1 -0
  83. package/dist/chunk-OBFENF3U.js +934 -0
  84. package/dist/chunk-OBFENF3U.js.map +1 -0
  85. package/dist/chunk-OWBRDNRZ.js +16 -0
  86. package/dist/chunk-OWBRDNRZ.js.map +1 -0
  87. package/dist/{chunk-KTSJ2ZHA.js → chunk-PAU352SV.js} +5 -3
  88. package/dist/{chunk-KTSJ2ZHA.js.map → chunk-PAU352SV.js.map} +1 -1
  89. package/dist/chunk-PCE7QHXJ.js +68 -0
  90. package/dist/chunk-PCE7QHXJ.js.map +1 -0
  91. package/dist/chunk-PCHZY2I7.js +299 -0
  92. package/dist/chunk-PCHZY2I7.js.map +1 -0
  93. package/dist/chunk-PHF3D7ER.js +1042 -0
  94. package/dist/chunk-PHF3D7ER.js.map +1 -0
  95. package/dist/chunk-Q35YIDBV.js +1202 -0
  96. package/dist/chunk-Q35YIDBV.js.map +1 -0
  97. package/dist/chunk-RLR4TKUZ.js +4398 -0
  98. package/dist/chunk-RLR4TKUZ.js.map +1 -0
  99. package/dist/chunk-RNVYGWIC.js +30 -0
  100. package/dist/chunk-RNVYGWIC.js.map +1 -0
  101. package/dist/chunk-SE4JN5XN.js +19 -0
  102. package/dist/chunk-SE4JN5XN.js.map +1 -0
  103. package/dist/chunk-TIUTIOFB.js +25 -0
  104. package/dist/chunk-TIUTIOFB.js.map +1 -0
  105. package/dist/chunk-TU2WUBVZ.js +2 -0
  106. package/dist/chunk-TU2WUBVZ.js.map +1 -0
  107. package/dist/chunk-TZOYZK2E.js +98 -0
  108. package/dist/chunk-TZOYZK2E.js.map +1 -0
  109. package/dist/chunk-UKZNLVJW.js +17 -0
  110. package/dist/chunk-UKZNLVJW.js.map +1 -0
  111. package/dist/chunk-UZC7LDAQ.js +178 -0
  112. package/dist/chunk-UZC7LDAQ.js.map +1 -0
  113. package/dist/chunk-V46OILVC.js +3090 -0
  114. package/dist/chunk-V46OILVC.js.map +1 -0
  115. package/dist/chunk-WQE54PNH.js +1975 -0
  116. package/dist/chunk-WQE54PNH.js.map +1 -0
  117. package/dist/chunk-X3BPBDGQ.js +52 -0
  118. package/dist/chunk-X3BPBDGQ.js.map +1 -0
  119. package/dist/chunk-XSLV76YK.js +54 -0
  120. package/dist/chunk-XSLV76YK.js.map +1 -0
  121. package/dist/{chunk-QROCFW5S.js → chunk-XYLUCIKQ.js} +3 -3
  122. package/dist/chunk-YEUYKR62.js +72 -0
  123. package/dist/chunk-YEUYKR62.js.map +1 -0
  124. package/dist/{chunk-ESJ5W7EV.js → chunk-YFQBFNQS.js} +8 -94
  125. package/dist/chunk-YFQBFNQS.js.map +1 -0
  126. package/dist/chunk-YIL4XLLJ.js +1661 -0
  127. package/dist/chunk-YIL4XLLJ.js.map +1 -0
  128. package/dist/chunk-YNHZHSSM.js +41 -0
  129. package/dist/chunk-YNHZHSSM.js.map +1 -0
  130. package/dist/chunk-YTCZRLTU.js +96 -0
  131. package/dist/chunk-YTCZRLTU.js.map +1 -0
  132. package/dist/chunk-YYBFZLAJ.js +374 -0
  133. package/dist/chunk-YYBFZLAJ.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-2QPR2OZG.js +232 -0
  137. package/dist/cli-2QPR2OZG.js.map +1 -0
  138. package/dist/cli-4IOPGZHR.js +1203 -0
  139. package/dist/cli-4IOPGZHR.js.map +1 -0
  140. package/dist/cli-5FL73WHA.js +346 -0
  141. package/dist/cli-5FL73WHA.js.map +1 -0
  142. package/dist/cli-C262QOWM.js +739 -0
  143. package/dist/cli-C262QOWM.js.map +1 -0
  144. package/dist/cli-LJLLIQB2.js +423 -0
  145. package/dist/cli-LJLLIQB2.js.map +1 -0
  146. package/dist/cli-OFPZ5MAS.js +626 -0
  147. package/dist/cli-OFPZ5MAS.js.map +1 -0
  148. package/dist/cli-SHSMSRQY.js +28 -0
  149. package/dist/cli-SHSMSRQY.js.map +1 -0
  150. package/dist/cli-SRHFUZHA.js +473 -0
  151. package/dist/cli-SRHFUZHA.js.map +1 -0
  152. package/dist/cli-URZQXL4K.js +552 -0
  153. package/dist/cli-URZQXL4K.js.map +1 -0
  154. package/dist/cli.d.ts +12 -2
  155. package/dist/cli.js +109 -7651
  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-FE6KCNYJ.js +27 -0
  160. package/dist/github-FE6KCNYJ.js.map +1 -0
  161. package/dist/github-QXL3VMK2.js +32 -0
  162. package/dist/github-QXL3VMK2.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-SGZ6ZRFD.js +35 -0
  169. package/dist/json-SGZ6ZRFD.js.map +1 -0
  170. package/dist/lint-DL4LJRAY.js +28 -0
  171. package/dist/lint-DL4LJRAY.js.map +1 -0
  172. package/dist/list-6BAXTZUM.js +29 -0
  173. package/dist/list-6BAXTZUM.js.map +1 -0
  174. package/dist/list-7BKNYPSB.js +31 -0
  175. package/dist/list-7BKNYPSB.js.map +1 -0
  176. package/dist/page-3U2GCFNE.js +41 -0
  177. package/dist/page-3U2GCFNE.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-2H57QVTY.js +43 -0
  181. package/dist/pretty-2H57QVTY.js.map +1 -0
  182. package/dist/pretty-N6DO4OOL.js +37 -0
  183. package/dist/pretty-N6DO4OOL.js.map +1 -0
  184. package/dist/reporters-M6LJ2IYU.js +21 -0
  185. package/dist/reporters-M6LJ2IYU.js.map +1 -0
  186. package/dist/reporters-N6GHXSS7.js +42 -0
  187. package/dist/reporters-N6GHXSS7.js.map +1 -0
  188. package/dist/reporters-UCNEV7PH.js +71 -0
  189. package/dist/reporters-UCNEV7PH.js.map +1 -0
  190. package/dist/run-XZDAREJE.js +33 -0
  191. package/dist/run-XZDAREJE.js.map +1 -0
  192. package/dist/term-5ICGKPC3.js +1592 -0
  193. package/dist/term-5ICGKPC3.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-GQRM77YN.js +16 -0
  197. package/dist/validate-GQRM77YN.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 +52 -0
  201. package/plugin/manni/skills/check/SKILL.md +20 -0
  202. package/plugin/manni/skills/evals/SKILL.md +27 -0
  203. package/plugin/manni/skills/fix/SKILL.md +56 -0
  204. package/plugin/manni/skills/setup/SKILL.md +41 -0
  205. package/dist/batch-7JJWXWSF.js +0 -18
  206. package/dist/calibrate-IA2ARFMH.js +0 -13
  207. package/dist/capture-C32JXIFN.js +0 -15
  208. package/dist/chunk-3R23C5DT.js.map +0 -1
  209. package/dist/chunk-CI2GOU3A.js.map +0 -1
  210. package/dist/chunk-DP2ZA3WH.js +0 -26518
  211. package/dist/chunk-DP2ZA3WH.js.map +0 -1
  212. package/dist/chunk-ESJ5W7EV.js.map +0 -1
  213. package/dist/chunk-MOQXWXSG.js.map +0 -1
  214. package/dist/chunk-O6RVQKK6.js +0 -27170
  215. package/dist/chunk-O6RVQKK6.js.map +0 -1
  216. package/dist/picker-6HRMETE7.js +0 -12
  217. package/plugin/tracevals/.claude-plugin/plugin.json +0 -9
  218. package/plugin/tracevals/hooks/hooks.json +0 -17
  219. /package/dist/{batch-7JJWXWSF.js.map → batch-DFRCLY77.js.map} +0 -0
  220. /package/dist/{calibrate-IA2ARFMH.js.map → build-Q5C6SX5J.js.map} +0 -0
  221. /package/dist/{capture-C32JXIFN.js.map → calibrate-XQILKXS3.js.map} +0 -0
  222. /package/dist/{picker-6HRMETE7.js.map → capture-JQMOC3BW.js.map} +0 -0
  223. /package/dist/{chunk-RVVCA4WL.js.map → chunk-MYC3O5EJ.js.map} +0 -0
  224. /package/dist/{chunk-QROCFW5S.js.map → chunk-XYLUCIKQ.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cite/core/spell.ts","../src/cite/core/adapt.ts","../src/cite/core/reanchor.ts","../src/cite/core/claims.ts"],"sourcesContent":["/**\n * How a citation reads on a terminal. A pin is sixty-four hex digits and a\n * ciphertext is longer still, so both are abbreviated for a person, and every\n * report and every `add` line abbreviates them the same way.\n */\nimport type { PageLines } from \"../types.js\";\n\n/** `sha256-78af1d33…`, `hmac-sha256-5e0c1a2b…`: the prefix and eight hex digits. */\nexport function shortPin(integrity: string): string {\n const m = /^((?:hmac-)?sha256-)([0-9a-f]{8})/i.exec(integrity);\n const prefix = m?.[1];\n const digits = m?.[2];\n if (prefix === undefined || digits === undefined) return integrity;\n return `${prefix}${digits}…`;\n}\n\n/** The seven characters a person reads a commit by. */\nexport function shortCommit(commit: string): string {\n return commit.slice(0, 7);\n}\n\n/**\n * `~AQx7…:2`: an encrypted source, abbreviated, with its line suffix kept. A\n * plain path is spelled in full, because that is what a reader has to find.\n */\nexport function shortSrc(src: string): string {\n if (!src.startsWith(\"~\")) return src;\n const colon = src.indexOf(\":\");\n const token = colon === -1 ? src : src.slice(0, colon);\n const lines = colon === -1 ? \"\" : src.slice(colon);\n return token.length <= 5 ? src : `${token.slice(0, 5)}…${lines}`;\n}\n\n/** The widest a quoted line of a file is printed at. */\nconst LINE_WIDTH = 60;\n\n/**\n * A line of a file as a report quotes it: whitespace collapsed to single\n * spaces, then sixty characters and an ellipsis. The report is one line, so\n * neither an indented source line nor a long one decides how it reads.\n */\nexport function shortLine(text: string): string {\n const one = text.replace(/\\s+/g, \" \").trim();\n return one.length <= LINE_WIDTH ? one : `${one.slice(0, LINE_WIDTH)}…`;\n}\n\n/**\n * `line 9`, or `lines 9-12`: where on a page a span sits. Every refusal,\n * report and message that names one reads it this way, so `add`, `update`\n * and the reporters spell it once.\n */\nexport function spellAt(lines: PageLines): string {\n return lines.start === lines.end\n ? `line ${String(lines.start)}`\n : `lines ${String(lines.start)}-${String(lines.end)}`;\n}\n\n/** `a`, `a and b`, `a, b and c`: a list as a sentence reads it. */\nexport function listOf(values: readonly string[]): string {\n if (values.length <= 1) return values.join(\"\");\n return `${values.slice(0, -1).join(\", \")} and ${values[values.length - 1] ?? \"\"}`;\n}\n","/**\n * Findings, their messages, and the bridge to meta's `ValidationResult`, so\n * the github/sarif/junit reporters and the baseline ratchet work unchanged.\n *\n * A claim or marker finding sits on the page line a reviewer reads. A finding\n * about the entry itself, `entry-invalid` or a bare pin whose source changed,\n * sits on the entry's own line, in the manifest when one owns it.\n *\n * FieldError: schema \"manni:cite\" (matches BUILTIN_ID, so canonicalSchemaRef\n * leaves it alone), keyword = rule, instancePath \"/citations/N\", subject =\n * id ?? source.integrity, never the claim's pin, so accepting a claim does\n * not reopen baselined findings. `ok` is true iff no error-severity finding.\n *\n * Every message spells the source as the entry spelled it. `resolvedPath`,\n * `commitsSince` and `diff` never enter a message: they are pretty-only\n * fields, shown under `--reveal` and `--show-diff`.\n */\nimport { isAbsolute } from \"node:path\";\nimport { isErrorSeverity, type FieldError, type ValidationResult } from \"../../meta/index.js\";\nimport type {\n CitationFinding,\n CitationResult,\n CiteRule,\n CiteSeverity,\n ClaimEnd,\n PageCitationReport,\n SourceEnd,\n SourceStatus,\n} from \"../types.js\";\nimport { claimLine } from \"./claims.js\";\nimport { parseSrc } from \"./range.js\";\nimport { RULE_ID_PREFIX, ruleId } from \"./severity.js\";\nimport { listOf, shortSrc } from \"./spell.js\";\n\n/** The seven characters a person reads a commit by. */\nfunction short(commit: string): string {\n return commit.slice(0, 7);\n}\n\nfunction plural(n: number, noun: string): string {\n return `${String(n)} ${noun}${n === 1 ? \"\" : \"s\"}`;\n}\n\n/** Whether the entry spelled this source encrypted. */\nfunction citesEncrypted(src: string): boolean {\n try {\n return parseSrc(src).encrypted;\n } catch {\n return false;\n }\n}\n\n/**\n * Why an encrypted source is missing, in words that never name the path. A\n * plain path names its own file, so the bare status says the rest.\n */\nfunction missingMessage(source: SourceEnd): string {\n if (!citesEncrypted(source.src)) return \"missing\";\n switch (source.missingReason) {\n case \"no-key\":\n return \"missing (no encryption key is available to decrypt it)\";\n case \"undecryptable\":\n return \"missing (does not decrypt under the current key)\";\n case \"untracked\":\n return \"missing (no tracked file matches; wrong --root?)\";\n case \"unreadable\":\n case undefined:\n return \"missing\";\n }\n}\n\n/** The one place a source end's message is composed, per status. */\nexport function messageFor(source: SourceEnd): string {\n switch (source.status) {\n case \"current\":\n return \"current\";\n case \"skipped\":\n return \"skipped\";\n case \"moved\":\n // An encrypted source's new path is a ciphertext, abbreviated as the\n // entry's own is: `--reveal` stays the only way to read either.\n return `moved -> ${shortSrc(source.newSrc ?? \"?\")}`;\n case \"moved-ambiguous\": {\n const candidates = source.candidates ?? [];\n return `moved, ${plural(candidates.length, \"candidate\")} (${candidates.map(shortSrc).join(\", \")}); widen the range`;\n }\n case \"changed\": {\n // Where the old first and last line sit now, when the in-range search\n // found each exactly once: the span `update --accept` re-mints at.\n const span = source.newLines === undefined ? \"\" : `; now at lines ${source.newLines}`;\n if (source.commitSha === undefined) return `changed${span}`;\n const at = short(source.commitSha);\n if (source.historyAvailable === false) {\n return `changed (history unavailable: commit ${at} not found; fetch-depth: 0)`;\n }\n if (source.commitsSince === undefined) return `changed since ${at}${span}`;\n return `changed since ${at}, ${plural(source.commitsSince.length, \"commit\")}${span}`;\n }\n case \"never-true\":\n return source.commitSha === undefined\n ? \"never true: the pin does not match at the recorded commit\"\n : `never true: the pin does not match at ${short(source.commitSha)}`;\n case \"missing\":\n return missingMessage(source);\n }\n}\n\n/** `<id>: <text>`, or the text alone for an entry with no id. */\nfunction named(id: string | undefined, text: string): string {\n return id === undefined ? text : `${id}: ${text}`;\n}\n\n/** `line 9`, or `lines 9-10` when the claim covers several. */\nfunction at(spec: string): string {\n return spec.includes(\"-\") ? `lines ${spec}` : `line ${spec}`;\n}\n\n/** The one place a claim end's message is composed, per status. */\nexport function claimMessageFor(result: CitationResult): string {\n const claim = result.claim;\n const id = result.citation.id;\n if (claim === null) return \"\";\n // A marker-anchored claim has no lines of its own; it is judged where the\n // marker's text sits, and that is what the message names.\n const where =\n claim.fileLines ??\n (result.markerLine === undefined ? undefined : String(result.markerLine));\n switch (claim.status) {\n case \"moved\":\n return named(\n id,\n `the claim moved from ${at(where ?? \"?\")} to ${at(claim.newFileLines ?? \"?\")}.`,\n );\n case \"moved-ambiguous\":\n return named(\n id,\n `the claim at ${at(where ?? \"?\")} now appears at lines ${listOf(claim.candidateFileLines ?? [])}.`,\n );\n case \"reanchored\": {\n const since = claim.commitSha === undefined ? \"\" : ` since ${short(claim.commitSha)}`;\n // A claim-lines entry moved onto its new run; a marker-anchored one\n // never moves, because the marker travels with its own text.\n const to =\n claim.newFileLines === undefined ? \"\" : `, to ${at(claim.newFileLines)}`;\n return named(\n id,\n `the claim at ${at(where ?? \"?\")} was reanchored${since}${to}. Its words are unchanged.`,\n );\n }\n case \"changed\":\n if (where === undefined) {\n return named(\n id,\n \"the claim has no lines and no marker names the entry, so its pin anchors nothing.\",\n );\n }\n return named(id, `the claim at ${at(where)} has ${claimChange(claim)}`);\n case \"current\":\n case \"skipped\":\n return \"\";\n }\n}\n\n/** How a changed claim says since when, which is what its history could say. */\nfunction claimChange(claim: ClaimEnd): string {\n if (claim.historyAvailable === false) {\n return \"changed since it was pinned (history unavailable; fetch-depth: 0).\";\n }\n if (claim.commitSha === undefined) return \"changed since it was pinned.\";\n const at = short(claim.commitSha);\n // Zero commits since would read as \"just now\". The working tree holding the\n // change is what it actually means, so it says that.\n const since = claim.commitsSince ?? [];\n const count = since.length === 0 ? \"uncommitted\" : plural(since.length, \"commit\");\n return `changed since ${at}, ${count}.`;\n}\n\n/**\n * The one place a `marker-misplaced` message is composed. A quote marker's\n * place is above the block it anchors; every other marker's is the first line\n * of the paragraph its run splits.\n */\nexport function misplacedMessageFor(\n id: string | undefined,\n marker: { line: number; unit: string; place: number; block: boolean },\n): string {\n const place = marker.block\n ? `above the block at line ${String(marker.place)}`\n : `above line ${String(marker.place)}`;\n return named(\n id,\n `the marker at line ${String(marker.line)} splits the paragraph at ${at(marker.unit)}. Its place is ${place}.`,\n );\n}\n\n/** The rule a source status reports under, or undefined for one that is not a finding. */\nfunction sourceRuleOf(status: SourceStatus): CiteRule | undefined {\n if (status === \"skipped\" || status === \"current\") return undefined;\n return `source-${status}`;\n}\n\n/** The rule a claim status reports under, or undefined. */\nfunction claimRuleOf(claim: ClaimEnd): CiteRule | undefined {\n const status = claim.status;\n if (status === \"skipped\" || status === \"current\") return undefined;\n return `claim-${status}`;\n}\n\n/** Where a finding about a whole entry sits: its own line, in its own file. */\nfunction entrySite(result: CitationResult): Pick<CitationFinding, \"line\" | \"file\"> {\n const site: Pick<CitationFinding, \"line\" | \"file\"> = {};\n if (result.origin.line !== undefined) site.line = result.origin.line;\n if (result.origin.kind === \"manifest\") site.file = result.origin.file;\n return site;\n}\n\n/** Where a finding about an anchored citation sits: the page line it anchors to. */\nfunction anchorSite(result: CitationResult): Pick<CitationFinding, \"line\" | \"file\"> {\n if (result.anchorLine !== undefined) return { line: result.anchorLine };\n return entrySite(result);\n}\n\n/** Findings for classified citations under a severity table; `off` rules produce none. */\nexport function findingsFor(\n results: readonly CitationResult[],\n severity: Readonly<Record<CiteRule, CiteSeverity>>,\n): CitationFinding[] {\n const out: CitationFinding[] = [];\n const push = (\n result: CitationResult,\n rule: CiteRule,\n message: string,\n site: Pick<CitationFinding, \"line\" | \"file\">,\n extra?: Pick<CitationFinding, \"newSrc\">,\n ): void => {\n const level = severity[rule];\n if (level === \"off\") return;\n const finding: CitationFinding = {\n rule,\n ruleId: ruleId(rule),\n severity: level,\n message,\n src: result.source.src,\n index: result.origin.index,\n };\n if (site.line !== undefined) finding.line = site.line;\n if (site.file !== undefined) finding.file = site.file;\n if (result.citation.id !== undefined) finding.id = result.citation.id;\n if (extra?.newSrc !== undefined) finding.newSrc = extra.newSrc;\n out.push(finding);\n };\n\n for (const result of results) {\n const claim = result.claim;\n if (claim !== null) {\n const rule = claimRuleOf(claim);\n // A claim pin that anchors nothing has no page line to sit on.\n if (rule !== undefined) {\n const site =\n claimLine(claim) === undefined && result.markerLine === undefined\n ? entrySite(result)\n : { line: claimLine(claim) ?? result.markerLine };\n push(result, rule, claimMessageFor(result), site);\n }\n }\n const rule = sourceRuleOf(result.source.status);\n if (rule === undefined) continue;\n const extra =\n result.source.newSrc === undefined ? undefined : { newSrc: result.source.newSrc };\n push(result, rule, messageFor(result.source), anchorSite(result), extra);\n }\n return out;\n}\n\n/**\n * The pin of the citation a finding is about, for the fingerprint subject of\n * an entry with no id. Always the source's: accepting a changed claim must\n * not reopen a baselined finding.\n */\nfunction integrityFor(\n finding: CitationFinding,\n results: readonly CitationResult[],\n): string | undefined {\n if (finding.index === undefined) return undefined;\n return results.find((r) => r.origin.index === finding.index)?.citation.source.integrity;\n}\n\n/**\n * Where a finding is located once it becomes a `FieldError`: the page, or\n * the manifest the entry sits in.\n *\n * A manifest outside the repository has no location any reporter can use —\n * SARIF drops a uri that rebases to `../…`, and a GitHub annotation on one\n * lands nowhere — so the finding falls back to the page, and its line goes\n * with the file it belonged to. Inside the tree, both travel, and `file`\n * is what every reporter reads to annotate the manifest instead.\n */\nexport function errorSite(\n finding: CitationFinding,\n): Pick<CitationFinding, \"line\" | \"file\"> {\n if (finding.file === undefined) {\n return finding.line === undefined ? {} : { line: finding.line };\n }\n if (finding.file.startsWith(\"../\") || isAbsolute(finding.file)) return {};\n return {\n file: finding.file,\n ...(finding.line === undefined ? {} : { line: finding.line }),\n };\n}\n\nexport function toValidationResult(report: PageCitationReport): ValidationResult {\n const errors: FieldError[] = report.findings.map((finding) => {\n const error: FieldError = {\n schema: RULE_ID_PREFIX,\n instancePath: finding.index === undefined ? \"\" : `/citations/${String(finding.index)}`,\n message: finding.message,\n keyword: finding.rule,\n severity: finding.severity,\n };\n const subject = finding.id ?? integrityFor(finding, report.citations);\n if (subject !== undefined) error.subject = subject;\n const site = errorSite(finding);\n if (site.file !== undefined) error.file = site.file;\n if (site.line !== undefined) error.line = site.line;\n return error;\n });\n return {\n file: report.file,\n format: report.format,\n ok: !errors.some(isErrorSeverity),\n schemas: [RULE_ID_PREFIX],\n errors,\n };\n}\n","/**\n * Misplaced markers, and what to do about them. Proposal 0054 is the record.\n *\n * A **marker run** is one or more consecutive lines that each hold one marker\n * and nothing else. A run is **misplaced** when the line directly above it and\n * the line directly below it are both unit text: deleting the run would join\n * them into one paragraph. Such a marker splits the paragraph for the renderer\n * and for the tool, and the lines above it are anchored by nothing.\n *\n * A misplaced marker belongs where `add --marker` writes one: above the first\n * line of the unit, or, for a `quote: true` entry, above the block it anchors.\n * A run moves in its own order, so two markers that were stacked stay stacked.\n *\n * The claim of a marker-anchored entry is read against three spans, in order:\n * the unit the marker belongs to, the span it anchors now, and the span it was\n * pinned over before PR #43 (marker lines included, down to the next blank\n * line or fence). The second or third holding means the pinned text is on the\n * page and the marker anchors a different span: `claim-moved`.\n */\nimport type { ClaimEnd, PageCitation, PageCitations, PageLines } from \"../types.js\";\nimport { hashLines } from \"./hash.js\";\nimport { MAX_MARKERS_PER_PAGE } from \"./page.js\";\nimport { spellLines } from \"../../shared/pin.js\";\nimport { ANY_FENCE, anchoredLines, isBoundLine, isMarkerLine } from \"./statements.js\";\n\n/** Whether a line is text a paragraph is made of. */\nexport function isUnitText(line: string | undefined, format: string): boolean {\n if (line === undefined) return false;\n if (line.trim() === \"\") return false;\n if (ANY_FENCE.test(line)) return false;\n if (isMarkerLine(line, format)) return false;\n return !isBoundLine(line, format);\n}\n\n/** Whether the file line `n` holds one marker and nothing else. */\nfunction markerAt(lines: readonly string[], n: number, format: string): boolean {\n const line = lines[n - 1];\n return line !== undefined && isMarkerLine(line, format);\n}\n\n/** The run of marker-only lines that holds `line`. */\nexport function markerRunAt(\n lines: readonly string[],\n line: number,\n format: string,\n bodyLine: number,\n): PageLines {\n let start = line;\n while (start - 1 >= bodyLine && markerAt(lines, start - 1, format)) start--;\n let end = line;\n while (end + 1 <= lines.length && markerAt(lines, end + 1, format)) end++;\n return { start, end };\n}\n\n/**\n * The paragraph a run splits, in file lines, marker lines included.\n * `undefined` when the run sits where `add` writes markers: after a blank\n * line, a fence, a bound line, or the body's first line.\n */\nexport function splitUnit(\n lines: readonly string[],\n run: PageLines,\n format: string,\n bodyLine: number,\n): PageLines | undefined {\n if (run.start - 1 < bodyLine) return undefined;\n if (!isUnitText(lines[run.start - 2], format)) return undefined;\n if (!isUnitText(lines[run.end], format)) return undefined;\n let start = run.start - 1;\n while (start - 1 >= bodyLine && isUnitText(lines[start - 2], format)) start--;\n let end = run.end + 1;\n while (end + 1 <= lines.length && isUnitText(lines[end], format)) end++;\n return { start, end };\n}\n\n/**\n * The span a marker was pinned over before PR #43: from the line below it\n * through the next blank line or fence, marker lines included. `undefined`\n * when the line below is blank or a fence, so the old reading covered nothing.\n */\nexport function pre43Span(\n lines: readonly string[],\n markerLine: number,\n): PageLines | undefined {\n const start = markerLine + 1;\n const first = lines[start - 1];\n if (first === undefined || first.trim() === \"\" || ANY_FENCE.test(first)) return undefined;\n let end = start;\n while (end + 1 <= lines.length) {\n const next = lines[end];\n if (next === undefined || next.trim() === \"\" || ANY_FENCE.test(next)) break;\n end++;\n }\n return { start, end };\n}\n\n/** One marker line that splits a paragraph. */\nexport interface MisplacedMarker {\n /** File line of the marker. */\n line: number;\n /** The whole run of marker-only lines it belongs to. */\n run: PageLines;\n /** Its position in that run, counted from zero, so stacked markers keep their order. */\n order: number;\n /** The paragraph the run splits, in file lines as the page reads now. */\n unit: PageLines;\n /** The file line the marker belongs above. */\n place: number;\n /** Whether `place` is a fenced block the entry quotes rather than the unit's first line. */\n block: boolean;\n /** The file line the marker takes once the whole run has moved. */\n to: number;\n /** The entry the marker names, when one is anchored by it. */\n entry?: PageCitation;\n}\n\n/** The lines of a run, which is `end - start + 1` markers. */\nfunction runLength(run: PageLines): number {\n return run.end - run.start + 1;\n}\n\n/** Whether a misplaced marker at `line` splits a paragraph, and where it belongs. */\nexport function misplacedMarkerAt(\n page: PageCitations,\n lines: readonly string[],\n line: number,\n entry?: PageCitation,\n): MisplacedMarker | undefined {\n if (!markerAt(lines, line, page.format)) return undefined;\n const run = markerRunAt(lines, line, page.format, page.bodyLine);\n const unit = splitUnit(lines, run, page.format, page.bodyLine);\n if (unit === undefined) return undefined;\n const order = line - run.start;\n const quote = entry?.citation.quote === true;\n const marker = entry?.marker;\n const blockAt =\n quote && marker !== undefined\n ? anchoredLines(page.content, marker.end, page.format, true)?.start\n : undefined;\n const out: MisplacedMarker = blockAt === undefined\n ? { line, run, order, unit, place: unit.start, block: false, to: unit.start + order }\n : {\n line,\n run,\n order,\n unit,\n place: blockAt,\n block: true,\n to: blockAt - runLength(run) + order,\n };\n if (entry !== undefined) out.entry = entry;\n return out;\n}\n\n/**\n * Every misplaced marker on a page, in the order the page reads. An orphan,\n * repeated or invalid marker is reported like any other: it splits the\n * paragraph whether or not it names an entry.\n */\nexport function misplacedMarkers(\n page: PageCitations,\n lines: readonly string[],\n): MisplacedMarker[] {\n const out: MisplacedMarker[] = [];\n for (const statement of page.statements.slice(0, MAX_MARKERS_PER_PAGE)) {\n const entry = page.citations.find((c) => c.marker?.line === statement.line);\n const found = misplacedMarkerAt(page, lines, statement.line, entry);\n if (found !== undefined) out.push(found);\n }\n return out;\n}\n\n/**\n * The span the pin covers once a misplaced run has moved: the joined unit,\n * pushed down by the markers now above it. A quote marker's pin covers its\n * block, which no move touches, so this is never asked of one.\n */\nexport function movedUnit(misplaced: MisplacedMarker): PageLines {\n return { start: misplaced.unit.start + runLength(misplaced.run), end: misplaced.unit.end };\n}\n\n/** The unit's text, the run's marker lines left out: what the pin covers after the move. */\nexport function unitText(lines: readonly string[], misplaced: MisplacedMarker): string[] {\n const { unit, run } = misplaced;\n const out: string[] = [];\n for (let n = unit.start; n <= unit.end; n++) {\n if (n >= run.start && n <= run.end) continue;\n const line = lines[n - 1];\n if (line !== undefined) out.push(line);\n }\n return out;\n}\n\n/** One marker line a rewrite moves, and the file line it goes above. */\nexport interface MarkerMove {\n from: number;\n place: number;\n}\n\n/** A page with its markers moved, and where its lines went. */\nexport interface MovedPage {\n content: string;\n /** The new file line of an old one. */\n line(old: number): number;\n}\n\n/** A page split into line texts and the terminator each position carries. */\nfunction splitKeepingEol(content: string): { texts: string[]; eols: string[] } {\n const parts = content.match(/[^\\n]*\\n|[^\\n]+$/g) ?? [];\n const texts: string[] = [];\n const eols: string[] = [];\n for (const part of parts) {\n const eol = /\\r?\\n$/.exec(part)?.[0] ?? \"\";\n texts.push(part.slice(0, part.length - eol.length));\n eols.push(eol);\n }\n return { texts, eols };\n}\n\n/**\n * The page with each named marker line lifted out and written above its place,\n * in the order the moves are given, so a run that was stacked stays stacked.\n * A moved marker takes the indentation `add` would write it at, and the file's\n * terminators stay where they are: the lines are permuted, never re-joined.\n *\n * Read the join carefully. A line's text comes from where it was, and its\n * terminator from where it now sits. That asymmetry is deliberate: the last\n * position of a page with no final newline carries no terminator, and it has\n * to stay the last position. Were terminators to travel with their lines, a\n * move that lifted that last line would carry the missing terminator into the\n * middle of the page and glue two lines together.\n *\n * The cost is that a page mixing `\\r\\n` and `\\n` has the endings of the two\n * swapped positions trade places. No byte is gained or lost, and the file\n * still ends as it began. A uniform page, which is what a checkout gives,\n * cannot tell the difference.\n */\nexport function applyMarkerMoves(\n content: string,\n moves: readonly MarkerMove[],\n indentAt: (line: number) => string,\n): MovedPage {\n const { texts, eols } = splitKeepingEol(content);\n const moving = new Set(moves.map((move) => move.from));\n const inserts = new Map<number, number[]>();\n for (const move of moves) {\n const list = inserts.get(move.place) ?? [];\n list.push(move.from);\n inserts.set(move.place, list);\n }\n const order: number[] = [];\n for (let n = 1; n <= texts.length; n++) {\n for (const from of inserts.get(n) ?? []) order.push(from);\n if (!moving.has(n)) order.push(n);\n }\n const moved = new Map<number, string>();\n for (const move of moves) {\n moved.set(move.from, indentAt(move.place) + (texts[move.from - 1] ?? \"\").trim());\n }\n const at = new Map<number, number>();\n order.forEach((old, index) => at.set(old, index + 1));\n const out = order\n .map((old, index) => (moved.get(old) ?? texts[old - 1] ?? \"\") + (eols[index] ?? \"\"))\n .join(\"\");\n return { content: out, line: (old) => at.get(old) ?? old };\n}\n\n/** The plain pin of a span of lines, or of an explicit list of them. */\nfunction pinOf(lines: readonly string[], span: PageLines): string | undefined {\n if (span.start < 1 || span.end > lines.length || span.end < span.start) return undefined;\n return hashLines(lines.slice(span.start - 1, span.end).join(\"\\n\"));\n}\n\n/**\n * The claim end of a marker-anchored entry, read against proposal 0054's\n * three spans. `misplaced` is the marker's misplacement, when it has one.\n *\n * For a misplaced marker at `moved`, `fileLines` is the span that held and\n * `newLines` the span the pin will cover once the marker moves. Both are file\n * lines: a marker-anchored claim has no body lines of its own.\n */\nexport function markerClaimEnd(\n page: PageCitations,\n entry: PageCitation,\n lines: readonly string[],\n misplaced: MisplacedMarker | undefined,\n): ClaimEnd {\n const { citation, marker } = entry;\n const pin = citation.claim?.integrity;\n const quote = citation.quote === true;\n if (marker === undefined || pin === undefined) return { status: \"changed\" };\n const current = anchoredLines(page.content, marker.end, page.format, quote);\n if (current === undefined) return { status: \"changed\" };\n\n /** The claim end this span reads as, and where the move will take it. */\n const claimAt = (span: PageLines, status: ClaimEnd[\"status\"], to?: PageLines): ClaimEnd => {\n const end: ClaimEnd = { fileLines: spellLines(span), status };\n if (to !== undefined) {\n end.newLines = spellLines(to);\n end.newFileLines = end.newLines;\n }\n if (status === \"changed\") end.text = lines.slice(span.start - 1, Math.min(span.end, lines.length));\n return end;\n };\n\n // A quote marker's pin covers its block, which no move touches, and the\n // block reading never changed, so there is one span to read it against.\n if (quote) {\n return claimAt(current, pinOf(lines, current) === pin ? \"current\" : \"changed\");\n }\n\n if (misplaced !== undefined) {\n const to = movedUnit(misplaced);\n if (hashLines(unitText(lines, misplaced).join(\"\\n\")) === pin) return claimAt(to, \"current\");\n if (pinOf(lines, current) === pin) return claimAt(current, \"moved\", to);\n const pre43 = pre43Span(lines, marker.line);\n if (pre43 !== undefined && pinOf(lines, pre43) === pin) return claimAt(pre43, \"moved\", to);\n return claimAt(current, \"changed\");\n }\n\n if (pinOf(lines, current) === pin) return claimAt(current, \"current\");\n // Stacked markers written before PR #43 were pinned over a sibling marker\n // line and the paragraph. That renders fine, so only the pin is repaired.\n const pre43 = pre43Span(lines, marker.line);\n if (pre43 !== undefined && pinOf(lines, pre43) === pin) return claimAt(pre43, \"moved\", current);\n return claimAt(current, \"changed\");\n}\n","/**\n * The claim end: the page text a citation supports, classified by the same\n * machinery as the source end and against the page as it is now.\n *\n * The claim's lines are body-relative, so editing the frontmatter never moves\n * them; every line a person reads is a file line, translated here. The pin\n * holds at the recorded lines: `current`. The same text is found verbatim\n * elsewhere in the body: `moved`, once, or `moved-ambiguous`. Nowhere:\n * `changed`, the sentence was edited. A marker-anchored claim pins what the\n * marker anchors, so its text never moves on the page; it is `current`,\n * `changed`, or, when the pin holds over a span the marker no longer anchors,\n * `moved`. `src/cite/core/reanchor.ts` reads those spans.\n */\nimport type {\n ClaimEnd,\n PageCitation,\n PageCitations,\n PageLines,\n} from \"../types.js\";\nimport {\n findWindows,\n parseLines,\n pinOfLines,\n spellLines,\n toBodyLines,\n toFileLines,\n} from \"../../shared/pin.js\";\nimport {\n markerClaimEnd,\n misplacedMarkerAt,\n type MisplacedMarker,\n} from \"./reanchor.js\";\nimport {\n anchoredLines,\n fenceAround,\n fenceSpanAt,\n isMarkerLine,\n isTableRow,\n isTableSeparator,\n lineAt,\n offsetOfLine,\n paragraphAfter,\n} from \"./statements.js\";\n\n// The line translation and the claim pin are the shared pin engine's; this path keeps cite's imports working.\nexport { pinOfLines, toBodyLines, toFileLines } from \"../../shared/pin.js\";\n\nexport function normalizeWhitespace(text: string): string {\n return text.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * The hashing rule's normalization for a whole quoted block: one BOM, CRLF →\n * LF, and one trailing LF dropped. It differs from the shared `normalizeText`\n * only in that last step, because a quote is compared as one joined block\n * rather than split into lines first.\n */\nfunction normalizeBlock(text: string): string {\n let out = text.charCodeAt(0) === 0xfeff ? text.slice(1) : text;\n out = out.replace(/\\r\\n/g, \"\\n\");\n return out.endsWith(\"\\n\") ? out.slice(0, -1) : out;\n}\n\n/** `true` when the block's normalized text equals the cited lines under the hashing rule. */\nexport function blockMatches(blockText: string, citedJoined: string): boolean {\n return normalizeBlock(blockText) === normalizeBlock(citedJoined);\n}\n\n/** The page lines a range covers, as far as the page reaches. */\nfunction textAt(lines: readonly string[], range: PageLines): string[] {\n return lines.slice(range.start - 1, Math.min(range.end, lines.length));\n}\n\n/** The first file line of a classified claim: where its findings sit. */\nexport function claimLine(claim: ClaimEnd): number | undefined {\n const at = claim.fileLines === undefined ? undefined : parseLines(claim.fileLines);\n return at?.start;\n}\n\n/** Where the claim is now: the moved-to lines when it moved, else the recorded ones. */\nexport function claimLineNow(claim: ClaimEnd): number | undefined {\n const spec = claim.newFileLines ?? claim.candidateFileLines?.[0] ?? claim.fileLines;\n const at = spec === undefined ? undefined : parseLines(spec);\n return at?.start;\n}\n\n/** The file lines the claim occupies now, for the quote check. */\nexport function claimLinesNow(claim: ClaimEnd): PageLines | undefined {\n const spec = claim.newFileLines ?? claim.candidateFileLines?.[0] ?? claim.fileLines;\n return spec === undefined ? undefined : parseLines(spec);\n}\n\n/**\n * Classify one entry's claim end against the page. `lines` is the page under\n * the hashing rule (`splitLines`). `null` for an entry with no `claim`: a\n * bare pin, or a marker with no drift check on its sentence.\n */\nexport function claimEnd(\n page: PageCitations,\n entry: PageCitation,\n lines: readonly string[],\n misplaced?: MisplacedMarker,\n): ClaimEnd | null {\n const { citation, marker } = entry;\n const claim = citation.claim;\n if (claim === undefined) return null;\n const body = page.bodyLine;\n\n if (claim.lines !== undefined) {\n const recorded = parseLines(claim.lines);\n // An unreadable range is `entry-invalid`, and that entry is never classified.\n if (recorded === undefined) return { status: \"skipped\" };\n const file = toFileLines(recorded, body);\n const end: ClaimEnd = {\n lines: spellLines(recorded),\n fileLines: spellLines(file),\n status: \"changed\",\n };\n // Lines and a marker both: `anchor-invalid`, and neither anchor is judged.\n if (marker !== undefined) return { ...end, status: \"skipped\" };\n if (pinOfLines(lines, file) === claim.integrity) return { ...end, status: \"current\" };\n\n const width = recorded.end - recorded.start + 1;\n const found = findWindows(lines.slice(body - 1), width, claim.integrity, undefined, {\n around: recorded.start,\n });\n const spans = found.starts.map((start) => ({ start, end: start + width - 1 }));\n const [only] = spans;\n if (spans.length === 1 && only !== undefined) {\n return {\n ...end,\n status: \"moved\",\n newLines: spellLines(only),\n newFileLines: spellLines(toFileLines(only, body)),\n };\n }\n if (spans.length > 1) {\n return {\n ...end,\n status: \"moved-ambiguous\",\n candidates: spans.map(spellLines),\n candidateFileLines: spans.map((span) => spellLines(toFileLines(span, body))),\n };\n }\n return { ...end, text: textAt(lines, file) };\n }\n\n if (marker !== undefined) {\n // The marker travels with its text, so what moves is the span the marker\n // anchors, not the text. `reanchor.ts` reads the three spans.\n return markerClaimEnd(\n page,\n entry,\n lines,\n misplaced ?? misplacedMarkerAt(page, lines, marker.line, entry),\n );\n }\n\n // A claim pin with neither lines nor a marker anchors nothing at all.\n return { status: \"changed\" };\n}\n\n/**\n * Where else in the body the claim's text sits, as file lines. A claim whose\n * text repeats is `moved-ambiguous` the moment it moves, so `add` says so\n * while the pin is still being written, and `update --accept` says so before\n * it mints a pin that cannot tell two copies apart. The search is the\n * classifier's own.\n */\nexport function otherClaimSpans(\n lines: readonly string[],\n pageLines: PageLines,\n pin: string,\n bodyLine: number,\n): PageLines[] {\n const width = pageLines.end - pageLines.start + 1;\n const found = findWindows(lines.slice(bodyLine - 1), width, pin, undefined, {\n around: toBodyLines(pageLines, bodyLine).start,\n });\n return found.starts\n .map((start) => toFileLines({ start, end: start + width - 1 }, bodyLine))\n .filter((span) => span.start !== pageLines.start);\n}\n\n/** How many other locations a notice names before it starts counting them. */\nconst NAMED_SPANS = 3;\n\n/** `line 17`, `lines 16 and 18`, `lines 16, 18, 20 and 2 more`. */\nexport function spellElsewhere(spans: readonly PageLines[]): string {\n const first = spans[0];\n const noun = spans.length === 1 && first !== undefined && first.start === first.end ? \"line\" : \"lines\";\n const named = spans.slice(0, NAMED_SPANS).map((span) => spellLines(span));\n const rest = spans.length - named.length;\n if (rest > 0) return `${noun} ${named.join(\", \")} and ${String(rest)} more`;\n const last = named.pop() ?? \"\";\n return named.length === 0 ? `${noun} ${last}` : `${noun} ${named.join(\", \")} and ${last}`;\n}\n\n/**\n * What `update --accept` re-pins over: the paragraph, whole fenced block, or\n * lines inside a fenced block at a line.\n *\n * The three kinds are not interchangeable. `\"block\"` covers a fence, its\n * content and its closing fence, which is the only shape a `quote: true`\n * entry may hold. `\"fenced-lines\"` covers content lines inside a block and\n * neither fence, which is what a claim minted over part of a code sample\n * holds. `\"paragraph\"` covers prose, and table rows too, since `ClaimUnit`\n * draws no line between them.\n */\nexport interface ClaimUnit {\n lines: PageLines;\n kind: \"paragraph\" | \"block\" | \"fenced-lines\";\n text: string[];\n}\n\n/**\n * Why no unit sits at a file line. Each one is a different problem with a\n * different repair, so `update --accept` names which it hit rather than\n * leaving the entry skipped with no reason.\n */\nexport type NoUnit =\n | \"outside\"\n | \"blank\"\n | \"fence-crossed\"\n | \"marker\"\n | \"not-a-paragraph\"\n | \"table-short\"\n | \"table-rule\";\n\n/**\n * The span a claim of the recorded width holds at a line. A unit whose extent\n * is the author's, rather than the page's, keeps the number of lines it was\n * minted over: table rows and lines inside a fenced block both. One recorded\n * line gives one line, and five give five.\n */\nfunction spanOf(line: number, recorded: PageLines | undefined): PageLines {\n const width = recorded === undefined ? 1 : Math.max(1, recorded.end - recorded.start + 1);\n return { start: line, end: line + width - 1 };\n}\n\n/**\n * The rows a claim on a table re-pins over, or why there are none.\n *\n * A row is a statement, so a claim over N rows is a claim over N statements.\n * The extent is the author's, and re-pinning re-mints the hash over it rather\n * than redesigning it: one recorded line gives one row, and five give five.\n * Rows below a one-line claim are other statements, and a table that no longer\n * reaches the recorded end is a question only the author can answer.\n *\n * The unit comes back as `kind: \"paragraph\"`, since `ClaimUnit` names how a\n * unit is bounded and not what it holds. A caller wanting to know whether it\n * holds rows has to ask `isTableRow` about the text, not read `kind`.\n *\n * A span of nothing but `|---|---|` rules is refused. Those lines carry no\n * words, so a pin over them says nothing about what the page claims, and a\n * claim that shifted onto one is a claim the page lost. A header, its rule and\n * a body row is three rows and keeps all three.\n */\nfunction rowsAt(\n line: number,\n lines: readonly string[],\n recorded: PageLines | undefined,\n named: boolean,\n): ClaimUnit | NoUnit {\n const end = spanOf(line, recorded).end;\n if (end > lines.length) return \"table-short\";\n for (let n = line; n <= end; n++) {\n if (!isTableRow(lines[n - 1] ?? \"\")) return \"table-short\";\n }\n const text = lines.slice(line - 1, end);\n if (!named && text.every((row) => isTableSeparator(row))) return \"table-rule\";\n return { lines: { start: line, end }, kind: \"paragraph\", text };\n}\n\n/**\n * The unit at a file line, or why there is none. `unitAt` and `noUnitAt` are\n * the two halves a caller reads, so the guards are written once. `recorded` is\n * the span the claim holds now, which only a table reads. `named` is the\n * operator having named the entry with `--only`: the structural refusals a\n * blanket accept would hit are the ones they have looked at, so they stand\n * down and the line is read as the text it is.\n */\nfunction unitOrWhy(\n page: PageCitations,\n line: number,\n lines: readonly string[],\n recorded?: PageLines,\n named = false,\n): ClaimUnit | NoUnit {\n if (line < page.bodyLine || line > lines.length) return \"outside\";\n const own = lines[line - 1] ?? \"\";\n if (own.trim() === \"\") return \"blank\";\n // A line that is one marker and nothing else is another entry's anchor, not\n // claim text. Reading it as text is how a shifted claim gets a confident pin\n // over a comment.\n const marker = isMarkerLine(own, page.format);\n if (marker && !named) return \"marker\";\n const block = fenceSpanAt(page.content, line, page.format);\n if (block !== undefined) {\n return { lines: block, kind: \"block\", text: lines.slice(block.start - 1, block.end) };\n }\n const around = fenceAround(page.content, page.bodyOffset, line, page.format);\n if (around !== undefined) {\n // The claim was minted over lines inside this block, so it is re-pinned\n // over as many lines as it recorded, at the line it starts on. Re-pinning\n // the block around them would widen what the pin covers, which is the one\n // thing an accept may never do. A span reaching the closing fence, or past\n // it, is not lines inside a block at all, and stays refused.\n const span = spanOf(line, recorded);\n return span.end < around.end\n ? { lines: span, kind: \"fenced-lines\", text: lines.slice(span.start - 1, span.end) }\n : \"fence-crossed\";\n }\n // A table row is a statement of its own, and nothing between two rows ends a\n // paragraph, so the walk below would read the rest of the table as one.\n if (isTableRow(own)) return rowsAt(line, lines, recorded, named);\n // The format ends the paragraph at a marker under it, so a re-pin never\n // swallows another entry's anchor. A named entry sitting on a marker is read\n // without it, because there the marker is the line being accepted.\n const paragraph = paragraphAfter(\n page.content,\n offsetOfLine(page.content, line),\n marker ? undefined : page.format,\n );\n if (paragraph === undefined || paragraph.line !== line) return \"not-a-paragraph\";\n const span: PageLines = { start: line, end: lineAt(page.content, paragraph.end) };\n return { lines: span, kind: \"paragraph\", text: lines.slice(span.start - 1, span.end) };\n}\n\n/**\n * The paragraph, fenced block, fenced lines or table rows at a file line.\n * Undefined when the line holds no claim at all: it is blank, outside the\n * body, another entry's marker, a table rule, or a line whose claim runs out\n * of the fenced block it starts in. Those are the claims `update --accept`\n * skips, and `noUnitAt` says which of them it is.\n *\n * A paragraph runs from this line to its end, not from the paragraph's own\n * first line. The line asked about is the claim's first line, and re-pinning\n * has to leave that where it is, so a claim that started mid-paragraph keeps\n * starting there. A paragraph that gained a sentence gained it as part of the\n * same statement, which is why a claim grows with it.\n *\n * A table does not work that way. Each row is a statement, so a claim keeps\n * the number of rows `recorded` gives it, and refuses when the table no longer\n * reaches that far. Callers that know the claim's current span pass it.\n */\nexport function unitAt(\n page: PageCitations,\n line: number,\n lines: readonly string[],\n recorded?: PageLines,\n named = false,\n): ClaimUnit | undefined {\n const found = unitOrWhy(page, line, lines, recorded, named);\n return typeof found === \"string\" ? undefined : found;\n}\n\n/** Why `unitAt` found nothing at a file line, or undefined when it found a unit. */\nexport function noUnitAt(\n page: PageCitations,\n line: number,\n lines: readonly string[],\n recorded?: PageLines,\n named = false,\n): NoUnit | undefined {\n const found = unitOrWhy(page, line, lines, recorded, named);\n return typeof found === \"string\" ? found : undefined;\n}\n\n/** The lines a marker anchors now, for `update --accept` on a marker-anchored claim. */\nexport function markerUnit(\n page: PageCitations,\n entry: PageCitation,\n lines: readonly string[],\n): ClaimUnit | undefined {\n const { marker, citation } = entry;\n if (marker === undefined) return undefined;\n const span = anchoredLines(page.content, marker.end, page.format, citation.quote === true);\n if (span === undefined || span.end > lines.length) return undefined;\n return {\n lines: span,\n kind: citation.quote === true ? \"block\" : \"paragraph\",\n text: lines.slice(span.start - 1, span.end),\n };\n}\n"],"mappings":"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","names":["at","pre43","at","named","span","at","rule"]}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ var __defProp = Object.defineProperty;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: true });
6
+ };
7
+
8
+ export {
9
+ __export
10
+ };
11
+ //# sourceMappingURL=chunk-2H7UOFLK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,230 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ TERM_FIELDS,
4
+ displayPath,
5
+ plural
6
+ } from "./chunk-WQE54PNH.js";
7
+ import {
8
+ palette
9
+ } from "./chunk-RNVYGWIC.js";
10
+
11
+ // src/term/reporters/pretty.ts
12
+ var WIDTH = 80;
13
+ function wrapWords(text, width) {
14
+ const lines = [];
15
+ let line = "";
16
+ for (const word of text.split(/\s+/).filter((w) => w !== "")) {
17
+ if (line === "") line = word;
18
+ else if (line.length + 1 + word.length <= width) line = `${line} ${word}`;
19
+ else {
20
+ lines.push(line);
21
+ line = word;
22
+ }
23
+ }
24
+ if (line !== "") lines.push(line);
25
+ return lines.length === 0 ? [""] : lines;
26
+ }
27
+ function wrapSentences(text, width) {
28
+ if (text.length <= width) return [text];
29
+ const lines = [];
30
+ let line = "";
31
+ for (const sentence of text.split(/(?<=\.)\s+(?=\S)/)) {
32
+ if (line === "") line = sentence;
33
+ else if (line.length + 1 + sentence.length <= width) line = `${line} ${sentence}`;
34
+ else {
35
+ lines.push(line);
36
+ line = sentence;
37
+ }
38
+ }
39
+ if (line !== "") lines.push(line);
40
+ return lines;
41
+ }
42
+ function hanging(first, lines) {
43
+ const indent = " ".repeat(first.length);
44
+ return lines.map((line, i) => `${i === 0 ? first : indent}${line}`.trimEnd());
45
+ }
46
+ function renderListPretty(terms) {
47
+ const idWidth = Math.max(0, ...terms.map((t) => t.id.length)) + 3;
48
+ const labelWidth = Math.max(0, ...terms.map((t) => t.record.label.length)) + 3;
49
+ const rows = terms.map(
50
+ (t) => `${t.id.padEnd(idWidth)}${t.record.label.padEnd(labelWidth)}${(t.record["alt-labels"] ?? []).join(", ")}`.trimEnd()
51
+ );
52
+ return [...rows, plural(terms.length, "term")].join("\n");
53
+ }
54
+ var GET_FIELDS = [
55
+ "alt-labels",
56
+ "hidden-labels",
57
+ "broader",
58
+ "narrower",
59
+ "related-terms",
60
+ "see",
61
+ "abstract",
62
+ "scope-note",
63
+ "definition"
64
+ ];
65
+ var KEY_WIDTH = Math.max("language".length, ...TERM_FIELDS.map((f) => f.length)) + 2;
66
+ function renderGetPretty(term, opts) {
67
+ const c = palette(opts.color);
68
+ const where = `${displayPath(term.location.file, opts.cwd ?? process.cwd())}:${String(term.location.line)}`;
69
+ const lines = [`${c.bold(term.record.label.padEnd(40))}${c.dim(where)}`];
70
+ const row = (key, value) => {
71
+ const prefix = ` ${key.padEnd(KEY_WIDTH)}`;
72
+ lines.push(...hanging(prefix, wrapWords(value, WIDTH - prefix.length)));
73
+ };
74
+ row("id", term.id);
75
+ if (term.language !== void 0) row("language", term.language);
76
+ for (const field of GET_FIELDS) {
77
+ const value = term.record[field];
78
+ if (value === void 0) continue;
79
+ row(field, typeof value === "string" ? value : value.join(", "));
80
+ }
81
+ return lines.join("\n");
82
+ }
83
+ var RULE_WIDTH = 32;
84
+ function severityText(c, severity) {
85
+ const padded = severity.padEnd(6);
86
+ if (severity === "error") return c.red(padded);
87
+ if (severity === "warning") return c.yellow(padded);
88
+ return c.cyan(padded);
89
+ }
90
+ function counts(findings) {
91
+ const parts = [];
92
+ const n = (severity) => findings.filter((f) => f.severity === severity).length;
93
+ if (n("error") > 0) parts.push(plural(n("error"), "error"));
94
+ if (n("warning") > 0) parts.push(plural(n("warning"), "warning"));
95
+ if (n("notice") > 0) parts.push(plural(n("notice"), "notice"));
96
+ return parts.join(", ");
97
+ }
98
+ function renderFindingsPretty(report, opts) {
99
+ const c = palette(opts.color);
100
+ const { baseline } = report;
101
+ if (baseline?.written === true) {
102
+ return `${c.green("\u2713")} ${plural(report.found, "finding")} recorded in ${baseline.path}`;
103
+ }
104
+ const baselined = baseline !== void 0 && baseline.suppressed > 0 ? `, ${String(baseline.suppressed)} baselined` : "";
105
+ const terms = plural(report.terms, "term");
106
+ if (report.findings.length === 0) {
107
+ const references = opts.references === false ? "" : `, ${plural(report.references, "reference")}`;
108
+ return `${c.green("\u2713")} ${terms}${references}, no findings${baselined}`;
109
+ }
110
+ const ruleWidth = Math.max(RULE_WIDTH, ...report.findings.map((f) => f.ruleId.length + 2));
111
+ const lines = [];
112
+ let group;
113
+ for (const finding of report.findings) {
114
+ const file = displayPath(finding.file, report.cwd);
115
+ const header = finding.line === void 0 ? file : `${file}:${String(finding.line)}`;
116
+ if (header !== group) {
117
+ lines.push(c.bold(header));
118
+ group = header;
119
+ }
120
+ const prefixWidth = 2 + 6 + 1 + ruleWidth;
121
+ const message = wrapSentences(finding.message, WIDTH - prefixWidth);
122
+ const indent = " ".repeat(prefixWidth);
123
+ message.forEach((text, i) => {
124
+ lines.push(
125
+ i === 0 ? ` ${severityText(c, finding.severity)} ${finding.ruleId.padEnd(ruleWidth)}${text}` : `${indent}${text}`
126
+ );
127
+ });
128
+ }
129
+ lines.push("", `${counts(report.findings)} in ${terms}${baselined}`);
130
+ return lines.join("\n");
131
+ }
132
+ function changeLine(change) {
133
+ switch (change.action) {
134
+ case "create":
135
+ return `${change.path} would be created`;
136
+ case "change":
137
+ return `${change.path} would change`;
138
+ case "remove":
139
+ return `${change.path} would be removed`;
140
+ }
141
+ }
142
+ function swapCount(content) {
143
+ const lines = content.split(/\r?\n/);
144
+ const start = lines.indexOf("swap:");
145
+ if (start === -1) return 0;
146
+ return lines.slice(start + 1).filter((line) => line.startsWith(" ")).length;
147
+ }
148
+ function baseName(path) {
149
+ return path.split(/[\\/]/).pop() ?? path;
150
+ }
151
+ var CASING_RULES = /* @__PURE__ */ new Set(["Casing.yml", "Lowercase.yml", "SentenceStart.yml"]);
152
+ function valeLines(report) {
153
+ const rows = [];
154
+ const acronyms = [];
155
+ for (const file of report.files) {
156
+ const name = baseName(file.path);
157
+ if (CASING_RULES.has(name)) rows.push([name, plural(swapCount(file.content), "label")]);
158
+ else if (name === "Deprecated.yml") rows.push([name, plural(swapCount(file.content), "swap")]);
159
+ else acronyms.push(name);
160
+ }
161
+ if (acronyms.length > 0) rows.push([acronyms.join(", "), plural(acronyms.length, "acronym")]);
162
+ const width = Math.max(0, ...rows.map(([name]) => name.length)) + 2;
163
+ return rows.map(([name, what]) => ` ${name.padEnd(width)}${what}`);
164
+ }
165
+ function droppedLine(report) {
166
+ if (report.dropped.length === 0) return void 0;
167
+ const ids = /* @__PURE__ */ new Map();
168
+ for (const { id, field } of report.dropped) {
169
+ const set = ids.get(field) ?? /* @__PURE__ */ new Set();
170
+ set.add(id);
171
+ ids.set(field, set);
172
+ }
173
+ const fields = [...ids.entries()].map(([field, set]) => ({ field, n: set.size })).sort((a, b) => a.n - b.n || TERM_FIELDS.indexOf(a.field) - TERM_FIELDS.indexOf(b.field));
174
+ const parts = fields.map(({ field, n }, i) => `${field} on ${i === 0 ? plural(n, "term") : String(n)}`);
175
+ return ` dropped from ${report.droppedFrom ?? report.format ?? "the render"}: ${parts.join(", ")}`;
176
+ }
177
+ function skippedLine(report) {
178
+ if (report.skipped.length === 0) return void 0;
179
+ const construct = report.droppedFrom ?? report.format ?? "the render";
180
+ const count = plural(report.skipped.length, "term");
181
+ return ` skipped ${count} ${construct} cannot read without a definition: ${report.skipped.join(", ")}`;
182
+ }
183
+ function renderNotes(report) {
184
+ return [droppedLine(report), skippedLine(report)].filter((line) => line !== void 0);
185
+ }
186
+ function unchangedLine(report) {
187
+ return report.mode === "in-place" ? "Nothing to write" : `${report.target ?? ""} is up to date`;
188
+ }
189
+ function renderWritePretty(report) {
190
+ if (report.check) {
191
+ return report.changes.length > 0 ? report.changes.map(changeLine).join("\n") : unchangedLine(report);
192
+ }
193
+ if (report.dryRun) {
194
+ const changes = report.changes.length > 0 ? report.changes.map(changeLine) : [unchangedLine(report)];
195
+ return [...changes, ...renderNotes(report)].join("\n");
196
+ }
197
+ if (report.mode === "in-place") {
198
+ return report.changes.length === 0 ? "Nothing to write" : `Wrote ${plural(report.changes.length, "file")}`;
199
+ }
200
+ const each = report.shape === "directory" && report.format !== "vale" ? ", one file each" : "";
201
+ const written = report.terms - report.skipped.length;
202
+ const lines = [`Wrote ${plural(written, "term")} to ${report.target ?? ""}${each}`];
203
+ if (report.format === "vale") lines.push(...valeLines(report));
204
+ lines.push(...renderNotes(report));
205
+ return lines.join("\n");
206
+ }
207
+ function renderValeWiring(wiring) {
208
+ return [
209
+ wiring.addSection ? `notice: ${wiring.rootIni} has no section with BasedOnStyles. Add one that uses the Terms style:` : `notice: no section of ${wiring.rootIni} uses the Terms style. Add it to BasedOnStyles:`,
210
+ ` [${wiring.section}]`,
211
+ ` BasedOnStyles = ${wiring.styles.join(", ")}`
212
+ ].join("\n");
213
+ }
214
+ function renderFormatsPretty(rows) {
215
+ const formatWidth = Math.max(0, ...rows.map((r) => r.format.length)) + 3;
216
+ const labelWidth = Math.max(0, ...rows.map((r) => r.label.length)) + 3;
217
+ return rows.map(
218
+ (r) => `${r.format.padEnd(formatWidth)}${r.label.padEnd(labelWidth)}${r.read ? "read " : " "}${r.write ? "write" : ""}`.trimEnd()
219
+ ).join("\n");
220
+ }
221
+
222
+ export {
223
+ renderListPretty,
224
+ renderGetPretty,
225
+ renderFindingsPretty,
226
+ renderWritePretty,
227
+ renderValeWiring,
228
+ renderFormatsPretty
229
+ };
230
+ //# sourceMappingURL=chunk-2U3ORT6D.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/term/reporters/pretty.ts"],"sourcesContent":["/**\n * Human output for every `manni term` command, in the shapes the ladder of\n * proposal 0052 prints. Columns are padded to their widest value; prose wraps\n * to 80 columns under its own column, so a long definition or message never\n * runs back to the left edge.\n */\nimport { palette, type Colors } from \"../../shared/color.js\";\nimport type { TermReport } from \"../commands/findings.js\";\nimport type { FormatRow } from \"../commands/formats.js\";\nimport { displayPath, plural } from \"../commands/run.js\";\nimport type { ValeWiring, WriteReport } from \"../commands/write.js\";\nimport type { Severity } from \"../../shared/severity.js\";\nimport { TERM_FIELDS, type Term, type TermField, type TermFinding } from \"../types.js\";\n\nconst WIDTH = 80;\n\n/** Words packed into lines of at most `width` characters; a longer word stands alone. */\nfunction wrapWords(text: string, width: number): string[] {\n const lines: string[] = [];\n let line = \"\";\n for (const word of text.split(/\\s+/).filter((w) => w !== \"\")) {\n if (line === \"\") line = word;\n else if (line.length + 1 + word.length <= width) line = `${line} ${word}`;\n else {\n lines.push(line);\n line = word;\n }\n }\n if (line !== \"\") lines.push(line);\n return lines.length === 0 ? [\"\"] : lines;\n}\n\n/** Sentences packed into lines of at most `width`; a message that fits stays whole. */\nfunction wrapSentences(text: string, width: number): string[] {\n if (text.length <= width) return [text];\n const lines: string[] = [];\n let line = \"\";\n for (const sentence of text.split(/(?<=\\.)\\s+(?=\\S)/)) {\n if (line === \"\") line = sentence;\n else if (line.length + 1 + sentence.length <= width) line = `${line} ${sentence}`;\n else {\n lines.push(line);\n line = sentence;\n }\n }\n if (line !== \"\") lines.push(line);\n return lines;\n}\n\nfunction hanging(first: string, lines: readonly string[]): string[] {\n const indent = \" \".repeat(first.length);\n return lines.map((line, i) => `${i === 0 ? first : indent}${line}`.trimEnd());\n}\n\n// ---------------------------------------------------------------------------\n// list\n\nexport function renderListPretty(terms: readonly Term[]): string {\n const idWidth = Math.max(0, ...terms.map((t) => t.id.length)) + 3;\n const labelWidth = Math.max(0, ...terms.map((t) => t.record.label.length)) + 3;\n const rows = terms.map((t) =>\n `${t.id.padEnd(idWidth)}${t.record.label.padEnd(labelWidth)}${(t.record[\"alt-labels\"] ?? []).join(\", \")}`.trimEnd(),\n );\n return [...rows, plural(terms.length, \"term\")].join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// get\n\n/** The order `get` shows fields in: names first, then what they mean, the definition last. */\nconst GET_FIELDS: readonly TermField[] = [\n \"alt-labels\",\n \"hidden-labels\",\n \"broader\",\n \"narrower\",\n \"related-terms\",\n \"see\",\n \"abstract\",\n \"scope-note\",\n \"definition\",\n];\n\nconst KEY_WIDTH = Math.max(\"language\".length, ...TERM_FIELDS.map((f) => f.length)) + 2;\n\nexport function renderGetPretty(term: Term, opts: { color: boolean; cwd?: string }): string {\n const c = palette(opts.color);\n const where = `${displayPath(term.location.file, opts.cwd ?? process.cwd())}:${String(term.location.line)}`;\n const lines = [`${c.bold(term.record.label.padEnd(40))}${c.dim(where)}`];\n const row = (key: string, value: string): void => {\n const prefix = ` ${key.padEnd(KEY_WIDTH)}`;\n lines.push(...hanging(prefix, wrapWords(value, WIDTH - prefix.length)));\n };\n row(\"id\", term.id);\n if (term.language !== undefined) row(\"language\", term.language);\n for (const field of GET_FIELDS) {\n const value = term.record[field];\n if (value === undefined) continue;\n row(field, typeof value === \"string\" ? value : value.join(\", \"));\n }\n return lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// check and lint\n\nconst RULE_WIDTH = 32;\n\nfunction severityText(c: Colors, severity: Severity): string {\n const padded = severity.padEnd(6);\n if (severity === \"error\") return c.red(padded);\n if (severity === \"warning\") return c.yellow(padded);\n return c.cyan(padded);\n}\n\nfunction counts(findings: readonly TermFinding[]): string {\n const parts: string[] = [];\n const n = (severity: Severity): number => findings.filter((f) => f.severity === severity).length;\n if (n(\"error\") > 0) parts.push(plural(n(\"error\"), \"error\"));\n if (n(\"warning\") > 0) parts.push(plural(n(\"warning\"), \"warning\"));\n if (n(\"notice\") > 0) parts.push(plural(n(\"notice\"), \"notice\"));\n return parts.join(\", \");\n}\n\nexport interface FindingsPrettyOptions {\n color: boolean;\n /** Whether the clean line counts references: `check` reads them, `lint` does not. */\n references?: boolean;\n}\n\nexport function renderFindingsPretty(report: TermReport, opts: FindingsPrettyOptions): string {\n const c = palette(opts.color);\n const { baseline } = report;\n if (baseline?.written === true) {\n return `${c.green(\"✓\")} ${plural(report.found, \"finding\")} recorded in ${baseline.path}`;\n }\n const baselined = baseline !== undefined && baseline.suppressed > 0 ? `, ${String(baseline.suppressed)} baselined` : \"\";\n const terms = plural(report.terms, \"term\");\n\n if (report.findings.length === 0) {\n const references = opts.references === false ? \"\" : `, ${plural(report.references, \"reference\")}`;\n return `${c.green(\"✓\")} ${terms}${references}, no findings${baselined}`;\n }\n\n const ruleWidth = Math.max(RULE_WIDTH, ...report.findings.map((f) => f.ruleId.length + 2));\n const lines: string[] = [];\n let group: string | undefined;\n for (const finding of report.findings) {\n const file = displayPath(finding.file, report.cwd);\n const header = finding.line === undefined ? file : `${file}:${String(finding.line)}`;\n if (header !== group) {\n lines.push(c.bold(header));\n group = header;\n }\n const prefixWidth = 2 + 6 + 1 + ruleWidth;\n const message = wrapSentences(finding.message, WIDTH - prefixWidth);\n const indent = \" \".repeat(prefixWidth);\n message.forEach((text, i) => {\n lines.push(\n i === 0 ? ` ${severityText(c, finding.severity)} ${finding.ruleId.padEnd(ruleWidth)}${text}` : `${indent}${text}`,\n );\n });\n }\n lines.push(\"\", `${counts(report.findings)} in ${terms}${baselined}`);\n return lines.join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// write\n\nfunction changeLine(change: WriteReport[\"changes\"][number]): string {\n switch (change.action) {\n case \"create\":\n return `${change.path} would be created`;\n case \"change\":\n return `${change.path} would change`;\n case \"remove\":\n return `${change.path} would be removed`;\n }\n}\n\n/** A generated Vale rule file's `swap:` entries. */\nfunction swapCount(content: string): number {\n const lines = content.split(/\\r?\\n/);\n const start = lines.indexOf(\"swap:\");\n if (start === -1) return 0;\n return lines.slice(start + 1).filter((line) => line.startsWith(\" \")).length;\n}\n\nfunction baseName(path: string): string {\n return path.split(/[\\\\/]/).pop() ?? path;\n}\n\nconst CASING_RULES = new Set([\"Casing.yml\", \"Lowercase.yml\", \"SentenceStart.yml\"]);\n\n/** What each file of a Vale style holds: rule files by name, the acronym files together. */\nfunction valeLines(report: WriteReport): string[] {\n const rows: [string, string][] = [];\n const acronyms: string[] = [];\n for (const file of report.files) {\n const name = baseName(file.path);\n // A casing rule swaps each label and alt-label, so what it counts is labels.\n if (CASING_RULES.has(name)) rows.push([name, plural(swapCount(file.content), \"label\")]);\n else if (name === \"Deprecated.yml\") rows.push([name, plural(swapCount(file.content), \"swap\")]);\n else acronyms.push(name);\n }\n if (acronyms.length > 0) rows.push([acronyms.join(\", \"), plural(acronyms.length, \"acronym\")]);\n const width = Math.max(0, ...rows.map(([name]) => name.length)) + 2;\n return rows.map(([name, what]) => ` ${name.padEnd(width)}${what}`);\n}\n\n/** ` dropped from a definition list: scope-note on 3 terms, hidden-labels on 12`. */\nfunction droppedLine(report: WriteReport): string | undefined {\n if (report.dropped.length === 0) return undefined;\n const ids = new Map<TermField, Set<string>>();\n for (const { id, field } of report.dropped) {\n const set = ids.get(field) ?? new Set<string>();\n set.add(id);\n ids.set(field, set);\n }\n const fields = [...ids.entries()]\n .map(([field, set]) => ({ field, n: set.size }))\n .sort((a, b) => a.n - b.n || TERM_FIELDS.indexOf(a.field) - TERM_FIELDS.indexOf(b.field));\n const parts = fields.map(({ field, n }, i) => `${field} on ${i === 0 ? plural(n, \"term\") : String(n)}`);\n return ` dropped from ${report.droppedFrom ?? report.format ?? \"the render\"}: ${parts.join(\", \")}`;\n}\n\n/** ` skipped 2 terms a definition list cannot read without a definition: varifocal, bifocal`. */\nfunction skippedLine(report: WriteReport): string | undefined {\n if (report.skipped.length === 0) return undefined;\n const construct = report.droppedFrom ?? report.format ?? \"the render\";\n const count = plural(report.skipped.length, \"term\");\n return ` skipped ${count} ${construct} cannot read without a definition: ${report.skipped.join(\", \")}`;\n}\n\n/** The dropped and skipped lines, which a write and a dry run print alike. */\nfunction renderNotes(report: WriteReport): string[] {\n return [droppedLine(report), skippedLine(report)].filter((line) => line !== undefined);\n}\n\nfunction unchangedLine(report: WriteReport): string {\n return report.mode === \"in-place\" ? \"Nothing to write\" : `${report.target ?? \"\"} is up to date`;\n}\n\nexport function renderWritePretty(report: WriteReport): string {\n if (report.check) {\n return report.changes.length > 0 ? report.changes.map(changeLine).join(\"\\n\") : unchangedLine(report);\n }\n if (report.dryRun) {\n const changes = report.changes.length > 0 ? report.changes.map(changeLine) : [unchangedLine(report)];\n return [...changes, ...renderNotes(report)].join(\"\\n\");\n }\n if (report.mode === \"in-place\") {\n return report.changes.length === 0 ? \"Nothing to write\" : `Wrote ${plural(report.changes.length, \"file\")}`;\n }\n const each = report.shape === \"directory\" && report.format !== \"vale\" ? \", one file each\" : \"\";\n const written = report.terms - report.skipped.length;\n const lines = [`Wrote ${plural(written, \"term\")} to ${report.target ?? \"\"}${each}`];\n if (report.format === \"vale\") lines.push(...valeLines(report));\n lines.push(...renderNotes(report));\n return lines.join(\"\\n\");\n}\n\n/** The notice `write -f vale` prints when no section of Vale's config uses the style, or there is no section. */\nexport function renderValeWiring(wiring: ValeWiring): string {\n return [\n wiring.addSection\n ? `notice: ${wiring.rootIni} has no section with BasedOnStyles. Add one that uses the Terms style:`\n : `notice: no section of ${wiring.rootIni} uses the Terms style. Add it to BasedOnStyles:`,\n ` [${wiring.section}]`,\n ` BasedOnStyles = ${wiring.styles.join(\", \")}`,\n ].join(\"\\n\");\n}\n\n// ---------------------------------------------------------------------------\n// formats\n\nexport function renderFormatsPretty(rows: readonly FormatRow[]): string {\n const formatWidth = Math.max(0, ...rows.map((r) => r.format.length)) + 3;\n const labelWidth = Math.max(0, ...rows.map((r) => r.label.length)) + 3;\n return rows\n .map((r) =>\n `${r.format.padEnd(formatWidth)}${r.label.padEnd(labelWidth)}${r.read ? \"read \" : \" \"}${r.write ? \"write\" : \"\"}`.trimEnd(),\n )\n .join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;;AAcA,IAAM,QAAQ;AAGd,SAAS,UAAU,MAAc,OAAyB;AACxD,QAAM,QAAkB,CAAC;AACzB,MAAI,OAAO;AACX,aAAW,QAAQ,KAAK,MAAM,KAAK,EAAE,OAAO,CAAC,MAAM,MAAM,EAAE,GAAG;AAC5D,QAAI,SAAS,GAAI,QAAO;AAAA,aACf,KAAK,SAAS,IAAI,KAAK,UAAU,MAAO,QAAO,GAAG,IAAI,IAAI,IAAI;AAAA,SAClE;AACH,YAAM,KAAK,IAAI;AACf,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,SAAS,GAAI,OAAM,KAAK,IAAI;AAChC,SAAO,MAAM,WAAW,IAAI,CAAC,EAAE,IAAI;AACrC;AAGA,SAAS,cAAc,MAAc,OAAyB;AAC5D,MAAI,KAAK,UAAU,MAAO,QAAO,CAAC,IAAI;AACtC,QAAM,QAAkB,CAAC;AACzB,MAAI,OAAO;AACX,aAAW,YAAY,KAAK,MAAM,kBAAkB,GAAG;AACrD,QAAI,SAAS,GAAI,QAAO;AAAA,aACf,KAAK,SAAS,IAAI,SAAS,UAAU,MAAO,QAAO,GAAG,IAAI,IAAI,QAAQ;AAAA,SAC1E;AACH,YAAM,KAAK,IAAI;AACf,aAAO;AAAA,IACT;AAAA,EACF;AACA,MAAI,SAAS,GAAI,OAAM,KAAK,IAAI;AAChC,SAAO;AACT;AAEA,SAAS,QAAQ,OAAe,OAAoC;AAClE,QAAM,SAAS,IAAI,OAAO,MAAM,MAAM;AACtC,SAAO,MAAM,IAAI,CAAC,MAAM,MAAM,GAAG,MAAM,IAAI,QAAQ,MAAM,GAAG,IAAI,GAAG,QAAQ,CAAC;AAC9E;AAKO,SAAS,iBAAiB,OAAgC;AAC/D,QAAM,UAAU,KAAK,IAAI,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,IAAI;AAChE,QAAM,aAAa,KAAK,IAAI,GAAG,GAAG,MAAM,IAAI,CAAC,MAAM,EAAE,OAAO,MAAM,MAAM,CAAC,IAAI;AAC7E,QAAM,OAAO,MAAM;AAAA,IAAI,CAAC,MACtB,GAAG,EAAE,GAAG,OAAO,OAAO,CAAC,GAAG,EAAE,OAAO,MAAM,OAAO,UAAU,CAAC,IAAI,EAAE,OAAO,YAAY,KAAK,CAAC,GAAG,KAAK,IAAI,CAAC,GAAG,QAAQ;AAAA,EACpH;AACA,SAAO,CAAC,GAAG,MAAM,OAAO,MAAM,QAAQ,MAAM,CAAC,EAAE,KAAK,IAAI;AAC1D;AAMA,IAAM,aAAmC;AAAA,EACvC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,YAAY,KAAK,IAAI,WAAW,QAAQ,GAAG,YAAY,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI;AAE9E,SAAS,gBAAgB,MAAY,MAAgD;AAC1F,QAAM,IAAI,QAAQ,KAAK,KAAK;AAC5B,QAAM,QAAQ,GAAG,YAAY,KAAK,SAAS,MAAM,KAAK,OAAO,QAAQ,IAAI,CAAC,CAAC,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC;AACzG,QAAM,QAAQ,CAAC,GAAG,EAAE,KAAK,KAAK,OAAO,MAAM,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,KAAK,CAAC,EAAE;AACvE,QAAM,MAAM,CAAC,KAAa,UAAwB;AAChD,UAAM,SAAS,KAAK,IAAI,OAAO,SAAS,CAAC;AACzC,UAAM,KAAK,GAAG,QAAQ,QAAQ,UAAU,OAAO,QAAQ,OAAO,MAAM,CAAC,CAAC;AAAA,EACxE;AACA,MAAI,MAAM,KAAK,EAAE;AACjB,MAAI,KAAK,aAAa,OAAW,KAAI,YAAY,KAAK,QAAQ;AAC9D,aAAW,SAAS,YAAY;AAC9B,UAAM,QAAQ,KAAK,OAAO,KAAK;AAC/B,QAAI,UAAU,OAAW;AACzB,QAAI,OAAO,OAAO,UAAU,WAAW,QAAQ,MAAM,KAAK,IAAI,CAAC;AAAA,EACjE;AACA,SAAO,MAAM,KAAK,IAAI;AACxB;AAKA,IAAM,aAAa;AAEnB,SAAS,aAAa,GAAW,UAA4B;AAC3D,QAAM,SAAS,SAAS,OAAO,CAAC;AAChC,MAAI,aAAa,QAAS,QAAO,EAAE,IAAI,MAAM;AAC7C,MAAI,aAAa,UAAW,QAAO,EAAE,OAAO,MAAM;AAClD,SAAO,EAAE,KAAK,MAAM;AACtB;AAEA,SAAS,OAAO,UAA0C;AACxD,QAAM,QAAkB,CAAC;AACzB,QAAM,IAAI,CAAC,aAA+B,SAAS,OAAO,CAAC,MAAM,EAAE,aAAa,QAAQ,EAAE;AAC1F,MAAI,EAAE,OAAO,IAAI,EAAG,OAAM,KAAK,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC;AAC1D,MAAI,EAAE,SAAS,IAAI,EAAG,OAAM,KAAK,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC;AAChE,MAAI,EAAE,QAAQ,IAAI,EAAG,OAAM,KAAK,OAAO,EAAE,QAAQ,GAAG,QAAQ,CAAC;AAC7D,SAAO,MAAM,KAAK,IAAI;AACxB;AAQO,SAAS,qBAAqB,QAAoB,MAAqC;AAC5F,QAAM,IAAI,QAAQ,KAAK,KAAK;AAC5B,QAAM,EAAE,SAAS,IAAI;AACrB,MAAI,UAAU,YAAY,MAAM;AAC9B,WAAO,GAAG,EAAE,MAAM,QAAG,CAAC,IAAI,OAAO,OAAO,OAAO,SAAS,CAAC,gBAAgB,SAAS,IAAI;AAAA,EACxF;AACA,QAAM,YAAY,aAAa,UAAa,SAAS,aAAa,IAAI,KAAK,OAAO,SAAS,UAAU,CAAC,eAAe;AACrH,QAAM,QAAQ,OAAO,OAAO,OAAO,MAAM;AAEzC,MAAI,OAAO,SAAS,WAAW,GAAG;AAChC,UAAM,aAAa,KAAK,eAAe,QAAQ,KAAK,KAAK,OAAO,OAAO,YAAY,WAAW,CAAC;AAC/F,WAAO,GAAG,EAAE,MAAM,QAAG,CAAC,IAAI,KAAK,GAAG,UAAU,gBAAgB,SAAS;AAAA,EACvE;AAEA,QAAM,YAAY,KAAK,IAAI,YAAY,GAAG,OAAO,SAAS,IAAI,CAAC,MAAM,EAAE,OAAO,SAAS,CAAC,CAAC;AACzF,QAAM,QAAkB,CAAC;AACzB,MAAI;AACJ,aAAW,WAAW,OAAO,UAAU;AACrC,UAAM,OAAO,YAAY,QAAQ,MAAM,OAAO,GAAG;AACjD,UAAM,SAAS,QAAQ,SAAS,SAAY,OAAO,GAAG,IAAI,IAAI,OAAO,QAAQ,IAAI,CAAC;AAClF,QAAI,WAAW,OAAO;AACpB,YAAM,KAAK,EAAE,KAAK,MAAM,CAAC;AACzB,cAAQ;AAAA,IACV;AACA,UAAM,cAAc,IAAI,IAAI,IAAI;AAChC,UAAM,UAAU,cAAc,QAAQ,SAAS,QAAQ,WAAW;AAClE,UAAM,SAAS,IAAI,OAAO,WAAW;AACrC,YAAQ,QAAQ,CAAC,MAAM,MAAM;AAC3B,YAAM;AAAA,QACJ,MAAM,IAAI,KAAK,aAAa,GAAG,QAAQ,QAAQ,CAAC,IAAI,QAAQ,OAAO,OAAO,SAAS,CAAC,GAAG,IAAI,KAAK,GAAG,MAAM,GAAG,IAAI;AAAA,MAClH;AAAA,IACF,CAAC;AAAA,EACH;AACA,QAAM,KAAK,IAAI,GAAG,OAAO,OAAO,QAAQ,CAAC,OAAO,KAAK,GAAG,SAAS,EAAE;AACnE,SAAO,MAAM,KAAK,IAAI;AACxB;AAKA,SAAS,WAAW,QAAgD;AAClE,UAAQ,OAAO,QAAQ;AAAA,IACrB,KAAK;AACH,aAAO,GAAG,OAAO,IAAI;AAAA,IACvB,KAAK;AACH,aAAO,GAAG,OAAO,IAAI;AAAA,IACvB,KAAK;AACH,aAAO,GAAG,OAAO,IAAI;AAAA,EACzB;AACF;AAGA,SAAS,UAAU,SAAyB;AAC1C,QAAM,QAAQ,QAAQ,MAAM,OAAO;AACnC,QAAM,QAAQ,MAAM,QAAQ,OAAO;AACnC,MAAI,UAAU,GAAI,QAAO;AACzB,SAAO,MAAM,MAAM,QAAQ,CAAC,EAAE,OAAO,CAAC,SAAS,KAAK,WAAW,IAAI,CAAC,EAAE;AACxE;AAEA,SAAS,SAAS,MAAsB;AACtC,SAAO,KAAK,MAAM,OAAO,EAAE,IAAI,KAAK;AACtC;AAEA,IAAM,eAAe,oBAAI,IAAI,CAAC,cAAc,iBAAiB,mBAAmB,CAAC;AAGjF,SAAS,UAAU,QAA+B;AAChD,QAAM,OAA2B,CAAC;AAClC,QAAM,WAAqB,CAAC;AAC5B,aAAW,QAAQ,OAAO,OAAO;AAC/B,UAAM,OAAO,SAAS,KAAK,IAAI;AAE/B,QAAI,aAAa,IAAI,IAAI,EAAG,MAAK,KAAK,CAAC,MAAM,OAAO,UAAU,KAAK,OAAO,GAAG,OAAO,CAAC,CAAC;AAAA,aAC7E,SAAS,iBAAkB,MAAK,KAAK,CAAC,MAAM,OAAO,UAAU,KAAK,OAAO,GAAG,MAAM,CAAC,CAAC;AAAA,QACxF,UAAS,KAAK,IAAI;AAAA,EACzB;AACA,MAAI,SAAS,SAAS,EAAG,MAAK,KAAK,CAAC,SAAS,KAAK,IAAI,GAAG,OAAO,SAAS,QAAQ,SAAS,CAAC,CAAC;AAC5F,QAAM,QAAQ,KAAK,IAAI,GAAG,GAAG,KAAK,IAAI,CAAC,CAAC,IAAI,MAAM,KAAK,MAAM,CAAC,IAAI;AAClE,SAAO,KAAK,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,KAAK,KAAK,OAAO,KAAK,CAAC,GAAG,IAAI,EAAE;AACpE;AAGA,SAAS,YAAY,QAAyC;AAC5D,MAAI,OAAO,QAAQ,WAAW,EAAG,QAAO;AACxC,QAAM,MAAM,oBAAI,IAA4B;AAC5C,aAAW,EAAE,IAAI,MAAM,KAAK,OAAO,SAAS;AAC1C,UAAM,MAAM,IAAI,IAAI,KAAK,KAAK,oBAAI,IAAY;AAC9C,QAAI,IAAI,EAAE;AACV,QAAI,IAAI,OAAO,GAAG;AAAA,EACpB;AACA,QAAM,SAAS,CAAC,GAAG,IAAI,QAAQ,CAAC,EAC7B,IAAI,CAAC,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,GAAG,IAAI,KAAK,EAAE,EAC9C,KAAK,CAAC,GAAG,MAAM,EAAE,IAAI,EAAE,KAAK,YAAY,QAAQ,EAAE,KAAK,IAAI,YAAY,QAAQ,EAAE,KAAK,CAAC;AAC1F,QAAM,QAAQ,OAAO,IAAI,CAAC,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,KAAK,OAAO,MAAM,IAAI,OAAO,GAAG,MAAM,IAAI,OAAO,CAAC,CAAC,EAAE;AACtG,SAAO,kBAAkB,OAAO,eAAe,OAAO,UAAU,YAAY,KAAK,MAAM,KAAK,IAAI,CAAC;AACnG;AAGA,SAAS,YAAY,QAAyC;AAC5D,MAAI,OAAO,QAAQ,WAAW,EAAG,QAAO;AACxC,QAAM,YAAY,OAAO,eAAe,OAAO,UAAU;AACzD,QAAM,QAAQ,OAAO,OAAO,QAAQ,QAAQ,MAAM;AAClD,SAAO,aAAa,KAAK,IAAI,SAAS,sCAAsC,OAAO,QAAQ,KAAK,IAAI,CAAC;AACvG;AAGA,SAAS,YAAY,QAA+B;AAClD,SAAO,CAAC,YAAY,MAAM,GAAG,YAAY,MAAM,CAAC,EAAE,OAAO,CAAC,SAAS,SAAS,MAAS;AACvF;AAEA,SAAS,cAAc,QAA6B;AAClD,SAAO,OAAO,SAAS,aAAa,qBAAqB,GAAG,OAAO,UAAU,EAAE;AACjF;AAEO,SAAS,kBAAkB,QAA6B;AAC7D,MAAI,OAAO,OAAO;AAChB,WAAO,OAAO,QAAQ,SAAS,IAAI,OAAO,QAAQ,IAAI,UAAU,EAAE,KAAK,IAAI,IAAI,cAAc,MAAM;AAAA,EACrG;AACA,MAAI,OAAO,QAAQ;AACjB,UAAM,UAAU,OAAO,QAAQ,SAAS,IAAI,OAAO,QAAQ,IAAI,UAAU,IAAI,CAAC,cAAc,MAAM,CAAC;AACnG,WAAO,CAAC,GAAG,SAAS,GAAG,YAAY,MAAM,CAAC,EAAE,KAAK,IAAI;AAAA,EACvD;AACA,MAAI,OAAO,SAAS,YAAY;AAC9B,WAAO,OAAO,QAAQ,WAAW,IAAI,qBAAqB,SAAS,OAAO,OAAO,QAAQ,QAAQ,MAAM,CAAC;AAAA,EAC1G;AACA,QAAM,OAAO,OAAO,UAAU,eAAe,OAAO,WAAW,SAAS,oBAAoB;AAC5F,QAAM,UAAU,OAAO,QAAQ,OAAO,QAAQ;AAC9C,QAAM,QAAQ,CAAC,SAAS,OAAO,SAAS,MAAM,CAAC,OAAO,OAAO,UAAU,EAAE,GAAG,IAAI,EAAE;AAClF,MAAI,OAAO,WAAW,OAAQ,OAAM,KAAK,GAAG,UAAU,MAAM,CAAC;AAC7D,QAAM,KAAK,GAAG,YAAY,MAAM,CAAC;AACjC,SAAO,MAAM,KAAK,IAAI;AACxB;AAGO,SAAS,iBAAiB,QAA4B;AAC3D,SAAO;AAAA,IACL,OAAO,aACH,WAAW,OAAO,OAAO,2EACzB,yBAAyB,OAAO,OAAO;AAAA,IAC3C,MAAM,OAAO,OAAO;AAAA,IACpB,qBAAqB,OAAO,OAAO,KAAK,IAAI,CAAC;AAAA,EAC/C,EAAE,KAAK,IAAI;AACb;AAKO,SAAS,oBAAoB,MAAoC;AACtE,QAAM,cAAc,KAAK,IAAI,GAAG,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,OAAO,MAAM,CAAC,IAAI;AACvE,QAAM,aAAa,KAAK,IAAI,GAAG,GAAG,KAAK,IAAI,CAAC,MAAM,EAAE,MAAM,MAAM,CAAC,IAAI;AACrE,SAAO,KACJ;AAAA,IAAI,CAAC,MACJ,GAAG,EAAE,OAAO,OAAO,WAAW,CAAC,GAAG,EAAE,MAAM,OAAO,UAAU,CAAC,GAAG,EAAE,OAAO,WAAW,QAAQ,GAAG,EAAE,QAAQ,UAAU,EAAE,GAAG,QAAQ;AAAA,EACjI,EACC,KAAK,IAAI;AACd;","names":[]}
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ displayPath
4
+ } from "./chunk-WQE54PNH.js";
5
+ import {
6
+ escapeWorkflowCommandMessage,
7
+ escapeWorkflowCommandProperty
8
+ } from "./chunk-MNH7QO4Z.js";
9
+
10
+ // src/term/reporters/github.ts
11
+ function renderFindingsGithub(report) {
12
+ return report.findings.map((finding) => {
13
+ const params = [`file=${escapeWorkflowCommandProperty(displayPath(finding.file, report.cwd))}`];
14
+ if (finding.line !== void 0) params.push(`line=${String(finding.line)}`);
15
+ params.push(`title=${escapeWorkflowCommandProperty(finding.ruleId)}`);
16
+ return `::${finding.severity} ${params.join(",")}::${escapeWorkflowCommandMessage(finding.message)}`;
17
+ }).join("\n");
18
+ }
19
+
20
+ export {
21
+ renderFindingsGithub
22
+ };
23
+ //# sourceMappingURL=chunk-3AFUD75K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/term/reporters/github.ts"],"sourcesContent":["/**\n * GitHub workflow commands, one per reported finding:\n * `::error file=<file>,line=<n>,title=<ruleId>::<message>`, with `::warning`\n * and `::notice` for the lower levels. Uses meta's escapes. A clean run is the\n * empty string, which the CLI prints nothing for.\n */\nimport { escapeWorkflowCommandMessage, escapeWorkflowCommandProperty } from \"../../meta/internal.js\";\nimport type { TermReport } from \"../commands/findings.js\";\nimport { displayPath } from \"../commands/run.js\";\n\nexport function renderFindingsGithub(report: TermReport): string {\n return report.findings\n .map((finding) => {\n const params = [`file=${escapeWorkflowCommandProperty(displayPath(finding.file, report.cwd))}`];\n if (finding.line !== undefined) params.push(`line=${String(finding.line)}`);\n params.push(`title=${escapeWorkflowCommandProperty(finding.ruleId)}`);\n return `::${finding.severity} ${params.join(\",\")}::${escapeWorkflowCommandMessage(finding.message)}`;\n })\n .join(\"\\n\");\n}\n"],"mappings":";;;;;;;;;;AAUO,SAAS,qBAAqB,QAA4B;AAC/D,SAAO,OAAO,SACX,IAAI,CAAC,YAAY;AAChB,UAAM,SAAS,CAAC,QAAQ,8BAA8B,YAAY,QAAQ,MAAM,OAAO,GAAG,CAAC,CAAC,EAAE;AAC9F,QAAI,QAAQ,SAAS,OAAW,QAAO,KAAK,QAAQ,OAAO,QAAQ,IAAI,CAAC,EAAE;AAC1E,WAAO,KAAK,SAAS,8BAA8B,QAAQ,MAAM,CAAC,EAAE;AACpE,WAAO,KAAK,QAAQ,QAAQ,IAAI,OAAO,KAAK,GAAG,CAAC,KAAK,6BAA6B,QAAQ,OAAO,CAAC;AAAA,EACpG,CAAC,EACA,KAAK,IAAI;AACd;","names":[]}
@@ -1,7 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- ToolError
4
- } from "./chunk-IOYXPBCL.js";
5
2
 
6
3
  // src/tracevals/trace/discover.ts
7
4
  import { open, readdir, stat } from "node:fs/promises";
@@ -103,18 +100,9 @@ async function summarizeTrace(file) {
103
100
  return summary;
104
101
  }
105
102
 
106
- // src/tracevals/types.ts
107
- var TracevalsError = class extends ToolError {
108
- constructor(message) {
109
- super(message);
110
- this.name = "TracevalsError";
111
- }
112
- };
113
-
114
103
  export {
115
104
  slugFor,
116
105
  configDir,
117
- discoverTraces,
118
- TracevalsError
106
+ discoverTraces
119
107
  };
120
- //# sourceMappingURL=chunk-3R23C5DT.js.map
108
+ //# sourceMappingURL=chunk-4TSWU2SU.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tracevals/trace/discover.ts"],"sourcesContent":["/**\n * Session-store discovery: find Claude Code trace files for a project (or all\n * projects) in Claude Code's own config directory.\n *\n * The location is detected, not configured: `CLAUDE_CONFIG_DIR` is Claude\n * Code's variable for that directory, so a session that has moved it is\n * followed without tracevals adding a switch of its own, and a test or CI job\n * points at a fixture tree with the same variable the agent itself reads.\n */\nimport { open, readdir, stat } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\n\nexport interface TraceListing {\n /** Absolute path of the trace file. */\n file: string;\n mtimeMs: number;\n sizeBytes: number;\n sessionId?: string;\n /** The cwd recorded in the session, when readable. */\n project?: string;\n /** First non-sidechain user prompt, for identification in lists. */\n firstPrompt?: string;\n}\n\nexport interface DiscoverOptions {\n /** Project directory to scope to (its session-store slug is scanned). */\n project?: string;\n /** Scan every project directory in the store. */\n allProjects?: boolean;\n /** Maximum entries returned, applied after newest-first sorting. */\n limit?: number;\n env?: Record<string, string | undefined>;\n}\n\n/** Claude Code's project-slug rule: every non-alphanumeric character → `-`. */\nexport function slugFor(cwd: string): string {\n return cwd.replace(/[^a-zA-Z0-9]/g, \"-\");\n}\n\n/**\n * Claude Code's config directory: `CLAUDE_CONFIG_DIR` when it is set, and\n * `~/.claude` otherwise. Everything the agent keeps per user — `projects/`,\n * `skills/`, `agents/`, `commands/`, `plugins/` — hangs off it.\n */\nexport function configDir(\n env: Record<string, string | undefined> = process.env,\n): string {\n const configured = env.CLAUDE_CONFIG_DIR;\n if (configured) return resolve(configured);\n return join(homedir(), \".claude\");\n}\n\nexport async function discoverTraces(\n options: DiscoverOptions = {},\n): Promise<TraceListing[]> {\n const store = join(configDir(options.env), \"projects\");\n\n let projectDirs: string[];\n if (options.allProjects) {\n try {\n const entries = await readdir(store, { withFileTypes: true });\n projectDirs = entries\n .filter((e) => e.isDirectory())\n .map((e) => join(store, e.name));\n } catch {\n return [];\n }\n } else {\n const project = options.project ?? process.cwd();\n projectDirs = [join(store, slugFor(project))];\n }\n\n const listings: TraceListing[] = [];\n for (const dir of projectDirs) {\n let names: string[];\n try {\n names = (await readdir(dir)).filter((n) => n.endsWith(\".jsonl\"));\n } catch {\n continue;\n }\n for (const name of names) {\n const file = join(dir, name);\n try {\n const info = await stat(file);\n listings.push({\n file,\n mtimeMs: info.mtimeMs,\n sizeBytes: info.size,\n ...(await summarizeTrace(file)),\n });\n } catch {\n continue;\n }\n }\n }\n\n listings.sort((a, b) => b.mtimeMs - a.mtimeMs);\n return options.limit !== undefined\n ? listings.slice(0, options.limit)\n : listings;\n}\n\n/** Bytes read from the head of a session file when summarizing for a list. */\nconst SUMMARY_WINDOW = 256 * 1024;\n\n/** Read only the first `bytes` of a file — session files run to many MB. */\nasync function readHead(file: string, bytes: number): Promise<string | null> {\n let handle;\n try {\n handle = await open(file, \"r\");\n const buffer = Buffer.alloc(bytes);\n const { bytesRead } = await handle.read(buffer, 0, bytes, 0);\n return buffer.toString(\"utf-8\", 0, bytesRead);\n } catch {\n return null;\n } finally {\n await handle?.close();\n }\n}\n\nasync function summarizeTrace(\n file: string,\n): Promise<Pick<TraceListing, \"sessionId\" | \"project\" | \"firstPrompt\">> {\n const content = await readHead(file, SUMMARY_WINDOW);\n if (content === null) return {};\n\n const summary: Pick<TraceListing, \"sessionId\" | \"project\" | \"firstPrompt\"> =\n {};\n for (const line of content.split(\"\\n\")) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch {\n continue;\n }\n // A bare `null`, number or string is valid JSON but no record. The same\n // guard `detect.ts` uses: skip the line rather than let a property read\n // throw and drop the whole file from the listing.\n if (typeof parsed !== \"object\" || parsed === null) continue;\n const rec = parsed as Record<string, unknown>;\n if (summary.sessionId === undefined) {\n const id = rec.sessionId ?? rec.session_id;\n if (typeof id === \"string\") summary.sessionId = id;\n }\n if (summary.project === undefined && typeof rec.cwd === \"string\") {\n summary.project = rec.cwd;\n }\n if (\n summary.firstPrompt === undefined &&\n rec.type === \"user\" &&\n rec.isSidechain !== true\n ) {\n const message = rec.message as Record<string, unknown> | undefined;\n const content = message?.content;\n if (typeof content === \"string\" && !content.startsWith(\"<command-\")) {\n summary.firstPrompt = content.split(\"\\n\")[0]?.slice(0, 200);\n }\n }\n if (summary.sessionId && summary.project && summary.firstPrompt) break;\n }\n return summary;\n}\n"],"mappings":"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","names":["content"]}