@hawkeyexl/manni 4.3.1 → 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-CFDUZRM2.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-KJR7OVDX.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-UBMMXS2Y.js → chunk-KCGV52AM.js} +69 -48
  67. package/dist/{chunk-UBMMXS2Y.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-HAPTXWU2.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-5HNHEUD5.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-G5CM2VGQ.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 -7661
  156. package/dist/cli.js.map +1 -1
  157. package/dist/docmeta.js +15 -3
  158. package/dist/docmeta.js.map +1 -1
  159. package/dist/github-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-A5HZKYIW.js +0 -18
  206. package/dist/calibrate-S5K6QHUY.js +0 -13
  207. package/dist/capture-OZEZDABQ.js +0 -15
  208. package/dist/chunk-3R23C5DT.js.map +0 -1
  209. package/dist/chunk-CFDUZRM2.js.map +0 -1
  210. package/dist/chunk-G5CM2VGQ.js.map +0 -1
  211. package/dist/chunk-KJR7OVDX.js.map +0 -1
  212. package/dist/chunk-V4KUVE47.js +0 -27170
  213. package/dist/chunk-V4KUVE47.js.map +0 -1
  214. package/dist/chunk-ZQBTK3DO.js +0 -26518
  215. package/dist/chunk-ZQBTK3DO.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-A5HZKYIW.js.map → batch-DFRCLY77.js.map} +0 -0
  220. /package/dist/{calibrate-S5K6QHUY.js.map → build-Q5C6SX5J.js.map} +0 -0
  221. /package/dist/{capture-OZEZDABQ.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-HAPTXWU2.js.map → chunk-MYC3O5EJ.js.map} +0 -0
  224. /package/dist/{chunk-5HNHEUD5.js.map → chunk-XYLUCIKQ.js.map} +0 -0
@@ -0,0 +1,683 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ REPORT_FORMATS,
4
+ parseFormat
5
+ } from "./chunk-ZXRAE55H.js";
6
+ import {
7
+ palette
8
+ } from "./chunk-RNVYGWIC.js";
9
+ import {
10
+ escapeWorkflowCommandMessage,
11
+ escapeWorkflowCommandProperty
12
+ } from "./chunk-MNH7QO4Z.js";
13
+
14
+ // src/docevals/reporters/scope.ts
15
+ function scopeLine(report) {
16
+ const sc = report.since ?? report.newerThan;
17
+ if (sc === void 0) return void 0;
18
+ const { pagesSelected, pagesTotal } = sc;
19
+ const ref = report.since?.ref;
20
+ const window = report.newerThan?.duration;
21
+ return {
22
+ empty: pagesSelected === 0,
23
+ text: (code = (s) => s) => {
24
+ const what = [
25
+ ref === void 0 ? void 0 : `since ${code(ref)}`,
26
+ window === void 0 ? void 0 : `in the last ${window}`
27
+ ].filter((s) => s !== void 0).join(" and ");
28
+ return pagesSelected === 0 ? `No pages changed ${what} \u2014 nothing was evaluated.` : `Scoped to ${String(pagesSelected)} of ${String(pagesTotal)} page(s) changed ${what}.`;
29
+ }
30
+ };
31
+ }
32
+
33
+ // src/docevals/reporters/location.ts
34
+ function declaringEntry(r) {
35
+ return r.location ?? { file: r.file };
36
+ }
37
+ function locationLabel(location) {
38
+ return location.line === void 0 ? location.file : `${location.file}:${String(location.line)}`;
39
+ }
40
+
41
+ // src/docevals/reporters/pretty.ts
42
+ function outcomeTag(r, pc) {
43
+ switch (r.outcome) {
44
+ case "pass":
45
+ return pc.green("pass");
46
+ case "fail":
47
+ return pc.red("FAIL");
48
+ case "needs-review":
49
+ return pc.yellow("review");
50
+ case "skipped":
51
+ return pc.dim("skip");
52
+ case "error":
53
+ return pc.red("ERROR");
54
+ }
55
+ }
56
+ function renderPretty(report, opts = {}) {
57
+ const pc = palette(opts.color === true);
58
+ const lines = [];
59
+ const byFile = /* @__PURE__ */ new Map();
60
+ for (const r of report.evalResults) {
61
+ const list = byFile.get(r.file) ?? [];
62
+ list.push(r);
63
+ byFile.set(r.file, list);
64
+ }
65
+ for (const [file, results] of [...byFile.entries()].sort()) {
66
+ lines.push(pc.bold(file));
67
+ for (const r of results) {
68
+ const zone = r.consensus ? pc.dim(` [${r.consensus.zone}]`) : "";
69
+ const via = r.via ? pc.dim(" (human-reviewed)") : "";
70
+ const gen = r.generated ? pc.cyan(" (generated)") : "";
71
+ const entry = pc.dim(locationLabel(declaringEntry(r)));
72
+ lines.push(` ${outcomeTag(r, pc)} ${r.evalName}${zone}${via}${gen} ${entry}`);
73
+ if (r.skipReason && r.outcome !== "pass") {
74
+ lines.push(pc.dim(` ${r.skipReason}`));
75
+ }
76
+ for (const f of r.findings ?? []) {
77
+ const loc = f.line != null ? `:${f.line}` : "";
78
+ const rule = f.ruleId ? pc.dim(` [${f.ruleId}]`) : "";
79
+ const sev = f.severity === "error" ? pc.red(f.severity) : f.severity === "warning" ? pc.yellow(f.severity) : pc.dim(f.severity);
80
+ lines.push(` ${sev}${loc}${rule} ${f.message}`);
81
+ }
82
+ if (r.consensus && r.outcome !== "pass") {
83
+ const v = r.consensus;
84
+ lines.push(
85
+ pc.dim(
86
+ ` votes pass:${v.votes.pass} fail:${v.votes.fail} partial:${v.votes.partial}` + (v.votes.error ? ` error:${v.votes.error}` : "") + ` \u2014 confidence ${v.meanConfidence.toFixed(2)}`
87
+ )
88
+ );
89
+ const reasoning = v.runs.find((run) => run.verdict)?.verdict?.reasoning;
90
+ if (reasoning) lines.push(pc.dim(` ${reasoning}`));
91
+ }
92
+ }
93
+ }
94
+ for (const p of report.problems) {
95
+ const tag = p.level === "error" ? pc.red("error") : pc.yellow("warn");
96
+ const loc = p.line != null ? `:${p.line}` : "";
97
+ lines.push(`${tag} ${p.file}${loc} ${p.message}`);
98
+ }
99
+ if (report.generated.length > 0) {
100
+ lines.push("");
101
+ lines.push(pc.cyan(`Generated ${report.generated.length} check script(s):`));
102
+ for (const g of report.generated) lines.push(` ${g}`);
103
+ }
104
+ lines.push("");
105
+ lines.push(pc.bold("Suites"));
106
+ for (const s of report.suites) {
107
+ const status = s.partial ? pc.yellow("partial \u2014 filtered run, target not evaluated") : s.meetsTarget ? pc.green("ok") : pc.red("below target");
108
+ const extras = [];
109
+ if (s.needsReview > 0) extras.push(`${s.needsReview} to review`);
110
+ if (s.skipped > 0) extras.push(`${s.skipped} skipped`);
111
+ const extra = extras.length > 0 ? pc.dim(` (${extras.join(", ")})`) : "";
112
+ lines.push(
113
+ ` ${s.suite}: ${s.passed}/${s.passed + s.failed + s.errored} passed \u2014 ${(s.passRate * 100).toFixed(0)}% vs target ${(s.targetPassRate * 100).toFixed(0)}% ${status}${extra}`
114
+ );
115
+ }
116
+ const sc = scopeLine(report);
117
+ if (sc) {
118
+ lines.push("");
119
+ lines.push(sc.empty ? pc.yellow(sc.text()) : pc.dim(sc.text()));
120
+ }
121
+ const bl = report.baseline;
122
+ if (bl) {
123
+ lines.push("");
124
+ if (bl.written) {
125
+ lines.push(
126
+ pc.dim(
127
+ `Baseline ${bl.path}: recorded ${bl.written.total} finding(s) (+${bl.written.added}, -${bl.written.removed}).`
128
+ )
129
+ );
130
+ if (bl.written.removed > 0) {
131
+ lines.push(
132
+ pc.yellow(
133
+ ` ${bl.written.removed} previously recorded finding(s) are no longer in the baseline. If this run covered less of the corpus than the last one, they have just been forgiven.`
134
+ )
135
+ );
136
+ }
137
+ } else {
138
+ lines.push(
139
+ pc.dim(
140
+ `Baseline ${bl.path}: ${bl.suppressed} finding(s) suppressed of ${bl.recorded} recorded` + (bl.stale > 0 ? `, ${bl.stale} no longer occur` : "") + "."
141
+ )
142
+ );
143
+ }
144
+ }
145
+ if (report.usage.judgedEvals > 0) {
146
+ lines.push("");
147
+ lines.push(
148
+ pc.dim(
149
+ `Judged ${report.usage.judgedEvals} evals (${report.usage.cachedEvals} cached), ${report.usage.totalTokens.toLocaleString()} tokens`
150
+ )
151
+ );
152
+ }
153
+ const reviews = report.evalResults.filter(
154
+ (r) => r.outcome === "needs-review"
155
+ );
156
+ if (reviews.length > 0) {
157
+ lines.push("");
158
+ lines.push(
159
+ pc.yellow(
160
+ `${reviews.length} eval(s) need human review \u2014 run \`manni docevals review\` to record verdicts.`
161
+ )
162
+ );
163
+ }
164
+ return lines.join("\n");
165
+ }
166
+
167
+ // src/docevals/reporters/json.ts
168
+ function renderJson(report) {
169
+ return JSON.stringify(report, null, 2);
170
+ }
171
+
172
+ // src/docevals/reporters/markdown.ts
173
+ var OUTCOME_ICON = {
174
+ pass: "\u2705",
175
+ fail: "\u274C",
176
+ "needs-review": "\u{1F7E1}",
177
+ skipped: "\u23ED\uFE0F",
178
+ error: "\u{1F6D1}"
179
+ };
180
+ function renderMarkdown(report) {
181
+ const lines = ["## manni docevals results", ""];
182
+ lines.push("| Suite | Passed | Failed | Review | Pass rate | Target | |");
183
+ lines.push("|---|---|---|---|---|---|---|");
184
+ for (const s of report.suites) {
185
+ lines.push(
186
+ `| ${s.suite} | ${s.passed} | ${s.failed + s.errored} | ${s.needsReview} | ${(s.passRate * 100).toFixed(0)}% | ${(s.targetPassRate * 100).toFixed(0)}% | ${s.partial ? "\u2796 partial" : s.meetsTarget ? "\u2705" : "\u274C"} |`
187
+ );
188
+ }
189
+ const sc = scopeLine(report);
190
+ if (sc) {
191
+ const text = sc.text((s) => `\`${s}\``);
192
+ lines.push("");
193
+ lines.push(sc.empty ? `> **${text}**` : `_${text}_`);
194
+ }
195
+ const bl = report.baseline;
196
+ if (bl) {
197
+ lines.push("");
198
+ if (bl.written) {
199
+ lines.push(
200
+ `_Baseline \`${bl.path}\`: recorded ${bl.written.total} finding(s) (+${bl.written.added}, -${bl.written.removed})._`
201
+ );
202
+ if (bl.written.removed > 0) {
203
+ lines.push(
204
+ "",
205
+ `> **${bl.written.removed} previously recorded finding(s) are no longer in the baseline.** If this run covered less of the corpus than the last one, they have just been forgiven.`
206
+ );
207
+ }
208
+ } else {
209
+ lines.push(
210
+ `_Baseline \`${bl.path}\`: ${bl.suppressed} finding(s) suppressed of ${bl.recorded} recorded` + (bl.stale > 0 ? `, ${bl.stale} no longer occur` : "") + "._"
211
+ );
212
+ }
213
+ }
214
+ const notable = report.evalResults.filter(
215
+ (r) => r.outcome === "fail" || r.outcome === "error" || r.outcome === "needs-review"
216
+ );
217
+ if (notable.length > 0) {
218
+ lines.push("", "### Findings", "");
219
+ for (const r of notable) {
220
+ const icon = OUTCOME_ICON[r.outcome] ?? "";
221
+ const entry = declaringEntry(r);
222
+ const where = entry.file === r.file ? `\`${locationLabel(entry)}\`` : `\`${r.file}\` \xB7 \`${locationLabel(entry)}\``;
223
+ lines.push(`- ${icon} **${r.evalName}** \u2014 ${where}`);
224
+ for (const f of r.findings ?? []) {
225
+ const loc = f.line != null ? `:${f.line}` : "";
226
+ lines.push(` - ${f.severity}${loc}: ${f.message}`);
227
+ }
228
+ if (r.consensus) {
229
+ const v = r.consensus;
230
+ const reasoning = v.runs.find((run) => run.verdict)?.verdict?.reasoning;
231
+ lines.push(
232
+ ` - votes pass:${v.votes.pass} fail:${v.votes.fail} partial:${v.votes.partial}, confidence ${v.meanConfidence.toFixed(2)} (${v.zone})`
233
+ );
234
+ if (reasoning) lines.push(` - ${reasoning}`);
235
+ }
236
+ if (r.skipReason && r.outcome === "error") lines.push(` - ${r.skipReason}`);
237
+ }
238
+ }
239
+ for (const p of report.problems) {
240
+ lines.push(`- \u26A0\uFE0F \`${p.file}\`${p.line != null ? `:${p.line}` : ""} ${p.message}`);
241
+ }
242
+ if (report.generated.length > 0) {
243
+ lines.push("", "### Generated scripts", "");
244
+ for (const g of report.generated) lines.push(`- \`${g}\``);
245
+ }
246
+ if (report.usage.judgedEvals > 0) {
247
+ lines.push(
248
+ "",
249
+ `_Judged ${report.usage.judgedEvals} evals (${report.usage.cachedEvals} cached), ${report.usage.totalTokens.toLocaleString()} tokens._`
250
+ );
251
+ }
252
+ return lines.join("\n");
253
+ }
254
+
255
+ // src/docevals/reporters/github.ts
256
+ function renderGithub(report) {
257
+ const lines = [];
258
+ for (const r of report.evalResults) {
259
+ const entry = declaringEntry(r);
260
+ const entryProps = [
261
+ `file=${escapeWorkflowCommandProperty(entry.file)}`,
262
+ entry.line !== void 0 ? `line=${String(entry.line)}` : void 0
263
+ ];
264
+ for (const f of r.findings ?? []) {
265
+ const level = f.severity;
266
+ const props = [
267
+ ...f.line != null ? [`file=${escapeWorkflowCommandProperty(f.file)}`, `line=${String(f.line)}`] : entryProps,
268
+ f.line != null && f.col != null ? `col=${String(f.col)}` : void 0,
269
+ `title=${escapeWorkflowCommandProperty(`manni docevals: ${f.evalName}`)}`
270
+ ].filter(Boolean).join(",");
271
+ lines.push(`::${level} ${props}::${escapeWorkflowCommandMessage(f.message)}`);
272
+ }
273
+ if (r.outcome === "fail" && r.consensus) {
274
+ const reasoning = r.consensus.runs.find((run) => run.verdict)?.verdict?.reasoning ?? "";
275
+ const props = [...entryProps, `title=${escapeWorkflowCommandProperty(`manni docevals: ${r.evalName}`)}`].filter(Boolean).join(",");
276
+ lines.push(
277
+ `::error ${props}::${escapeWorkflowCommandMessage(
278
+ `AI judge: fail (confidence ${r.consensus.meanConfidence.toFixed(2)}). ${reasoning}`
279
+ )}`
280
+ );
281
+ }
282
+ if (r.outcome === "error" && (r.findings ?? []).length === 0) {
283
+ const props = [...entryProps, `title=${escapeWorkflowCommandProperty(`manni docevals: ${r.evalName}`)}`].filter(Boolean).join(",");
284
+ lines.push(`::error ${props}::${escapeWorkflowCommandMessage(r.skipReason ?? "eval errored")}`);
285
+ }
286
+ }
287
+ for (const p of report.problems) {
288
+ const level = p.level === "error" ? "error" : "warning";
289
+ const props = [
290
+ `file=${escapeWorkflowCommandProperty(p.file)}`,
291
+ p.line != null ? `line=${p.line}` : void 0,
292
+ `title=manni docevals`
293
+ ].filter(Boolean).join(",");
294
+ lines.push(`::${level} ${props}::${escapeWorkflowCommandMessage(p.message)}`);
295
+ }
296
+ const sc = scopeLine(report);
297
+ if (sc) {
298
+ lines.push(`::notice title=manni docevals::${escapeWorkflowCommandMessage(sc.text())}`);
299
+ }
300
+ lines.push("", renderMarkdown(report));
301
+ return lines.join("\n");
302
+ }
303
+
304
+ // src/docevals/reporters/sarif.ts
305
+ var SARIF_SCHEMA = "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/main/sarif-2.1/schema/sarif-schema-2.1.0.json";
306
+ function levelFor(severity) {
307
+ switch (severity) {
308
+ case "error":
309
+ return "error";
310
+ case "warning":
311
+ return "warning";
312
+ case "notice":
313
+ return "note";
314
+ }
315
+ }
316
+ function uriFor(file) {
317
+ return file.replace(/\\/g, "/").replace(/^\.\//, "");
318
+ }
319
+ function ruleIdFor(finding) {
320
+ return finding.ruleId ?? finding.evalName;
321
+ }
322
+ function entryLocation(result) {
323
+ const entry = declaringEntry(result);
324
+ return {
325
+ artifactLocation: { uri: uriFor(entry.file) },
326
+ ...entry.line !== void 0 ? { region: { startLine: entry.line } } : {}
327
+ };
328
+ }
329
+ function renderSarif(report) {
330
+ const rules = /* @__PURE__ */ new Map();
331
+ const results = [];
332
+ for (const evalResult of report.evalResults) {
333
+ for (const finding of evalResult.findings ?? []) {
334
+ const id = ruleIdFor(finding);
335
+ const level = levelFor(finding.severity);
336
+ if (!rules.has(id)) {
337
+ rules.set(id, {
338
+ id,
339
+ name: finding.evalName,
340
+ shortDescription: {
341
+ text: `manni docevals eval "${finding.evalName}" (${evalResult.grader})`
342
+ },
343
+ defaultConfiguration: { level }
344
+ });
345
+ }
346
+ results.push({
347
+ ruleId: id,
348
+ level,
349
+ message: { text: finding.message },
350
+ locations: [
351
+ {
352
+ // A finding with a content line keeps it. One without lands on
353
+ // the entry that declares the eval.
354
+ physicalLocation: finding.line != null ? {
355
+ artifactLocation: { uri: uriFor(finding.file) },
356
+ region: {
357
+ startLine: finding.line,
358
+ ...finding.col != null ? { startColumn: finding.col } : {}
359
+ }
360
+ } : entryLocation(evalResult)
361
+ }
362
+ ]
363
+ });
364
+ }
365
+ if (evalResult.outcome === "error") {
366
+ const id = evalResult.evalName;
367
+ if (!rules.has(id)) {
368
+ rules.set(id, {
369
+ id,
370
+ name: evalResult.evalName,
371
+ shortDescription: {
372
+ text: `manni docevals eval "${evalResult.evalName}" (${evalResult.grader})`
373
+ },
374
+ defaultConfiguration: { level: "error" }
375
+ });
376
+ }
377
+ results.push({
378
+ ruleId: id,
379
+ level: "error",
380
+ message: { text: evalResult.skipReason ?? "eval errored" },
381
+ locations: [{ physicalLocation: entryLocation(evalResult) }]
382
+ });
383
+ }
384
+ if (evalResult.outcome === "fail" && evalResult.consensus) {
385
+ const id = evalResult.evalName;
386
+ if (!rules.has(id)) {
387
+ rules.set(id, {
388
+ id,
389
+ name: evalResult.evalName,
390
+ shortDescription: {
391
+ text: `manni docevals eval "${evalResult.evalName}" (AI judge)`
392
+ },
393
+ defaultConfiguration: { level: "error" }
394
+ });
395
+ }
396
+ const reasoning = evalResult.consensus.runs.find((r) => r.verdict)?.verdict?.reasoning ?? "";
397
+ results.push({
398
+ ruleId: id,
399
+ level: "error",
400
+ message: {
401
+ text: `AI judge: fail (confidence ${evalResult.consensus.meanConfidence.toFixed(2)}). ${reasoning}`.trim()
402
+ },
403
+ locations: [{ physicalLocation: entryLocation(evalResult) }]
404
+ });
405
+ }
406
+ }
407
+ const log = {
408
+ $schema: SARIF_SCHEMA,
409
+ version: "2.1.0",
410
+ runs: [
411
+ {
412
+ tool: {
413
+ driver: {
414
+ name: "manni-docevals",
415
+ informationUri: "https://hawkeyexl.github.io/manni/docevals/",
416
+ rules: [...rules.values()]
417
+ }
418
+ },
419
+ results
420
+ }
421
+ ]
422
+ };
423
+ return `${JSON.stringify(log, null, 2)}
424
+ `;
425
+ }
426
+
427
+ // src/docevals/reporters/junit.ts
428
+ var FORBIDDEN = /[- --Ÿ]/g;
429
+ function esc(s) {
430
+ return s.replace(FORBIDDEN, "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
431
+ }
432
+ function attr(name, value) {
433
+ return `${name}="${esc(String(value))}"`;
434
+ }
435
+ function failureText(result) {
436
+ const findings = (result.findings ?? []).map(
437
+ (f) => `${f.file}${f.line != null ? `:${f.line}` : ""} ${f.message}`
438
+ );
439
+ if (findings.length > 0) return findings.join("\n");
440
+ if (result.consensus) {
441
+ const reasoning = result.consensus.runs.find((r) => r.verdict)?.verdict?.reasoning ?? "";
442
+ return `AI judge: fail (confidence ${result.consensus.meanConfidence.toFixed(2)}). ${reasoning}`.trim();
443
+ }
444
+ if (result.skipReason) return result.skipReason;
445
+ return `${result.evalName} failed`;
446
+ }
447
+ function testcase(result) {
448
+ const entry = declaringEntry(result);
449
+ const open = ` <testcase ${attr("classname", result.file)} ${attr(
450
+ "name",
451
+ result.evalName
452
+ )} ${attr("file", entry.file)}${entry.line === void 0 ? "" : ` ${attr("line", entry.line)}`} ${attr("time", (result.durationMs / 1e3).toFixed(3))}`;
453
+ switch (result.outcome) {
454
+ case "pass":
455
+ return `${open} />`;
456
+ case "skipped":
457
+ return `${open}>
458
+ <skipped ${attr(
459
+ "message",
460
+ result.skipReason ?? "skipped"
461
+ )} />
462
+ </testcase>`;
463
+ case "error":
464
+ return `${open}>
465
+ <error ${attr(
466
+ "message",
467
+ `${result.evalName} errored`
468
+ )}>${esc(failureText(result))}</error>
469
+ </testcase>`;
470
+ case "needs-review":
471
+ return `${open}>
472
+ <skipped ${attr(
473
+ "message",
474
+ "needs human review"
475
+ )} />
476
+ </testcase>`;
477
+ default:
478
+ return `${open}>
479
+ <failure ${attr(
480
+ "message",
481
+ `${result.evalName} failed`
482
+ )}>${esc(failureText(result))}</failure>
483
+ </testcase>`;
484
+ }
485
+ }
486
+ function renderJunit(report) {
487
+ const bySuite = /* @__PURE__ */ new Map();
488
+ for (const r of report.evalResults) {
489
+ const suite = r.suite ?? "default";
490
+ const list = bySuite.get(suite) ?? [];
491
+ list.push(r);
492
+ bySuite.set(suite, list);
493
+ }
494
+ const suites = [...bySuite.entries()].map(([name, results]) => {
495
+ const failures2 = results.filter((r) => r.outcome === "fail").length;
496
+ const errors2 = results.filter((r) => r.outcome === "error").length;
497
+ const skipped = results.filter(
498
+ (r) => r.outcome === "skipped" || r.outcome === "needs-review"
499
+ ).length;
500
+ const time = results.reduce((sum, r) => sum + r.durationMs, 0) / 1e3;
501
+ return [
502
+ ` <testsuite ${attr("name", name)} ${attr("tests", results.length)} ${attr(
503
+ "failures",
504
+ failures2
505
+ )} ${attr("errors", errors2)} ${attr("skipped", skipped)} ${attr(
506
+ "time",
507
+ time.toFixed(3)
508
+ )}>`,
509
+ ...results.map(testcase),
510
+ " </testsuite>"
511
+ ].join("\n");
512
+ });
513
+ const total = report.evalResults.length;
514
+ const failures = report.evalResults.filter((r) => r.outcome === "fail").length;
515
+ const errors = report.evalResults.filter((r) => r.outcome === "error").length;
516
+ return [
517
+ '<?xml version="1.0" encoding="UTF-8"?>',
518
+ `<testsuites ${attr("name", "manni-docevals")} ${attr("tests", total)} ${attr(
519
+ "failures",
520
+ failures
521
+ )} ${attr("errors", errors)}>`,
522
+ ...suites,
523
+ "</testsuites>",
524
+ ""
525
+ ].join("\n");
526
+ }
527
+
528
+ // src/docevals/reporters/html.ts
529
+ var OUTCOME_LABEL = {
530
+ pass: "Pass",
531
+ fail: "Fail",
532
+ "needs-review": "Needs review",
533
+ skipped: "Skipped",
534
+ error: "Error"
535
+ };
536
+ function esc2(value) {
537
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
538
+ }
539
+ var pct = (n) => `${(n * 100).toFixed(0)}%`;
540
+ function suiteRows(report) {
541
+ return report.suites.map((s) => {
542
+ const verdict = s.partial ? '<span class="v partial">partial</span>' : s.meetsTarget ? '<span class="v ok">met</span>' : '<span class="v bad">missed</span>';
543
+ const criteria = s.criteria ? `${String(s.criteria.passed)}/${String(s.criteria.total)}` + (s.criteria.suspended > 0 ? ` <span class="muted">(${String(s.criteria.suspended)} suspended)</span>` : "") : '<span class="muted">\u2014</span>';
544
+ return `<tr><th>${esc2(s.suite)}</th><td>${String(s.passed)}</td><td>${String(
545
+ s.failed + s.errored
546
+ )}</td><td>${String(s.needsReview)}</td><td>${String(s.skipped)}</td><td>${criteria}</td><td>${pct(
547
+ s.passRate
548
+ )}</td><td>${pct(s.targetPassRate)}</td><td>${verdict}</td></tr>`;
549
+ }).join("\n");
550
+ }
551
+ function evalBlock(r) {
552
+ const bits = [];
553
+ bits.push(
554
+ `<div class="eval ${esc2(r.outcome)}"><div class="eh"><span class="badge ${esc2(r.outcome)}">${esc2(
555
+ OUTCOME_LABEL[r.outcome] ?? r.outcome
556
+ )}</span> <code>${esc2(r.evalName)}</code><span class="muted"> \xB7 ${esc2(locationLabel(declaringEntry(r)))} \xB7 ${esc2(r.grader)}${r.weight !== void 0 && r.weight !== 1 ? ` \xB7 weight ${String(r.weight)}` : ""}</span></div>`
557
+ );
558
+ if (r.skipReason) bits.push(`<p class="reason">${esc2(r.skipReason)}</p>`);
559
+ const verdict = r.consensus?.runs.find((run) => run.verdict)?.verdict;
560
+ if (verdict) {
561
+ bits.push(
562
+ `<p class="reason">${esc2(verdict.reasoning)}</p>`,
563
+ verdict.observed ? `<blockquote>${esc2(verdict.observed)}</blockquote>` : "",
564
+ `<p class="muted">consensus ${esc2(r.consensus?.verdict ?? "")} \xB7 agreement ${pct(
565
+ r.consensus?.agreement ?? 0
566
+ )} \xB7 confidence ${pct(r.consensus?.meanConfidence ?? 0)} \xB7 zone ${esc2(
567
+ r.consensus?.zone ?? ""
568
+ )}</p>`
569
+ );
570
+ }
571
+ if (r.via === "human-review") {
572
+ bits.push('<p class="note">Resolved by a recorded human review.</p>');
573
+ }
574
+ if (r.selfPreference) {
575
+ bits.push(
576
+ `<p class="warn">Judged by <code>${esc2(r.selfPreference.model)}</code>, which also ` + (r.selfPreference.axis === "content" ? "wrote what this eval grades, by the page's provenance or meta-provenance." : "proposed this eval, by the page's meta-provenance.") + " Self-judging favors the author; give the eval a model: of its own.</p>"
577
+ );
578
+ }
579
+ for (const f of r.findings ?? []) {
580
+ bits.push(
581
+ `<p class="finding"><span class="sev ${esc2(f.severity)}">${esc2(f.severity)}</span> ${esc2(f.message)}${f.line ? ` <span class="muted">(line ${String(f.line)})</span>` : ""}</p>`
582
+ );
583
+ }
584
+ bits.push("</div>");
585
+ return bits.filter(Boolean).join("\n");
586
+ }
587
+ function renderHtml(report) {
588
+ const byFile = /* @__PURE__ */ new Map();
589
+ for (const r of report.evalResults) {
590
+ const list = byFile.get(r.file) ?? [];
591
+ list.push(r);
592
+ byFile.set(r.file, list);
593
+ }
594
+ const pages = [...byFile.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([file, results]) => {
595
+ const failed = results.filter(
596
+ (r) => r.outcome === "fail" || r.outcome === "error"
597
+ ).length;
598
+ return `<section><h3>${esc2(file)}` + (failed > 0 ? ` <span class="badge fail">${String(failed)}</span>` : "") + `</h3>${results.map(evalBlock).join("\n")}</section>`;
599
+ }).join("\n");
600
+ const problems = report.problems.length ? `<h2>Problems</h2><ul class="problems">${report.problems.map(
601
+ (p) => `<li class="${esc2(p.level)}"><code>${esc2(p.file)}</code>${p.line ? `:${String(p.line)}` : ""} \u2014 ${esc2(p.message)}</li>`
602
+ ).join("")}</ul>` : "";
603
+ const bl = report.baseline;
604
+ const baseline = bl ? `<p class="note">Baseline <code>${esc2(bl.path)}</code>: ${String(
605
+ bl.recorded
606
+ )} recorded, ${String(bl.suppressed)} suppressed${bl.stale > 0 ? `, ${String(bl.stale)} stale` : ""}.</p>` : "";
607
+ return `<!doctype html>
608
+ <html lang="en"><head><meta charset="utf-8">
609
+ <meta name="viewport" content="width=device-width,initial-scale=1">
610
+ <title>manni docevals results</title>
611
+ <style>
612
+ :root{--bg:#fff;--fg:#1a1a1a;--muted:#666;--line:#e2e2e2;--ok:#137333;--bad:#b3261e;--warn:#8a6100;--card:#fafafa}
613
+ @media (prefers-color-scheme:dark){:root{--bg:#16181c;--fg:#e6e6e6;--muted:#9aa0a6;--line:#2c2f36;--ok:#7ee2a8;--bad:#ff8a80;--warn:#ffca7a;--card:#1d2026}}
614
+ *{box-sizing:border-box}
615
+ body{margin:0;padding:2rem 1.25rem;background:var(--bg);color:var(--fg);
616
+ font:15px/1.55 ui-sans-serif,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif}
617
+ main{max-width:60rem;margin:0 auto}
618
+ h1{font-size:1.5rem;margin:0 0 .25rem}
619
+ h2{font-size:1.1rem;margin:2rem 0 .5rem;padding-bottom:.25rem;border-bottom:1px solid var(--line)}
620
+ h3{font-size:.95rem;margin:1.5rem 0 .5rem;font-family:ui-monospace,SFMono-Regular,Consolas,monospace}
621
+ table{border-collapse:collapse;width:100%;font-size:.9rem}
622
+ th,td{text-align:left;padding:.4rem .6rem;border-bottom:1px solid var(--line)}
623
+ thead th{color:var(--muted);font-weight:600}
624
+ code{font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:.9em}
625
+ .muted{color:var(--muted)}
626
+ .eval{border:1px solid var(--line);border-left-width:3px;border-radius:6px;background:var(--card);padding:.6rem .8rem;margin:.4rem 0}
627
+ .eval.fail,.eval.error{border-left-color:var(--bad)}
628
+ .eval.pass{border-left-color:var(--ok)}
629
+ .eval.needs-review{border-left-color:var(--warn)}
630
+ .badge{display:inline-block;padding:.05rem .4rem;border-radius:4px;font-size:.75rem;font-weight:600;border:1px solid var(--line)}
631
+ .badge.pass{color:var(--ok)}.badge.fail,.badge.error{color:var(--bad)}
632
+ blockquote{margin:.4rem 0;padding:.3rem .7rem;border-left:2px solid var(--line);color:var(--muted)}
633
+ .reason{margin:.3rem 0}
634
+ .warn{color:var(--warn);margin:.3rem 0}
635
+ .note{color:var(--muted);margin:.3rem 0}
636
+ .finding{margin:.2rem 0}
637
+ .sev{font-size:.75rem;text-transform:uppercase;font-weight:600;margin-right:.35rem}
638
+ .sev.error{color:var(--bad)}.sev.warning{color:var(--warn)}.sev.notice{color:var(--muted)}
639
+ .v.ok{color:var(--ok)}.v.bad{color:var(--bad)}.v.partial{color:var(--muted)}
640
+ .problems li.error{color:var(--bad)}.problems li.warning{color:var(--warn)}
641
+ </style></head><body><main>
642
+ <h1>manni docevals results</h1>
643
+ <p class="muted">${String(report.pages)} page(s) \xB7 ${String(
644
+ report.evalResults.length
645
+ )} eval(s) \xB7 exit ${String(report.exitCode)}</p>
646
+ ${baseline}
647
+ <h2>Suites</h2>
648
+ <table><thead><tr><th>Suite</th><th>Pass</th><th>Fail</th><th>Review</th><th>Skip</th><th>Criteria</th><th>Rate</th><th>Target</th><th></th></tr></thead>
649
+ <tbody>
650
+ ${suiteRows(report)}
651
+ </tbody></table>
652
+ ${problems}
653
+ <h2>Pages</h2>
654
+ ${pages}
655
+ </main></body></html>
656
+ `;
657
+ }
658
+
659
+ // src/docevals/reporters/index.ts
660
+ function render(report, format, opts = {}) {
661
+ parseFormat(format, REPORT_FORMATS, "format");
662
+ switch (format) {
663
+ case "pretty":
664
+ return renderPretty(report, opts);
665
+ case "json":
666
+ return renderJson(report);
667
+ case "markdown":
668
+ return renderMarkdown(report);
669
+ case "sarif":
670
+ return renderSarif(report);
671
+ case "junit":
672
+ return renderJunit(report);
673
+ case "github":
674
+ return renderGithub(report);
675
+ case "html":
676
+ return renderHtml(report);
677
+ }
678
+ }
679
+
680
+ export {
681
+ render
682
+ };
683
+ //# sourceMappingURL=chunk-NCPWXHDO.js.map