vigiles 21.0.2 → 23.0.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 +1 -1
- package/dist/adapters/claude-code/hook-protocol.js +3 -0
- package/dist/adapters/claude-code/layout.js +2 -0
- package/dist/cli-flag-check.js +1 -0
- package/dist/cli.d.ts +2 -1
- package/dist/cli.js +229 -45
- package/dist/core/hook-block-ineffective.js +24 -1
- package/dist/core/hook-protocol.d.ts +14 -0
- package/dist/core/layout.d.ts +15 -0
- package/dist/coverage-evidence.d.ts +48 -2
- package/dist/coverage-evidence.js +96 -3
- package/dist/eval.d.ts +10 -0
- package/dist/eval.js +14 -3
- package/dist/plugin-loader.js +35 -0
- package/dist/run-hook.d.ts +23 -2
- package/dist/run-hook.js +10 -3
- package/dist/scan-core.d.ts +5 -0
- package/dist/scan-core.js +10 -1
- package/dist/spec-hooks.d.mts +35 -0
- package/dist/spec-hooks.mjs +68 -0
- package/dist/spec-host.d.mts +2 -0
- package/dist/spec-host.mjs +79 -0
- package/dist/test-coverage-files.js +17 -8
- package/dist/test-coverage.js +29 -16
- package/package.json +1 -1
package/dist/test-coverage.js
CHANGED
|
@@ -273,7 +273,14 @@ function discoverTests(basePath, globs, ignore) {
|
|
|
273
273
|
// skill (matched by the explicit-dot `.claude/skills/*/SKILL.md` pattern) is
|
|
274
274
|
// still discovered — so the surface looks untested even after the user adds
|
|
275
275
|
// exactly the suggested file. DEFAULT_IGNORE still drops .git/node_modules/etc.
|
|
276
|
-
|
|
276
|
+
// `{surface}` is widened to `*` for DISCOVERY so one pass finds every
|
|
277
|
+
// candidate; the narrowing back to a specific surface happens at match time
|
|
278
|
+
// (matchesSurfaceGlob). Globbing once per surface would be quadratic in I/O.
|
|
279
|
+
const found = (0, glob_1.globSync)(globs.map(coverage_evidence_js_1.discoveryGlob), {
|
|
280
|
+
cwd: basePath,
|
|
281
|
+
ignore,
|
|
282
|
+
dot: true,
|
|
283
|
+
});
|
|
277
284
|
// Prepared ONCE per file (comment-strip + declaration parse), not once per
|
|
278
285
|
// (surface × file) pair — the matching below is quadratic by nature.
|
|
279
286
|
return found.map((path) => (0, coverage_evidence_js_1.prepareTest)(path));
|
|
@@ -318,15 +325,17 @@ function isColocated(surface, testPath) {
|
|
|
318
325
|
* explicitly declared is reported as declared; otherwise the provenance summary
|
|
319
326
|
* would depend on glob order.
|
|
320
327
|
*/
|
|
321
|
-
function coverageOf(surface, tests) {
|
|
328
|
+
function coverageOf(surface, tests, globs) {
|
|
322
329
|
let best = null;
|
|
323
330
|
for (const t of tests) {
|
|
324
331
|
if (t.path === surface.path)
|
|
325
332
|
continue;
|
|
326
|
-
const ev = (0, coverage_evidence_js_1.evidenceFor)(surface, t, isColocated(surface, t.path));
|
|
333
|
+
const ev = (0, coverage_evidence_js_1.evidenceFor)(surface, t, isColocated(surface, t.path), (0, coverage_evidence_js_1.matchesSurfaceGlob)(surface, t.path, globs));
|
|
327
334
|
if (!ev)
|
|
328
335
|
continue;
|
|
329
|
-
|
|
336
|
+
// Rank, do not first-win: with a colocated harness AND a configured suite
|
|
337
|
+
// the reported provenance must not depend on glob order.
|
|
338
|
+
if (!best || (0, coverage_evidence_js_1.strongerEvidence)(ev, best.evidence))
|
|
330
339
|
best = { surface, evidence: ev, by: t.path };
|
|
331
340
|
}
|
|
332
341
|
return best;
|
|
@@ -370,12 +379,12 @@ function executedOf(surface, index, tier) {
|
|
|
370
379
|
* first, a colocated test second. Execution outranks the name because the name
|
|
371
380
|
* was only ever a stand-in for it.
|
|
372
381
|
*/
|
|
373
|
-
function tierOf(considered, tests, index, tier) {
|
|
382
|
+
function tierOf(considered, tests, index, tier, globs) {
|
|
374
383
|
const covered = [];
|
|
375
384
|
const untested = [];
|
|
376
385
|
const decisions = [];
|
|
377
386
|
for (const s of considered) {
|
|
378
|
-
const decision = executedOf(s, index, tier) ?? coverageOf(s, tests);
|
|
387
|
+
const decision = executedOf(s, index, tier) ?? coverageOf(s, tests, globs);
|
|
379
388
|
if (decision) {
|
|
380
389
|
covered.push(s);
|
|
381
390
|
decisions.push(decision);
|
|
@@ -432,7 +441,7 @@ function findUntestedSurfaces(options = {}) {
|
|
|
432
441
|
// file has several legitimate spellings (`x.mjs`, `./x.mjs`, absolute), and
|
|
433
442
|
// the artifact records whichever one was typed.
|
|
434
443
|
(by) => (0, node_fs_1.existsSync)((0, node_path_1.join)(basePath, (0, coverage_artifact_js_1.canonicalScript)(by, basePath))));
|
|
435
|
-
const union = tierOf(considered, tests, runIndex, undefined);
|
|
444
|
+
const union = tierOf(considered, tests, runIndex, undefined, globs);
|
|
436
445
|
return {
|
|
437
446
|
total: considered.length,
|
|
438
447
|
covered: union.covered,
|
|
@@ -456,8 +465,8 @@ function findUntestedSurfaces(options = {}) {
|
|
|
456
465
|
.filter((path) => read((0, node_path_1.join)(basePath, path)).includes(LEGACY_COVERS)),
|
|
457
466
|
retiredTestNames: retiredTestNamesFor(basePath, union.untested),
|
|
458
467
|
decisions: union.decisions,
|
|
459
|
-
harness: tierOf(considered, split.harness, runIndex, "harness"),
|
|
460
|
-
evals: tierOf(considered, split.evals, runIndex, "eval"),
|
|
468
|
+
harness: tierOf(considered, split.harness, runIndex, "harness", globs),
|
|
469
|
+
evals: tierOf(considered, split.evals, runIndex, "eval", globs),
|
|
461
470
|
};
|
|
462
471
|
}
|
|
463
472
|
/**
|
|
@@ -813,13 +822,17 @@ function formatUntestedReport(report) {
|
|
|
813
822
|
lines.push(` ${provenance}`);
|
|
814
823
|
lines.push(...coverageCaveats(report));
|
|
815
824
|
// Already testing these another way (a promptfoo suite, a home-grown evals
|
|
816
|
-
// file)?
|
|
817
|
-
//
|
|
818
|
-
//
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
`
|
|
822
|
-
`
|
|
825
|
+
// file)? Two shapes are accepted, and the message names BOTH — it used to
|
|
826
|
+
// name only `testGlobs`, which does not by itself make a centralized suite
|
|
827
|
+
// count, so a reader who followed it exactly saw the number not move (#175.2).
|
|
828
|
+
// See docs/rules/untested-skill.md.
|
|
829
|
+
lines.push(` Testing these another way (promptfoo / a home-grown eval loop)? Either ` +
|
|
830
|
+
`put the file NEXT TO the surface and name it after it ` +
|
|
831
|
+
`(\`<surface>/<surface>.eval.mjs\`), or — for a centralized layout — point ` +
|
|
832
|
+
`\`testGlobs\` at it USING THE \`{surface}\` placeholder, e.g. ` +
|
|
833
|
+
`\`"tests/{surface}/evals/promptfooconfig*.yaml"\`. A \`testGlobs\` entry ` +
|
|
834
|
+
`WITHOUT \`{surface}\` widens what counts as a test file but never says ` +
|
|
835
|
+
`which surface it covers, so it credits nothing on its own. ` +
|
|
823
836
|
`See docs/rules/untested-skill.md.`);
|
|
824
837
|
return lines.join("\n");
|
|
825
838
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vigiles",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "23.0.0",
|
|
4
4
|
"description": "Audit, test and measure the harness your AI agent runs on — grade your CLAUDE.md / AGENTS.md, skills, subagents and hooks, run them against a scripted model, and measure whether they actually fire.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude-code",
|