@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.
- package/README.md +9 -1
- package/dist/batch-DFRCLY77.js +36 -0
- package/dist/build-Q5C6SX5J.js +31 -0
- package/dist/calibrate-XQILKXS3.js +31 -0
- package/dist/capture-JQMOC3BW.js +32 -0
- package/dist/check-HYNGXYJV.js +18 -0
- package/dist/check-HYNGXYJV.js.map +1 -0
- package/dist/check-NFZQLJKN.js +27 -0
- package/dist/check-NFZQLJKN.js.map +1 -0
- package/dist/check-U54XV6BP.js +40 -0
- package/dist/check-U54XV6BP.js.map +1 -0
- package/dist/chunk-252LNOEG.js +622 -0
- package/dist/chunk-252LNOEG.js.map +1 -0
- package/dist/chunk-2H7UOFLK.js +11 -0
- package/dist/chunk-2H7UOFLK.js.map +1 -0
- package/dist/chunk-2U3ORT6D.js +230 -0
- package/dist/chunk-2U3ORT6D.js.map +1 -0
- package/dist/chunk-3AFUD75K.js +23 -0
- package/dist/chunk-3AFUD75K.js.map +1 -0
- package/dist/{chunk-3R23C5DT.js → chunk-4TSWU2SU.js} +2 -14
- package/dist/chunk-4TSWU2SU.js.map +1 -0
- package/dist/chunk-5KHIFVD2.js +1192 -0
- package/dist/chunk-5KHIFVD2.js.map +1 -0
- package/dist/chunk-5YXBLLAC.js +2165 -0
- package/dist/chunk-5YXBLLAC.js.map +1 -0
- package/dist/chunk-644JVKJ4.js +3872 -0
- package/dist/chunk-644JVKJ4.js.map +1 -0
- package/dist/chunk-6OYEI2VV.js +88 -0
- package/dist/chunk-6OYEI2VV.js.map +1 -0
- package/dist/chunk-77AINBYM.js +19 -0
- package/dist/chunk-77AINBYM.js.map +1 -0
- package/dist/chunk-77HX34KD.js +1287 -0
- package/dist/chunk-77HX34KD.js.map +1 -0
- package/dist/{chunk-CFDUZRM2.js → chunk-7QMCHA4N.js} +32 -240
- package/dist/chunk-7QMCHA4N.js.map +1 -0
- package/dist/chunk-BUXDLRDT.js +455 -0
- package/dist/chunk-BUXDLRDT.js.map +1 -0
- package/dist/chunk-C6OH6CNF.js +388 -0
- package/dist/chunk-C6OH6CNF.js.map +1 -0
- package/dist/chunk-CK7SKVHR.js +1042 -0
- package/dist/chunk-CK7SKVHR.js.map +1 -0
- package/dist/chunk-CYWHFSRT.js +6737 -0
- package/dist/chunk-CYWHFSRT.js.map +1 -0
- package/dist/chunk-ERMSO34F.js +17 -0
- package/dist/chunk-ERMSO34F.js.map +1 -0
- package/dist/{chunk-IOYXPBCL.js → chunk-G3T47CFV.js} +1 -7
- package/dist/{chunk-IOYXPBCL.js.map → chunk-G3T47CFV.js.map} +1 -1
- package/dist/chunk-G7NJSREW.js +979 -0
- package/dist/chunk-G7NJSREW.js.map +1 -0
- package/dist/chunk-GLP5PSXB.js +72 -0
- package/dist/chunk-GLP5PSXB.js.map +1 -0
- package/dist/chunk-H2DLH2JI.js +198 -0
- package/dist/chunk-H2DLH2JI.js.map +1 -0
- package/dist/chunk-H6FZ66XR.js +634 -0
- package/dist/chunk-H6FZ66XR.js.map +1 -0
- package/dist/{chunk-KJR7OVDX.js → chunk-IEQHSCZG.js} +56 -137
- package/dist/chunk-IEQHSCZG.js.map +1 -0
- package/dist/chunk-IKEWBMCN.js +98 -0
- package/dist/chunk-IKEWBMCN.js.map +1 -0
- package/dist/chunk-JOHKIAVH.js +5440 -0
- package/dist/chunk-JOHKIAVH.js.map +1 -0
- package/dist/chunk-JVTNMVYU.js +10921 -0
- package/dist/chunk-JVTNMVYU.js.map +1 -0
- package/dist/chunk-K3D6FPV6.js +164 -0
- package/dist/chunk-K3D6FPV6.js.map +1 -0
- package/dist/{chunk-UBMMXS2Y.js → chunk-KCGV52AM.js} +69 -48
- package/dist/{chunk-UBMMXS2Y.js.map → chunk-KCGV52AM.js.map} +1 -1
- package/dist/chunk-LAKAWRV5.js +1651 -0
- package/dist/chunk-LAKAWRV5.js.map +1 -0
- package/dist/chunk-LJ2RDH3F.js +49 -0
- package/dist/chunk-LJ2RDH3F.js.map +1 -0
- package/dist/chunk-M2JCK5F6.js +805 -0
- package/dist/chunk-M2JCK5F6.js.map +1 -0
- package/dist/chunk-MNH7QO4Z.js +15 -0
- package/dist/chunk-MNH7QO4Z.js.map +1 -0
- package/dist/{chunk-HAPTXWU2.js → chunk-MYC3O5EJ.js} +4 -4
- package/dist/chunk-MYMBCTDE.js +387 -0
- package/dist/chunk-MYMBCTDE.js.map +1 -0
- package/dist/chunk-NCPWXHDO.js +683 -0
- package/dist/chunk-NCPWXHDO.js.map +1 -0
- package/dist/chunk-NWZ2SLYL.js +2957 -0
- package/dist/chunk-NWZ2SLYL.js.map +1 -0
- package/dist/chunk-OBFENF3U.js +934 -0
- package/dist/chunk-OBFENF3U.js.map +1 -0
- package/dist/chunk-OWBRDNRZ.js +16 -0
- package/dist/chunk-OWBRDNRZ.js.map +1 -0
- package/dist/{chunk-KTSJ2ZHA.js → chunk-PAU352SV.js} +5 -3
- package/dist/{chunk-KTSJ2ZHA.js.map → chunk-PAU352SV.js.map} +1 -1
- package/dist/chunk-PCE7QHXJ.js +68 -0
- package/dist/chunk-PCE7QHXJ.js.map +1 -0
- package/dist/chunk-PCHZY2I7.js +299 -0
- package/dist/chunk-PCHZY2I7.js.map +1 -0
- package/dist/chunk-PHF3D7ER.js +1042 -0
- package/dist/chunk-PHF3D7ER.js.map +1 -0
- package/dist/chunk-Q35YIDBV.js +1202 -0
- package/dist/chunk-Q35YIDBV.js.map +1 -0
- package/dist/chunk-RLR4TKUZ.js +4398 -0
- package/dist/chunk-RLR4TKUZ.js.map +1 -0
- package/dist/chunk-RNVYGWIC.js +30 -0
- package/dist/chunk-RNVYGWIC.js.map +1 -0
- package/dist/chunk-SE4JN5XN.js +19 -0
- package/dist/chunk-SE4JN5XN.js.map +1 -0
- package/dist/chunk-TIUTIOFB.js +25 -0
- package/dist/chunk-TIUTIOFB.js.map +1 -0
- package/dist/chunk-TU2WUBVZ.js +2 -0
- package/dist/chunk-TU2WUBVZ.js.map +1 -0
- package/dist/chunk-TZOYZK2E.js +98 -0
- package/dist/chunk-TZOYZK2E.js.map +1 -0
- package/dist/chunk-UKZNLVJW.js +17 -0
- package/dist/chunk-UKZNLVJW.js.map +1 -0
- package/dist/chunk-UZC7LDAQ.js +178 -0
- package/dist/chunk-UZC7LDAQ.js.map +1 -0
- package/dist/chunk-V46OILVC.js +3090 -0
- package/dist/chunk-V46OILVC.js.map +1 -0
- package/dist/chunk-WQE54PNH.js +1975 -0
- package/dist/chunk-WQE54PNH.js.map +1 -0
- package/dist/chunk-X3BPBDGQ.js +52 -0
- package/dist/chunk-X3BPBDGQ.js.map +1 -0
- package/dist/chunk-XSLV76YK.js +54 -0
- package/dist/chunk-XSLV76YK.js.map +1 -0
- package/dist/{chunk-5HNHEUD5.js → chunk-XYLUCIKQ.js} +3 -3
- package/dist/chunk-YEUYKR62.js +72 -0
- package/dist/chunk-YEUYKR62.js.map +1 -0
- package/dist/{chunk-G5CM2VGQ.js → chunk-YFQBFNQS.js} +8 -94
- package/dist/chunk-YFQBFNQS.js.map +1 -0
- package/dist/chunk-YIL4XLLJ.js +1661 -0
- package/dist/chunk-YIL4XLLJ.js.map +1 -0
- package/dist/chunk-YNHZHSSM.js +41 -0
- package/dist/chunk-YNHZHSSM.js.map +1 -0
- package/dist/chunk-YTCZRLTU.js +96 -0
- package/dist/chunk-YTCZRLTU.js.map +1 -0
- package/dist/chunk-YYBFZLAJ.js +374 -0
- package/dist/chunk-YYBFZLAJ.js.map +1 -0
- package/dist/chunk-ZXRAE55H.js +31 -0
- package/dist/chunk-ZXRAE55H.js.map +1 -0
- package/dist/cli-2QPR2OZG.js +232 -0
- package/dist/cli-2QPR2OZG.js.map +1 -0
- package/dist/cli-4IOPGZHR.js +1203 -0
- package/dist/cli-4IOPGZHR.js.map +1 -0
- package/dist/cli-5FL73WHA.js +346 -0
- package/dist/cli-5FL73WHA.js.map +1 -0
- package/dist/cli-C262QOWM.js +739 -0
- package/dist/cli-C262QOWM.js.map +1 -0
- package/dist/cli-LJLLIQB2.js +423 -0
- package/dist/cli-LJLLIQB2.js.map +1 -0
- package/dist/cli-OFPZ5MAS.js +626 -0
- package/dist/cli-OFPZ5MAS.js.map +1 -0
- package/dist/cli-SHSMSRQY.js +28 -0
- package/dist/cli-SHSMSRQY.js.map +1 -0
- package/dist/cli-SRHFUZHA.js +473 -0
- package/dist/cli-SRHFUZHA.js.map +1 -0
- package/dist/cli-URZQXL4K.js +552 -0
- package/dist/cli-URZQXL4K.js.map +1 -0
- package/dist/cli.d.ts +12 -2
- package/dist/cli.js +109 -7661
- package/dist/cli.js.map +1 -1
- package/dist/docmeta.js +15 -3
- package/dist/docmeta.js.map +1 -1
- package/dist/github-FE6KCNYJ.js +27 -0
- package/dist/github-FE6KCNYJ.js.map +1 -0
- package/dist/github-QXL3VMK2.js +32 -0
- package/dist/github-QXL3VMK2.js.map +1 -0
- package/dist/index.d.ts +65 -3
- package/dist/index.js +407 -337
- package/dist/index.js.map +1 -1
- package/dist/json-7WV7KL6H.js +17 -0
- package/dist/json-7WV7KL6H.js.map +1 -0
- package/dist/json-SGZ6ZRFD.js +35 -0
- package/dist/json-SGZ6ZRFD.js.map +1 -0
- package/dist/lint-DL4LJRAY.js +28 -0
- package/dist/lint-DL4LJRAY.js.map +1 -0
- package/dist/list-6BAXTZUM.js +29 -0
- package/dist/list-6BAXTZUM.js.map +1 -0
- package/dist/list-7BKNYPSB.js +31 -0
- package/dist/list-7BKNYPSB.js.map +1 -0
- package/dist/page-3U2GCFNE.js +41 -0
- package/dist/page-3U2GCFNE.js.map +1 -0
- package/dist/picker-3XF36MJF.js +14 -0
- package/dist/picker-3XF36MJF.js.map +1 -0
- package/dist/pretty-2H57QVTY.js +43 -0
- package/dist/pretty-2H57QVTY.js.map +1 -0
- package/dist/pretty-N6DO4OOL.js +37 -0
- package/dist/pretty-N6DO4OOL.js.map +1 -0
- package/dist/reporters-M6LJ2IYU.js +21 -0
- package/dist/reporters-M6LJ2IYU.js.map +1 -0
- package/dist/reporters-N6GHXSS7.js +42 -0
- package/dist/reporters-N6GHXSS7.js.map +1 -0
- package/dist/reporters-UCNEV7PH.js +71 -0
- package/dist/reporters-UCNEV7PH.js.map +1 -0
- package/dist/run-XZDAREJE.js +33 -0
- package/dist/run-XZDAREJE.js.map +1 -0
- package/dist/term-5ICGKPC3.js +1592 -0
- package/dist/term-5ICGKPC3.js.map +1 -0
- package/dist/types-Y6TXHM7M.js +10 -0
- package/dist/types-Y6TXHM7M.js.map +1 -0
- package/dist/validate-GQRM77YN.js +16 -0
- package/dist/validate-GQRM77YN.js.map +1 -0
- package/package.json +1 -1
- package/plugin/manni/.claude-plugin/plugin.json +9 -0
- package/plugin/manni/hooks/hooks.json +52 -0
- package/plugin/manni/skills/check/SKILL.md +20 -0
- package/plugin/manni/skills/evals/SKILL.md +27 -0
- package/plugin/manni/skills/fix/SKILL.md +56 -0
- package/plugin/manni/skills/setup/SKILL.md +41 -0
- package/dist/batch-A5HZKYIW.js +0 -18
- package/dist/calibrate-S5K6QHUY.js +0 -13
- package/dist/capture-OZEZDABQ.js +0 -15
- package/dist/chunk-3R23C5DT.js.map +0 -1
- package/dist/chunk-CFDUZRM2.js.map +0 -1
- package/dist/chunk-G5CM2VGQ.js.map +0 -1
- package/dist/chunk-KJR7OVDX.js.map +0 -1
- package/dist/chunk-V4KUVE47.js +0 -27170
- package/dist/chunk-V4KUVE47.js.map +0 -1
- package/dist/chunk-ZQBTK3DO.js +0 -26518
- package/dist/chunk-ZQBTK3DO.js.map +0 -1
- package/dist/picker-6HRMETE7.js +0 -12
- package/plugin/tracevals/.claude-plugin/plugin.json +0 -9
- package/plugin/tracevals/hooks/hooks.json +0 -17
- /package/dist/{batch-A5HZKYIW.js.map → batch-DFRCLY77.js.map} +0 -0
- /package/dist/{calibrate-S5K6QHUY.js.map → build-Q5C6SX5J.js.map} +0 -0
- /package/dist/{capture-OZEZDABQ.js.map → calibrate-XQILKXS3.js.map} +0 -0
- /package/dist/{picker-6HRMETE7.js.map → capture-JQMOC3BW.js.map} +0 -0
- /package/dist/{chunk-HAPTXWU2.js.map → chunk-MYC3O5EJ.js.map} +0 -0
- /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, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
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("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
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
|